diff --git a/packages/compass-data-modeling/src/components/new-diagram-form.tsx b/packages/compass-data-modeling/src/components/new-diagram-form.tsx index bac68927711..d9e486a45d9 100644 --- a/packages/compass-data-modeling/src/components/new-diagram-form.tsx +++ b/packages/compass-data-modeling/src/components/new-diagram-form.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, { useMemo, useState } from 'react'; import { connect } from 'react-redux'; import type { DataModelingState } from '../store/reducer'; import { useConnectionsList } from '@mongodb-js/compass-connections/provider'; @@ -31,11 +31,25 @@ import { Select, SelectTable, spacing, + SpinLoader, + Body, TextInput, + SearchInput, } from '@mongodb-js/compass-components'; const footerStyles = css({ - gap: spacing[200], + flexDirection: 'row', + alignItems: 'center', +}); + +const footerTextStyles = css({ marginRight: 'auto' }); + +const footerActionsStyles = css({ display: 'flex', gap: spacing[200] }); + +const formContainerStyles = css({ + display: 'flex', + flexDirection: 'column', + gap: spacing[400], }); const FormStepContainer: React.FunctionComponent<{ @@ -47,6 +61,7 @@ const FormStepContainer: React.FunctionComponent<{ isNextDisabled: boolean; nextLabel: string; previousLabel: string; + footerText?: React.ReactNode; }> = ({ title, description, @@ -57,31 +72,103 @@ const FormStepContainer: React.FunctionComponent<{ nextLabel, previousLabel, children, + footerText, }) => { return ( <> {children} - - + {footerText} +
+ + +
); }; const selectTableStyles = css({ - maxHeight: 300, + height: 300, + overflow: 'scroll', }); +function SelectCollectionsStep({ + collections, + selectedCollections, + onCollectionsSelect, +}: { + collections: string[]; + selectedCollections: string[]; + onCollectionsSelect: (colls: string[]) => void; +}) { + const [searchTerm, setSearchTerm] = useState(''); + const filteredCollections = useMemo(() => { + try { + const regex = new RegExp(searchTerm, 'i'); + return collections.filter((x) => regex.test(x)); + } catch { + return collections; + } + }, [collections, searchTerm]); + return ( + + { + setSearchTerm(e.target.value); + }} + /> + { + return { + id: collName, + selected: selectedCollections.includes(collName), + 'data-testid': `new-diagram-collection-checkbox-${collName}`, + }; + })} + columns={[['id', 'Collection Name']]} + onChange={(items) => { + // When a user is searching, less collections are shown to the user + // and we need to keep existing selected collections selected. + const currentSelectedItems = selectedCollections.filter( + (collName) => { + const item = items.find((x) => x.id === collName); + // The already selected item was not shown to the user (using search), + // and we have to keep it selected. + return item ? item.selected : true; + } + ); + + const newSelectedItems = items + .filter((item) => { + return item.selected; + }) + .map((item) => { + return item.id; + }); + onCollectionsSelect( + Array.from(new Set([...newSelectedItems, ...currentSelectedItems])) + ); + }} + > + + ); +} + type NewDiagramFormProps = { isModalOpen: boolean; formStep: @@ -145,6 +232,7 @@ const NewDiagramForm: React.FunctionComponent = ({ isConfirmDisabled, onCancelAction, cancelLabel, + footerText, } = useMemo(() => { switch (currentStep) { case 'enter-name': @@ -177,14 +265,23 @@ const NewDiagramForm: React.FunctionComponent = ({ case 'select-collections': return { title: `Select collections for ${selectedDatabase ?? ''}`, - description: - 'These collections will be included to the generated diagram', + description: `${ + collections.length === 1 ? 'This collection' : 'These collections' + } will be included in your generated diagram.`, onConfirmAction: onCollectionsSelectionConfirm, confirmActionLabel: 'Generate', isConfirmDisabled: !selectedCollections || selectedCollections.length === 0, onCancelAction: onDatabaseSelectCancel, cancelLabel: 'Back', + footerText: ( + <> + {selectedCollections.length}/ + {collections.length} total{' '} + {collections.length === 1 ? 'collection' : 'collections'}{' '} + selected. + + ), }; } }, [ @@ -201,6 +298,7 @@ const NewDiagramForm: React.FunctionComponent = ({ selectedCollections, selectedConnectionId, selectedDatabase, + collections, ]); const formContent = useMemo(() => { @@ -220,7 +318,7 @@ const NewDiagramForm: React.FunctionComponent = ({ ); case 'select-connection': return ( - +