Skip to content

Commit 4d63d55

Browse files
committed
wip(data-modeling): add delete / rename logic and UI triggers
1 parent 2a67c20 commit 4d63d55

File tree

13 files changed

+361
-114
lines changed

13 files changed

+361
-114
lines changed

packages/compass-components/src/components/leafygreen.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22

33
// This file exports `@leafygreen-ui` components and wraps some of them.
44

@@ -67,7 +67,7 @@ export type {
6767
} from '@leafygreen-ui/table';
6868
import { Tabs, Tab } from '@leafygreen-ui/tabs';
6969
import TextArea from '@leafygreen-ui/text-area';
70-
import TextInput from '@leafygreen-ui/text-input';
70+
import LeafyGreenTextInput from '@leafygreen-ui/text-input';
7171
import { SearchInput } from '@leafygreen-ui/search-input';
7272
export type { ToastProps } from '@leafygreen-ui/toast';
7373
export { ToastProvider, useToast } from '@leafygreen-ui/toast';
@@ -112,6 +112,29 @@ delete (Checkbox as React.ComponentType<any>).propTypes;
112112
// all hrefs.
113113
export { Link, Button, IconButton } from './links/link';
114114

115+
// Working around leafygreen lack of support for `defaultValue` property
116+
const TextInput: typeof LeafyGreenTextInput = React.forwardRef(
117+
function TextInput({ defaultValue, value, onChange, ...props }, ref) {
118+
const [uncontrolledValue, setUncontrolledValue] = useState(
119+
String(defaultValue) ?? ''
120+
);
121+
const isControlled = typeof defaultValue === 'undefined';
122+
return (
123+
<LeafyGreenTextInput
124+
{...props}
125+
value={isControlled ? value : uncontrolledValue}
126+
onChange={(e) => {
127+
setUncontrolledValue(e.currentTarget.value);
128+
onChange?.(e);
129+
}}
130+
ref={ref}
131+
></LeafyGreenTextInput>
132+
);
133+
}
134+
);
135+
136+
TextInput.displayName = 'TextInput';
137+
115138
// 3. Export the leafygreen components.
116139
export {
117140
AtlasNavGraphic,

packages/compass-components/src/hooks/use-confirmation.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Variant as ConfirmationModalVariant } from '@leafygreen-ui/confirmation
99
import ConfirmationModal from '../components/modals/confirmation-modal';
1010
import { css } from '@leafygreen-ui/emotion';
1111
import type { ButtonProps } from '@leafygreen-ui/button';
12+
import FormFieldContainer from '../components/form-field-container';
13+
import { TextInput } from '../components/leafygreen';
1214

1315
export { ConfirmationModalVariant };
1416

@@ -207,3 +209,32 @@ export const ConfirmationModalArea: React.FunctionComponent = ({
207209
</ConfirmationModalAreaMountedContext.Provider>
208210
);
209211
};
212+
213+
export async function showPrompt(
214+
props: Omit<ConfirmationProperties, 'requiredInputText'> & {
215+
label: string;
216+
defaultValue?: string;
217+
}
218+
): Promise<string | null> {
219+
let userInput = props.defaultValue ?? '';
220+
const submitted = await showConfirmation({
221+
...props,
222+
description: (
223+
<>
224+
{props.description && <div>{props.description}</div>}
225+
<div>
226+
<FormFieldContainer>
227+
<TextInput
228+
label={props.label}
229+
defaultValue={userInput}
230+
onChange={(e) => {
231+
userInput = e.currentTarget.value;
232+
}}
233+
></TextInput>
234+
</FormFieldContainer>
235+
</div>
236+
</>
237+
),
238+
});
239+
return submitted ? userInput : null;
240+
}

packages/compass-components/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ export {
180180
ConfirmationModalVariant,
181181
ConfirmationModalArea,
182182
showConfirmation,
183+
showPrompt,
183184
} from './hooks/use-confirmation';
184185
export { showErrorDetails } from './hooks/use-error-details';
185186
export {

packages/compass-connections/src/stores/connections-store-redux.ts

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,67 +1479,67 @@ const connectWithOptions = (
14791479
return inflightConnection;
14801480
}
14811481
inflightConnection = (async () => {
1482-
if (
1483-
getCurrentConnectionStatus(getState(), connectionInfo.id) ===
1484-
'connected'
1485-
) {
1486-
return;
1487-
}
1482+
const deviceAuthAbortController = new AbortController();
14881483

1489-
const isAutoconnectAttempt = isAutoconnectInfo(
1490-
getState(),
1491-
connectionInfo.id
1492-
);
1484+
try {
1485+
if (
1486+
getCurrentConnectionStatus(getState(), connectionInfo.id) ===
1487+
'connected'
1488+
) {
1489+
return;
1490+
}
14931491

1494-
const deviceAuthAbortController = new AbortController();
1492+
const isAutoconnectAttempt = isAutoconnectInfo(
1493+
getState(),
1494+
connectionInfo.id
1495+
);
14951496

1496-
connectionInfo = cloneDeep(connectionInfo);
1497+
connectionInfo = cloneDeep(connectionInfo);
14971498

1498-
const {
1499-
forceConnectionOptions,
1500-
browserCommandForOIDCAuth,
1501-
maximumNumberOfActiveConnections,
1502-
telemetryAnonymousId,
1503-
} = preferences.getPreferences();
1499+
const {
1500+
forceConnectionOptions,
1501+
browserCommandForOIDCAuth,
1502+
maximumNumberOfActiveConnections,
1503+
telemetryAnonymousId,
1504+
} = preferences.getPreferences();
15041505

1505-
const connectionProgress = getNotificationTriggers();
1506+
const connectionProgress = getNotificationTriggers();
15061507

1507-
if (
1508-
typeof maximumNumberOfActiveConnections !== 'undefined' &&
1509-
getActiveConnectionsCount(getState().connections) >=
1510-
maximumNumberOfActiveConnections
1511-
) {
1512-
connectionProgress.openMaximumConnectionsReachedToast(
1513-
maximumNumberOfActiveConnections
1514-
);
1515-
return;
1516-
}
1508+
if (
1509+
typeof maximumNumberOfActiveConnections !== 'undefined' &&
1510+
getActiveConnectionsCount(getState().connections) >=
1511+
maximumNumberOfActiveConnections
1512+
) {
1513+
connectionProgress.openMaximumConnectionsReachedToast(
1514+
maximumNumberOfActiveConnections
1515+
);
1516+
return;
1517+
}
15171518

1518-
dispatch({
1519-
type: ActionTypes.ConnectionAttemptStart,
1520-
connectionInfo,
1521-
options: { forceSave: options.forceSave },
1522-
});
1519+
dispatch({
1520+
type: ActionTypes.ConnectionAttemptStart,
1521+
connectionInfo,
1522+
options: { forceSave: options.forceSave },
1523+
});
15231524

1524-
track(
1525-
'Connection Attempt',
1526-
{
1527-
is_favorite: connectionInfo.savedConnectionType === 'favorite',
1528-
is_new: isNewConnection(getState(), connectionInfo.id),
1529-
},
1530-
connectionInfo
1531-
);
1525+
track(
1526+
'Connection Attempt',
1527+
{
1528+
is_favorite: connectionInfo.savedConnectionType === 'favorite',
1529+
is_new: isNewConnection(getState(), connectionInfo.id),
1530+
},
1531+
connectionInfo
1532+
);
15321533

1533-
debug('connecting with connectionInfo', connectionInfo);
1534+
debug('connecting with connectionInfo', connectionInfo);
15341535

1535-
log.info(
1536-
mongoLogId(1_001_000_004),
1537-
'Connection UI',
1538-
'Initiating connection attempt',
1539-
{ isAutoconnectAttempt }
1540-
);
1536+
log.info(
1537+
mongoLogId(1_001_000_004),
1538+
'Connection UI',
1539+
'Initiating connection attempt',
1540+
{ isAutoconnectAttempt }
1541+
);
15411542

1542-
try {
15431543
// Connection form allows to start connecting with invalid connection
15441544
// strings, so throw fast if it's not valid before doing anything else
15451545
ensureWellFormedConnectionString(

packages/compass-data-modeling/src/components/diagram-editor.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { DataModelingState } from '../store/reducer';
44
import { CodemirrorMultilineEditor } from '@mongodb-js/compass-editor';
55
import {
66
applyEdit,
7+
getCurrentDiagramFromState,
78
redoEdit,
89
selectCurrentModel,
910
undoEdit,
@@ -228,9 +229,11 @@ export default connect(
228229
const { diagram, step } = state;
229230
return {
230231
step: step,
231-
hasUndo: diagram.prev.length > 0,
232-
hasRedo: diagram.next.length > 0,
233-
model: diagram.current ? selectCurrentModel(diagram.current) : null,
232+
hasUndo: (diagram?.edits.prev.length ?? 0) > 0,
233+
hasRedo: (diagram?.edits.next.length ?? 0) > 0,
234+
model: diagram
235+
? selectCurrentModel(getCurrentDiagramFromState(state))
236+
: null,
234237
};
235238
},
236239
{

packages/compass-data-modeling/src/components/new-diagram-form.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
selectDatabase,
1919
} from '../store/generate-diagram-wizard';
2020
import {
21+
Banner,
2122
Button,
2223
css,
2324
FormFieldContainer,
@@ -214,6 +215,7 @@ const NewDiagramForm: React.FunctionComponent<NewDiagramFormProps> = ({
214215
label=""
215216
value={selectedConnectionId ?? ''}
216217
onChange={onConnectionSelect}
218+
disabled={connections.length === 0}
217219
>
218220
{connections.map((connection) => {
219221
return (
@@ -223,6 +225,11 @@ const NewDiagramForm: React.FunctionComponent<NewDiagramFormProps> = ({
223225
);
224226
})}
225227
</Select>
228+
{connections.length === 0 && (
229+
<Banner variant="warning">
230+
You do not have any connections, create a new connection first
231+
</Banner>
232+
)}
226233
</FormFieldContainer>
227234
);
228235
case 'select-database':

packages/compass-data-modeling/src/components/saved-diagrams-list.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@ import {
66
Card,
77
EmptyContent,
88
Icon,
9+
ItemActionMenu,
910
WorkspaceContainer,
1011
} from '@mongodb-js/compass-components';
1112
import { useDataModelSavedItems } from '../provider';
12-
import { openDiagram } from '../store/diagram';
13+
import { deleteDiagram, openDiagram, renameDiagram } from '../store/diagram';
1314
import type { MongoDBDataModelDescription } from '../services/data-model-storage';
1415

1516
const SavedDiagramsList: React.FunctionComponent<{
1617
onCreateDiagramClick: () => void;
1718
onOpenDiagramClick: (diagram: MongoDBDataModelDescription) => void;
18-
}> = ({ onCreateDiagramClick, onOpenDiagramClick }) => {
19+
onDiagramDeleteClick: (id: string) => void;
20+
onDiagramRenameClick: (id: string) => void;
21+
}> = ({
22+
onCreateDiagramClick,
23+
onOpenDiagramClick,
24+
onDiagramRenameClick,
25+
onDiagramDeleteClick,
26+
}) => {
1927
const { items, status } = useDataModelSavedItems();
2028

2129
if (status === 'INITIAL' || status === 'LOADING') {
@@ -32,13 +40,28 @@ const SavedDiagramsList: React.FunctionComponent<{
3240
{items.map((diagram) => {
3341
return (
3442
<Card
35-
style={{ marginTop: 8 }}
43+
style={{ marginTop: 8, display: 'flex' }}
3644
key={diagram.id}
3745
onClick={() => {
3846
onOpenDiagramClick(diagram);
3947
}}
4048
>
4149
{diagram.name}
50+
<ItemActionMenu
51+
isVisible
52+
actions={[
53+
{ action: 'rename', label: 'Rename' },
54+
{ action: 'delete', label: 'Delete' },
55+
]}
56+
onAction={(action) => {
57+
if (action === 'rename') {
58+
onDiagramRenameClick(diagram.id);
59+
}
60+
if (action === 'delete') {
61+
onDiagramDeleteClick(diagram.id);
62+
}
63+
}}
64+
></ItemActionMenu>
4265
</Card>
4366
);
4467
})}
@@ -90,4 +113,6 @@ const SavedDiagramsList: React.FunctionComponent<{
90113
export default connect(null, {
91114
onCreateDiagramClick: createNewDiagram,
92115
onOpenDiagramClick: openDiagram,
116+
onDiagramDeleteClick: deleteDiagram,
117+
onDiagramRenameClick: renameDiagram,
93118
})(SavedDiagramsList);

0 commit comments

Comments
 (0)