diff --git a/packages/compass/src/app/components/home.spec.tsx b/packages/compass/src/app/components/home.spec.tsx index daee2d8611..0777cba316 100644 --- a/packages/compass/src/app/components/home.spec.tsx +++ b/packages/compass/src/app/components/home.spec.tsx @@ -1,6 +1,5 @@ import React, { type ComponentProps } from 'react'; import { expect } from 'chai'; -import * as hadronIpc from 'hadron-ipc'; import sinon from 'sinon'; import { ThemedHome } from './home'; import type { DataService } from 'mongodb-data-service'; @@ -11,7 +10,6 @@ import { screen, waitFor, within, - userEvent, } from '@mongodb-js/testing-library-compass'; import type { AllPreferences } from 'compass-preferences-model/provider'; import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider'; @@ -79,29 +77,12 @@ describe('Home [Component]', function () { return result; } - async function waitForConnect() { - userEvent.click(screen.getByRole('button', { name: 'Connect' })); - - await waitFor( - () => { - screen.getByTestId('home'); - }, - { timeout: 1_000_000 } - ); - } - afterEach(() => { cleanup(); sinon.restore(); }); describe('is not connected', function () { - it('renders the connect screen', function () { - renderHome(); - expect(() => screen.getByTestId('home')).to.throw; - expect(screen.getByTestId('connections-wrapper')).to.be.displayed; - }); - it('renders welcome modal and hides it', async function () { renderHome({ showWelcomeModal: true }); const modal = screen.getByTestId('welcome-modal'); @@ -137,58 +118,4 @@ describe('Home [Component]', function () { }); }); }); - - describe('is connected', function () { - describe('when UI status is complete', function () { - let dataServiceDisconnectedSpy: sinon.SinonSpy; - - let onDisconnectSpy: sinon.SinonSpy; - let hideCollectionSubMenuSpy: sinon.SinonSpy; - - beforeEach(async function () { - dataServiceDisconnectedSpy = sinon.fake.resolves(true); - hideCollectionSubMenuSpy = sinon.spy(); - onDisconnectSpy = sinon.spy(); - const dataService = { - ...createDataService(), - disconnect: dataServiceDisconnectedSpy, - addReauthenticationHandler: sinon.stub(), - }; - renderHome( - { - hideCollectionSubMenu: hideCollectionSubMenuSpy, - onDisconnect: onDisconnectSpy, - }, - [], - dataService - ); - await waitForConnect(); - }); - - afterEach(function () { - sinon.restore(); - }); - - it('renders only the workspaces', function () { - expect(screen.getByTestId('home')).to.be.displayed; - expect(() => screen.getByTestId('connections-wrapper')).to.throw; - }); - - it('on `app:disconnect`', async function () { - hadronIpc.ipcRenderer?.emit('app:disconnect'); - await waitFor(() => { - expect(onDisconnectSpy.called, 'it calls onDisconnect').to.be.true; - expect( - hideCollectionSubMenuSpy.called, - 'it calls hideCollectionSubMenu' - ).to.be.true; - }); - - await waitFor(() => { - expect(screen.queryByTestId('connections-wrapper')).to.be.visible; - }); - expect(dataServiceDisconnectedSpy.callCount).to.equal(1); - }); - }); - }); }); diff --git a/packages/connection-form/src/components/connection-form-actions.spec.tsx b/packages/connection-form/src/components/connection-form-actions.spec.tsx index 3fb75a3ab2..0343426176 100644 --- a/packages/connection-form/src/components/connection-form-actions.spec.tsx +++ b/packages/connection-form/src/components/connection-form-actions.spec.tsx @@ -1,12 +1,54 @@ import React from 'react'; -import { render, screen, fireEvent } from '@mongodb-js/testing-library-compass'; +import { render, screen, userEvent } from '@mongodb-js/testing-library-compass'; import { expect } from 'chai'; import sinon from 'sinon'; import { ConnectionFormModalActions } from './connection-form-actions'; describe('', function () { + it('should show warnings', function () { + render( + undefined} + onSaveAndConnect={() => undefined} + > + ); + expect(screen.getByText('Warning!')).to.be.visible; + }); + + it('should show errors', function () { + render( + undefined} + onSaveAndConnect={() => undefined} + > + ); + expect(screen.getByText('Error!')).to.be.visible; + }); + describe('Connect Button', function () { + it('should call onSaveAndConnect function', function () { + const onSaveAndConnectSpy = sinon.spy(); + render( + undefined} + onSaveAndConnect={onSaveAndConnectSpy} + > + ); + const connectButton = screen.getByRole('button', { name: 'Connect' }); + userEvent.click(connectButton); + + expect(onSaveAndConnectSpy).to.have.been.calledOnce; + }); + }); + + describe('Save Button', function () { it('should call onSave function', function () { const onSaveSpy = sinon.spy(); render( @@ -17,38 +59,24 @@ describe('', function () { onSaveAndConnect={() => undefined} > ); - const saveButton = screen.getByText('Save'); - fireEvent( - saveButton, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); + const saveButton = screen.getByRole('button', { name: 'Save' }); + userEvent.click(saveButton); expect(onSaveSpy).to.have.been.calledOnce; }); - it('should call onSaveAndConnect function', function () { - const onSaveAndConnectSpy = sinon.spy(); + it('should hide "save" button if there is no callback', function () { render( undefined} - onSaveAndConnect={onSaveAndConnectSpy} + onSaveAndConnect={() => undefined} > ); - const saveButton = screen.getByText('Connect'); - fireEvent( - saveButton, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); - expect(onSaveAndConnectSpy).to.have.been.calledOnce; + expect(screen.queryByRole('button', { name: 'Save' })).to.not.exist; }); + }); + describe('Cancel Button', function () { it('should call onCancel function', function () { const onCancelSpy = sinon.spy(); render( @@ -60,39 +88,22 @@ describe('', function () { onCancel={onCancelSpy} > ); - const saveButton = screen.getByText('Cancel'); - fireEvent( - saveButton, - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ); + const cancelButton = screen.getByRole('button', { name: 'Cancel' }); + userEvent.click(cancelButton); + expect(onCancelSpy).to.have.been.calledOnce; }); - it('should show warnings', function () { + it('should hide onCancel button if there is no callback', function () { render( undefined} - onSaveAndConnect={() => undefined} - > - ); - expect(screen.getByText('Warning!')).to.be.visible; - }); - - it('should show errors', function () { - render( - undefined} onSaveAndConnect={() => undefined} > ); - expect(screen.getByText('Error!')).to.be.visible; + expect(screen.queryByRole('button', { name: 'Cancel' })).to.not.exist; }); }); }); diff --git a/packages/connection-form/src/components/connection-form-actions.tsx b/packages/connection-form/src/components/connection-form-actions.tsx index dd32358a21..1ae3bcaaac 100644 --- a/packages/connection-form/src/components/connection-form-actions.tsx +++ b/packages/connection-form/src/components/connection-form-actions.tsx @@ -38,99 +38,15 @@ const saveAndConnectStyles = css({ justifyContent: 'flex-end', }); -export function LegacyConnectionFormActions({ - errors, - warnings, - onConnectClicked, - onSaveClicked, - onSaveAndConnectClicked, - saveButton, - saveAndConnectButton, -}: { - errors: ConnectionFormError[]; - warnings: ConnectionFormWarning[]; - onConnectClicked: () => void; - onSaveClicked: () => void; - onSaveAndConnectClicked: () => void; - saveButton: 'enabled' | 'disabled' | 'hidden'; - saveAndConnectButton: 'enabled' | 'disabled' | 'hidden'; -}): React.ReactElement { - const showFavoriteActions = useConnectionFormPreference( - 'showFavoriteActions' - ); - - return ( -
- {warnings.length > 0 && ( -
- warning.message)} - /> -
- )} - {errors.length > 0 && ( -
- error.message)} - /> -
- )} -
- {showFavoriteActions && ( - <> - {saveButton !== 'hidden' && ( - - )} - - {saveAndConnectButton !== 'hidden' && ( -
- -
- )} - - )} - - -
-
- ); -} - export type ConnectionFormModalActionsProps = { errors: ConnectionFormError[]; warnings: ConnectionFormWarning[]; onCancel?(): void; - onSave(): void; + onSave?(): void; onSaveAndConnect(): void; }; -// TODO(COMPASS-8098): Make sure these work for VSCode, for example add: -// saveButton: 'enabled' | 'disabled' | 'hidden'; -// saveAndConnectButton: 'enabled' | 'disabled' | 'hidden'; -// cancelButton: 'enabled' | 'disabled' | 'hidden'; export function ConnectionFormModalActions({ errors, warnings, @@ -138,6 +54,9 @@ export function ConnectionFormModalActions({ onSave, onSaveAndConnect, }: ConnectionFormModalActionsProps): React.ReactElement { + const saveAndConnectLabel = useConnectionFormPreference( + 'saveAndConnectLabel' + ); return (
{warnings.length > 0 && ( @@ -168,23 +87,25 @@ export function ConnectionFormModalActions({ )} -
- -
+ {onSave && ( +
+ +
+ )}
diff --git a/packages/connection-form/src/components/connection-form.spec.tsx b/packages/connection-form/src/components/connection-form.spec.tsx index e915862dc5..5d64e021fc 100644 --- a/packages/connection-form/src/components/connection-form.spec.tsx +++ b/packages/connection-form/src/components/connection-form.spec.tsx @@ -73,7 +73,7 @@ describe('ConnectionForm Component', function () { it('should render the connection string textbox', function () { renderForm(); - const textArea = screen.getByTestId('connectionString'); + const textArea = screen.getByTestId('connectionString'); expect(textArea).to.have.text('mongodb://pineapple:*****@localhost:27019/'); }); @@ -417,9 +417,8 @@ describe('ConnectionForm Component', function () { describe('name input', function () { it('should sync with the href of the connection string unless it has been edited', async function () { - const connectionString = screen.getByTestId( - 'connectionString' - ) as HTMLInputElement; + const connectionString = + screen.getByTestId('connectionString'); userEvent.clear(connectionString); await waitFor(() => expect(connectionString.value).to.equal('')); @@ -430,19 +429,18 @@ describe('ConnectionForm Component', function () { expect(connectionString.value).to.equal('mongodb://myserver:27017/') ); - const personalizationName = screen.getByTestId( + const personalizationName = screen.getByTestId( 'personalization-name-input' - ) as HTMLInputElement; + ); expect(personalizationName.value).to.equal('myserver:27017'); }); it('should not sync with the href of the connection string when it has been edited', async function () { - const connectionString = screen.getByTestId( - 'connectionString' - ) as HTMLInputElement; - const personalizationName = screen.getByTestId( + const connectionString = + screen.getByTestId('connectionString'); + const personalizationName = screen.getByTestId( 'personalization-name-input' - ) as HTMLInputElement; + ); userEvent.clear(personalizationName); userEvent.clear(connectionString); diff --git a/packages/connection-form/src/components/connection-form.tsx b/packages/connection-form/src/components/connection-form.tsx index a0896967c7..3ce6d49658 100644 --- a/packages/connection-form/src/components/connection-form.tsx +++ b/packages/connection-form/src/components/connection-form.tsx @@ -8,10 +8,6 @@ import { BannerVariant, Checkbox, Description, - FavoriteIcon, - Icon, - IconButton, - Overline, H3, spacing, Select, @@ -28,17 +24,13 @@ import { cloneDeep } from 'lodash'; import { usePreference } from 'compass-preferences-model/provider'; import ConnectionStringInput from './connection-string-input'; import AdvancedConnectionOptions from './advanced-connection-options'; -import { - ConnectionFormModalActions, - LegacyConnectionFormActions, -} from './connection-form-actions'; +import { ConnectionFormModalActions } from './connection-form-actions'; import { useConnectForm, type ConnectionPersonalizationOptions, type UpdateConnectionFormField, } from '../hooks/use-connect-form'; import { validateConnectionOptionsErrors } from '../utils/validation'; -import SaveConnectionModal from './save-connection-modal'; import type { ConnectionFormPreferences } from '../hooks/use-connect-form-preferences'; import { ConnectionFormPreferencesContext, @@ -125,22 +117,6 @@ const formFooterBorderLightModeStyles = css({ borderTop: `1px solid ${palette.gray.light2}`, }); -const favoriteButtonStyles = css({ - position: 'absolute', - top: -spacing[400], - right: 0, - cursor: 'pointer', - width: spacing[7], - height: spacing[7], -}); - -const favoriteButtonContentStyles = css({ - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', -}); - const headingWithHiddenButtonStyles = css({ button: { visibility: 'hidden', @@ -152,14 +128,6 @@ const headingWithHiddenButtonStyles = css({ }, }); -const editFavoriteButtonStyles = css({ - verticalAlign: 'text-top', -}); - -const favoriteButtonLabelStyles = css({ - paddingTop: spacing[1], -}); - const connectionStringErrorStyles = css({ marginBottom: spacing[3], }); @@ -341,7 +309,7 @@ type ConnectionFormPropsWithoutPreferences = { onCancel?: () => void; onConnectClicked?: (connectionInfo: ConnectionInfo) => void; onSaveAndConnectClicked?: (connectionInfo: ConnectionInfo) => void; - onSaveClicked: (connectionInfo: ConnectionInfo) => Promise; + onSaveClicked?: (connectionInfo: ConnectionInfo) => Promise; onAdvancedOptionsToggle?: (newState: boolean) => void; openSettingsModal?: (tab?: string) => void; }; @@ -377,7 +345,6 @@ function ConnectionForm({ const [ { enableEditingConnectionString: _enableEditingConnectionString, - isDirty, errors, warnings: _warnings, connectionOptions, @@ -387,10 +354,6 @@ function ConnectionForm({ { setEnableEditingConnectionString, updateConnectionFormField, setErrors }, ] = useConnectForm(initialConnectionInfo, connectionErrorMessage); - type SaveConnectionModalState = 'hidden' | 'save' | 'saveAndConnect'; - - const [saveConnectionModal, setSaveConnectionModal] = - useState('hidden'); const protectConnectionStrings = !!useConnectionFormPreference('protectConnectionStrings') && !allowEditingIfProtected; @@ -507,13 +470,15 @@ function ConnectionForm({ [onSaveClicked, setErrors] ); - const showFavoriteActions = useConnectionFormPreference( - 'showFavoriteActions' + const showPersonalisationForm = useConnectionFormPreference( + 'showPersonalisationForm' ); const showFooterBorder = !!isMultiConnectionEnabled; - const showHelpCardsInForm = !!isMultiConnectionEnabled; + const showHelpCardsInForm = useConnectionFormPreference( + 'showHelpCardsInForm' + ); return ( @@ -531,47 +496,10 @@ function ConnectionForm({

{initialConnectionInfo.favorite?.name ?? 'New Connection'} - {!isMultiConnectionEnabled && showFavoriteActions && ( - { - setSaveConnectionModal('save'); - }} - > - - - )}

- {!isMultiConnectionEnabled && 'Connect to a MongoDB deployment'} - {isMultiConnectionEnabled && 'Manage your connection settings'} + Manage your connection settings - - {!isMultiConnectionEnabled && showFavoriteActions && ( - { - setSaveConnectionModal('save'); - }} - > -
- - - FAVORITE - -
-
- )}
@@ -599,7 +527,7 @@ function ConnectionForm({ {connectionStringInvalidError.message} )} - {isMultiConnectionEnabled && ( + {showPersonalisationForm && ( - {isMultiConnectionEnabled && ( - + void callOnSaveConnectionClickedAndStoreErrors?.( getConnectionInfoToSave() - ) - } - onSaveAndConnect={() => onSubmitForm('saveAndConnect')} - /> - )} - {!isMultiConnectionEnabled && ( - { - if (initialConnectionInfo.favorite) { - void callOnSaveConnectionClickedAndStoreErrors({ - ...cloneDeep(initialConnectionInfo), - connectionOptions: cloneDeep(connectionOptions), - }); - } else { - setSaveConnectionModal('save'); - } - }} - onSaveAndConnectClicked={() => { - setSaveConnectionModal('saveAndConnect'); - }} - onConnectClicked={() => onSubmitForm('connect')} - /> - )} + )) + } + onSaveAndConnect={() => onSubmitForm('saveAndConnect')} + /> - - {showFavoriteActions && ( - { - setSaveConnectionModal('hidden'); - }} - onSaveClicked={async (favoriteInfo: ConnectionFavoriteOptions) => { - setSaveConnectionModal('hidden'); - - const connectionInfo = getConnectionInfoToSave(favoriteInfo); - await callOnSaveConnectionClickedAndStoreErrors(connectionInfo); - - if (saveConnectionModal === 'saveAndConnect') { - // Connect to the newly created favorite - onSubmitForm('connect'); - } - }} - key={initialConnectionInfo.id} - initialFavoriteInfo={initialConnectionInfo.favorite} - /> - )}
); } -const ConnectionFormWithPreferences = ( - props: ConnectionFormPropsWithoutPreferences & { +const ConnectionFormWithPreferences: React.FunctionComponent< + ConnectionFormPropsWithoutPreferences & { preferences?: Partial; } -) => { - const { preferences, ...rest } = props; - +> = ({ preferences, ...rest }) => { return ( diff --git a/packages/connection-form/src/hooks/use-connect-form-preferences.tsx b/packages/connection-form/src/hooks/use-connect-form-preferences.tsx index 0a2367841b..d01ebb86e9 100644 --- a/packages/connection-form/src/hooks/use-connect-form-preferences.tsx +++ b/packages/connection-form/src/hooks/use-connect-form-preferences.tsx @@ -3,6 +3,8 @@ import { createContext, useContext } from 'react'; // Not all of these preference map to Compass preferences. export type ConnectionFormPreferences = { showFavoriteActions: boolean; + showHelpCardsInForm: boolean; + showPersonalisationForm: boolean; protectConnectionStrings: boolean; forceConnectionOptions: [key: string, value: string][]; showKerberosPasswordField: boolean; @@ -14,10 +16,13 @@ export type ConnectionFormPreferences = { showKerberosAuth: boolean; showCSFLE: boolean; showProxySettings: boolean; + saveAndConnectLabel: string; }; const defaultPreferences = { showFavoriteActions: true, + showPersonalisationForm: true, + showHelpCardsInForm: true, protectConnectionStrings: false, forceConnectionOptions: [], showKerberosPasswordField: false, @@ -29,6 +34,7 @@ const defaultPreferences = { showKerberosAuth: true, showCSFLE: true, showProxySettings: true, + saveAndConnectLabel: 'Connect', }; export const ConnectionFormPreferencesContext = createContext<