Skip to content

Commit

Permalink
feat(sidebar): Add the shell icon on hover to the connections in the …
Browse files Browse the repository at this point in the history
…sidebar COMPASS-8050 COMPASS-8071 (#6057)

* chore: adds shell icon on hover of connected tree item

* update tests for the shell icon in the sidebar

* connectionName

* fix unit tests

---------

Co-authored-by: Himanshu Singh <[email protected]>
  • Loading branch information
lerouxb and himanshusinghs authored Jul 25, 2024
1 parent 55a5a60 commit df40eed
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -393,16 +393,13 @@ describe('ConnectionsNavigationTree', function () {
const connection = screen.getByTestId('connection_ready');

expect(within(connection).getByTitle('Create database')).to.be.visible;
expect(within(connection).getByTitle('Open MongoDB shell')).to.be.visible;

const otherActions = within(connection).getByTitle('Show actions');
expect(otherActions).to.exist;

userEvent.click(otherActions);

expect(screen.getByText('Open MongoDB shell')).to.be.visible;
expect(
screen.getByTestId('sidebar-navigation-item-actions-open-shell-action')
).not.to.have.attribute('disabled');
expect(screen.getByText('View performance metrics')).to.be.visible;
expect(screen.getByText('Show connection info')).to.be.visible;
expect(screen.getByText('Copy connection string')).to.be.visible;
Expand Down Expand Up @@ -565,29 +562,19 @@ describe('ConnectionsNavigationTree', function () {
const connection = screen.getByTestId('connection_ready');

expect(within(connection).queryByTitle('Create database')).not.to.exist;
if (name !== 'when preferences is readonly') {
expect(within(connection).getByLabelText('Open MongoDB shell')).to.be
.visible;
} else {
expect(within(connection).queryByLabelText('Open MongoDB shell')).not
.to.exist;
}

const otherActions = within(connection).getByTitle('Show actions');
expect(otherActions).to.exist;

userEvent.click(otherActions);

expect(screen.getByText('Open MongoDB shell')).to.be.visible;
if (
name !== 'when connection is datalake' &&
name !== 'when connection is not writable'
) {
expect(
screen.getByTestId(
'sidebar-navigation-item-actions-open-shell-action'
)
).to.have.attribute('disabled');
} else {
expect(
screen.getByTestId(
'sidebar-navigation-item-actions-open-shell-action'
)
).not.to.have.attribute('disabled');
}
expect(screen.getByText('View performance metrics')).to.be.visible;
expect(screen.getByText('Show connection info')).to.be.visible;
expect(screen.getByText('Copy connection string')).to.be.visible;
Expand Down Expand Up @@ -632,6 +619,40 @@ describe('ConnectionsNavigationTree', function () {
});
});

describe('shell action', function () {
it('should show shell action in the sidebar on hover of connected item', async function () {
await renderConnectionsNavigationTree();
userEvent.hover(screen.getByText('turtles'));
expect(screen.getByLabelText('Open MongoDB shell')).to.be.visible;
});

context('when preferences is readonly', function () {
it('should not render shell action at all', async function () {
await renderConnectionsNavigationTree(
{},
{
readOnly: true,
}
);
userEvent.hover(screen.getByText('turtles'));
expect(() => screen.getByLabelText('Open MongoDB shell')).to.throw;
});
});

context('when shell is disabled', function () {
it('should not render shell action at all', async function () {
await renderConnectionsNavigationTree(
{},
{
enableShell: false,
}
);
userEvent.hover(screen.getByText('turtles'));
expect(() => screen.getByLabelText('Open MongoDB shell')).to.throw;
});
});
});

describe('onItemAction', function () {
let preferences: PreferencesAccess;
beforeEach(async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
SidebarActionableItem,
Connection,
} from './tree-data';
import type { ItemAction, ItemSeparator } from '@mongodb-js/compass-components';
import {
VisuallyHidden,
css,
Expand All @@ -19,6 +20,7 @@ import {
} from '@mongodb-js/compass-components';
import type { WorkspaceTab } from '@mongodb-js/compass-workspaces';
import { usePreference } from 'compass-preferences-model/provider';
import type { NavigationItemActions } from './item-actions';
import {
collectionItemActions,
connectedConnectionItemActions,
Expand Down Expand Up @@ -56,6 +58,7 @@ const ConnectionsNavigationTree: React.FunctionComponent<
onItemExpand,
onItemAction,
}) => {
const preferencesShellEnabled = usePreference('enableShell');
const preferencesReadOnly = usePreference('readOnly');
const isSingleConnection = !usePreference(
'enableNewMultipleConnectionSystem'
Expand All @@ -72,8 +75,15 @@ const ConnectionsNavigationTree: React.FunctionComponent<
isSingleConnection,
expandedItems: expanded,
preferencesReadOnly,
preferencesShellEnabled,
});
}, [connections, isSingleConnection, expanded, preferencesReadOnly]);
}, [
connections,
isSingleConnection,
expanded,
preferencesReadOnly,
preferencesShellEnabled,
]);

const onDefaultAction: OnDefaultAction<SidebarActionableItem> = useCallback(
(item, evt) => {
Expand Down Expand Up @@ -115,38 +125,95 @@ const ConnectionsNavigationTree: React.FunctionComponent<
}
}, [activeWorkspace, isSingleConnection]);

const getItemActions = useCallback(
const getCollapseAfterForConnectedItem = useCallback(
(actions: NavigationItemActions) => {
const [firstAction, secondAction] = actions;

const actionCanBeShownInline = (
action: NavigationItemActions[number]
): boolean => {
if (typeof (action as ItemSeparator).separator !== 'undefined') {
return false;
}

return ['create-database', 'open-shell'].includes(
(action as ItemAction<Actions>).action
);
};

// this is the normal case for a connection that is writable and when we
// also have shell enabled
if (
actionCanBeShownInline(firstAction) &&
actionCanBeShownInline(secondAction)
) {
return 2;
}

// this will happen when the either the connection is not writable or the
// preference is readonly, or shell is not enabled in which case we either
// do not show create-database action or open-shell action
if (
actionCanBeShownInline(firstAction) ||
actionCanBeShownInline(secondAction)
) {
return 1;
}

return 0;
},
[]
);

const getItemActionsAndConfig = useCallback(
(item: SidebarTreeItem) => {
switch (item.type) {
case 'placeholder':
return [];
return {
actions: [],
};
case 'connection': {
if (item.connectionStatus === ConnectionStatus.Connected) {
return connectedConnectionItemActions({
const actions = connectedConnectionItemActions({
hasWriteActionsDisabled: item.hasWriteActionsDisabled,
isShellEnabled: item.isShellEnabled,
connectionInfo: item.connectionInfo,
isPerformanceTabSupported: item.isPerformanceTabSupported,
});
return {
actions: actions,
config: {
collapseAfter: getCollapseAfterForConnectedItem(actions),
},
};
} else {
return notConnectedConnectionItemActions({
connectionInfo: item.connectionInfo,
});
return {
actions: notConnectedConnectionItemActions({
connectionInfo: item.connectionInfo,
}),
config: {
collapseAfter: 0,
},
};
}
}
case 'database':
return databaseItemActions({
hasWriteActionsDisabled: item.hasWriteActionsDisabled,
});
return {
actions: databaseItemActions({
hasWriteActionsDisabled: item.hasWriteActionsDisabled,
}),
};
default:
return collectionItemActions({
hasWriteActionsDisabled: item.hasWriteActionsDisabled,
type: item.type,
isRenameCollectionEnabled,
});
return {
actions: collectionItemActions({
hasWriteActionsDisabled: item.hasWriteActionsDisabled,
type: item.type,
isRenameCollectionEnabled,
}),
};
}
},
[isRenameCollectionEnabled]
[isRenameCollectionEnabled, getCollapseAfterForConnectedItem]
);

const isTestEnv = process.env.NODE_ENV === 'test';
Expand All @@ -166,7 +233,7 @@ const ConnectionsNavigationTree: React.FunctionComponent<
onDefaultAction={onDefaultAction}
onItemAction={onItemAction}
onItemExpand={onItemExpand}
getItemActions={getItemActions}
getItemActions={getItemActionsAndConfig}
getItemKey={(item) => item.id}
renderItem={({
item,
Expand Down
31 changes: 17 additions & 14 deletions packages/compass-connections-navigation/src/item-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,8 @@ export const connectedConnectionItemActions = ({
connectionInfo,
isEditDisabled: true,
}).slice(1); // for connected connections we don't show connect action

const actions: NavigationItemActions = [
{
action: 'create-database',
icon: 'Plus',
label: 'Create database',
},
{
action: 'open-shell',
icon: 'Shell',
label: 'Open MongoDB shell',
isDisabled: !isShellEnabled,
disabledDescription: 'Not available',
},
{
action: 'connection-performance-metrics',
icon: 'Gauge',
Expand Down Expand Up @@ -102,11 +91,25 @@ export const connectedConnectionItemActions = ({
...connectionManagementActions,
];

// we show shell icon only when its enabled
if (isShellEnabled) {
actions.unshift({
action: 'open-shell',
icon: 'Shell',
label: 'Open MongoDB shell',
});
}

// when connection is readonly we don't want to show create-database action
// and hence we splice it out here
if (hasWriteActionsDisabled) {
actions.splice(0, 1);
if (!hasWriteActionsDisabled) {
actions.unshift({
action: 'create-database',
icon: 'Plus',
label: 'Create database',
});
}

return actions;
};

Expand Down
27 changes: 10 additions & 17 deletions packages/compass-connections-navigation/src/navigation-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ type NavigationItemProps = {
item: SidebarTreeItem;
isActive: boolean;
isFocused: boolean;
getItemActions: (item: SidebarTreeItem) => NavigationItemActions;
getItemActions: (item: SidebarTreeItem) => {
actions: NavigationItemActions;
config?: {
collapseAfter: number;
};
};
onItemAction: (item: SidebarActionableItem, action: Actions) => void;
onItemExpand(item: SidebarActionableItem, isExpanded: boolean): void;
};
Expand Down Expand Up @@ -159,25 +164,13 @@ export function NavigationItem({
const style = useMemo(() => getTreeItemStyles(item), [item]);

const actionProps = useMemo(() => {
const collapseAfter = (() => {
if (item.type === 'connection') {
if (
item.connectionStatus === ConnectionStatus.Connected &&
!item.hasWriteActionsDisabled
) {
return 1;
}
// when connected connection is readonly we don't show the create-database action
// so the whole action menu is collapsed
return 0;
}
})();
const { actions, config: actionsConfig } = getItemActions(item);

return {
actions: getItemActions(item),
actions: actions,
onAction: onAction,
...(typeof collapseAfter === 'number' && {
collapseAfter,
...(typeof actionsConfig?.collapseAfter === 'number' && {
collapseAfter: actionsConfig?.collapseAfter,
}),
...(item.type === 'database' && {
collapseToMenuThreshold: 3,
Expand Down
Loading

0 comments on commit df40eed

Please sign in to comment.