Skip to content
Open
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
4 changes: 1 addition & 3 deletions e2e/add-new-collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ test('opens MongoDB Designer, adds collection, and checks "New Collection" visib
await expect(newButton).toBeVisible();
await newButton.click();

const addCollectionButton = page
.getByRole('button', { name: 'Add Collection' })
.first();
const addCollectionButton = page.locator('.add-collection-button');
await expect(addCollectionButton).toBeVisible();
await addCollectionButton.click();

Expand Down
102 changes: 91 additions & 11 deletions src/common/components/action-button/action-button.component.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@ import { fireEvent, render, screen } from '@testing-library/react';
import { vi } from 'vitest';
import { ActionButton } from './action-button.component';
import { ShortcutOptions } from '@/common/shortcut';
import { useModalDialogContext } from '@/core/providers';

vi.mock('@/core/providers', () => ({
useModalDialogContext: vi.fn(),
}));

describe('ActionButton', () => {
let onClick: () => void;
let shortcutOptions: ShortcutOptions;

beforeEach(() => {
vi.mocked(useModalDialogContext).mockReturnValue({
modalDialog: {
isOpen: false,
selectedComponent: null,
title: '',
},
openModal: vi.fn(),
closeModal: vi.fn(),
});

onClick = vi.fn();

shortcutOptions = {
Expand Down Expand Up @@ -52,19 +67,84 @@ describe('ActionButton', () => {
expect(onClick).toHaveBeenCalled();
});

it('should render the tooltip with the correct shortcut key', () => {
const { getByRole } = render(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
shortcutOptions={shortcutOptions}
/>
);
describe('tooltip display', () => {
it('should render system modifier correctly', () => {
// Test Mac
const { getByRole, rerender } = render(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
shortcutOptions={{
...shortcutOptions,
modifierType: 'system',
}}
/>
);
expect(getByRole('tooltip').textContent).toBe('(⌘ + A)');

// Test Windows
Object.defineProperty(window.navigator, 'userAgent', {
value: 'Windows',
configurable: true,
});
rerender(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
shortcutOptions={{
...shortcutOptions,
modifierType: 'system',
}}
/>
);
expect(getByRole('tooltip').textContent).toBe('(Ctrl + A)');
});

const tooltip = getByRole('tooltip');
it('should render alt tooltip correctly', () => {
const { getByRole } = render(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
shortcutOptions={{
...shortcutOptions,
modifierType: 'alt',
}}
/>
);
expect(getByRole('tooltip').textContent).toBe('(Alt + A)');
});

it('should render mo-modifier tooltip correctly', () => {
const { getByRole } = render(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
shortcutOptions={{
...shortcutOptions,
modifierType: 'none',
}}
/>
);
expect(getByRole('tooltip').textContent).toBe('(A)');
});

expect(tooltip.textContent).toContain('Ctrl + A');
it('should not show tooltip when disabled', () => {
const { queryByRole } = render(
<ActionButton
icon={<span>Icon</span>}
label="Label"
onClick={onClick}
disabled
shortcutOptions={shortcutOptions}
/>
);

expect(queryByRole('tooltip')).toBeNull();
});
});

it('should disable the button if the disabled prop is true', () => {
Expand Down
25 changes: 22 additions & 3 deletions src/common/components/action-button/action-button.component.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { isMacOS } from '@/common/helpers/platform.helpers';
import classes from './action-button.component.module.css';
import { ShortcutOptions } from '@/common/shortcut';
import { ModifierType, ShortcutOptions } from '@/common/shortcut';
import useShortcut from '@/common/shortcut/shortcut.hook';

interface Props {
Expand All @@ -25,9 +25,28 @@ export const ActionButton: React.FC<Props> = ({
showLabel = true,
tooltipPosition = 'bottom',
}) => {
const shortcutCommand = isMacOS() ? 'Ctrl' : 'Alt';
const getModifierSymbol = (modifierType: ModifierType = 'system') => {
switch (modifierType) {
case 'none':
return '';
case 'alt':
return 'Alt';
case 'system':
default:
return isMacOS() ? '⌘' : 'Ctrl';
}
};

const shortcutCommand = getModifierSymbol(shortcutOptions?.modifierType);

const showTooltip = shortcutOptions && !disabled;
const tooltipText = `(${shortcutCommand} + ${shortcutOptions?.targetKeyLabel})`;
const tooltipText =
shortcutOptions &&
`(${
shortcutOptions.modifierType === 'none'
? shortcutOptions.targetKeyLabel
: `${shortcutCommand} + ${shortcutOptions.targetKeyLabel}`
})`;

const tooltipPositionClass =
tooltipPosition === 'top' ? classes.tooltipTop : classes.tooltipBottom;
Expand Down
198 changes: 101 additions & 97 deletions src/common/shortcut/shortcut.const.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,108 @@
import { ShortcutOptions } from './shortcut.model';

interface Shortcut {
[key: string]: ShortcutOptions;
[key: string]: ShortcutOptions;
}

export const SHORTCUTS: Shortcut = {
addCollection: {
description: 'Add Collection',
id: 'add-collection-button-shortcut',
targetKey: ['c'],
targetKeyLabel: 'C',
},
addRelation: {
description: 'Add Relation',
id: 'add-relation-button-shortcut',
targetKey: ['r'],
targetKeyLabel: 'R',
},
delete: {
description: 'Delete',
id: 'delete-button-shortcut',
targetKey: ['backspace'],
targetKeyLabel: 'Backspace',
},
export: {
description: 'Export',
id: 'export-button-shortcut',
targetKey: ['e'],
targetKeyLabel: 'E',
},
new: {
description: 'New',
id: 'new-button-shortcut',
targetKey: ['n'],
targetKeyLabel: 'N',
},
open: {
description: 'Open',
id: 'open-button-shortcut',
targetKey: ['o'],
targetKeyLabel: 'O',
},
redo: {
description: 'Redo',
id: 'redo-button-shortcut',
targetKey: ['y'],
targetKeyLabel: 'Y',
},
save: {
description: 'Save',
id: 'save-button-shortcut',
targetKey: ['s'],
targetKeyLabel: 'S',
},
settings: {
description: 'Settings',
id: 'settings-button-shortcut',
targetKey: ['t'],
targetKeyLabel: 'T',
},
undo: {
description: 'Undo',
id: 'undo-button-shortcut',
targetKey: ['z'],
targetKeyLabel: 'Z',
},
zoomIn: {
description: 'Zoom In',
id: 'zoom-in-button-shortcut',
targetKey: ['=', '+'],
targetKeyLabel: '"+"',
},
zoomOut: {
description: 'Zoom Out',
id: 'zoom-out-button-shortcut',
targetKey: ['-', '-'],
targetKeyLabel: '"-"',
},
duplicate: {
description: 'Duplicate',
id: 'duplicate-button-shortcut',
targetKey: ['d'],
targetKeyLabel: 'D',
},
copy: {
description: 'Copy',
id: 'copy-button-shortcut',
targetKey: ['c'],
targetKeyLabel: 'C',
},
paste: {
description: 'Paste',
id: 'paste-button-shortcut',
targetKey: ['v'],
targetKeyLabel: 'V',
},
import: {
description: 'Import',
id: 'import-button-shortcut',
targetKey: ['i'],
targetKeyLabel: 'I',
},
addCollection: {
description: 'Add Collection',
id: 'add-collection-button-shortcut',
targetKey: ['c'],
targetKeyLabel: 'Collection "C"',
modifierType: 'none',
},
addRelation: {
description: 'Add Relation',
id: 'add-relation-button-shortcut',
targetKey: ['r'],
targetKeyLabel: 'Relation "R"',
modifierType: 'none',
},
delete: {
description: 'Delete',
id: 'delete-button-shortcut',
targetKey: ['backspace'],
targetKeyLabel: 'Backspace',
modifierType: 'none',
},
export: {
description: 'Export',
id: 'export-button-shortcut',
targetKey: ['e'],
targetKeyLabel: 'E',
},
new: {
description: 'New',
id: 'new-button-shortcut',
targetKey: ['n'],
targetKeyLabel: 'N',
modifierType: 'alt',
},
open: {
description: 'Open',
id: 'open-button-shortcut',
targetKey: ['o'],
targetKeyLabel: 'O',
},
redo: {
description: 'Redo',
id: 'redo-button-shortcut',
targetKey: ['y'],
targetKeyLabel: 'Y',
},
save: {
description: 'Save',
id: 'save-button-shortcut',
targetKey: ['s'],
targetKeyLabel: 'S',
},
settings: {
description: 'Settings',
id: 'settings-button-shortcut',
targetKey: [','],
targetKeyLabel: ',',
},
undo: {
description: 'Undo',
id: 'undo-button-shortcut',
targetKey: ['z'],
targetKeyLabel: 'Z',
},
zoomIn: {
description: 'Zoom In',
id: 'zoom-in-button-shortcut',
targetKey: ['=', '+'],
targetKeyLabel: '"+"',
},
zoomOut: {
description: 'Zoom Out',
id: 'zoom-out-button-shortcut',
targetKey: ['-', '-'],
targetKeyLabel: '"-"',
},
duplicate: {
description: 'Duplicate',
id: 'duplicate-button-shortcut',
targetKey: ['d'],
targetKeyLabel: 'D',
},
copy: {
description: 'Copy',
id: 'copy-button-shortcut',
targetKey: ['c'],
targetKeyLabel: 'C',
},
paste: {
description: 'Paste',
id: 'paste-button-shortcut',
targetKey: ['v'],
targetKeyLabel: 'V',
},
import: {
description: 'Import',
id: 'import-button-shortcut',
targetKey: ['i'],
targetKeyLabel: 'I',
},
};
Loading