Skip to content

Commit 56a4b9e

Browse files
committed
feat: diagram edit handling COMPASS-9312
1 parent f0e08f4 commit 56a4b9e

File tree

3 files changed

+120
-16
lines changed

3 files changed

+120
-16
lines changed

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

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { useCallback, useMemo, useState } from 'react';
22
import { connect } from 'react-redux';
33
import type { DataModelingState } from '../store/reducer';
44
import { CodemirrorMultilineEditor } from '@mongodb-js/compass-editor';
@@ -19,6 +19,9 @@ import {
1919
spacing,
2020
Button,
2121
palette,
22+
SplitButton,
23+
RadioBoxGroup,
24+
RadioBox,
2225
} from '@mongodb-js/compass-components';
2326
import { cancelAnalysis, retryAnalysis } from '../store/analysis-process';
2427

@@ -73,7 +76,7 @@ const modelPreviewStyles = css({
7376
});
7477

7578
const editorContainerStyles = css({
76-
height: 160 + 34 + 16,
79+
height: 46 + 160 + 34 + 16,
7780
display: 'flex',
7881
flexDirection: 'column',
7982
gap: 8,
@@ -86,6 +89,15 @@ const editorContainerApplyButtonStyles = css({
8689
alignSelf: 'flex-end',
8790
});
8891

92+
const editorContainerPlaceholderButtonStyles = css({
93+
paddingLeft: 8,
94+
paddingRight: 8,
95+
alignSelf: 'flex-start',
96+
display: 'flex',
97+
gap: spacing[200],
98+
paddingTop: spacing[200],
99+
});
100+
89101
const DiagramEditor: React.FunctionComponent<{
90102
step: DataModelingState['step'];
91103
hasUndo: boolean;
@@ -118,6 +130,44 @@ const DiagramEditor: React.FunctionComponent<{
118130
}
119131
}, [applyInput]);
120132

133+
const applyPlaceholder = useCallback(
134+
(type: 'AddRelationship' | 'RemoveRelationship') => () => {
135+
let placeholder = {};
136+
switch (type) {
137+
case 'AddRelationship':
138+
placeholder = {
139+
type: 'AddRelationship',
140+
id: 'relationship1',
141+
relationship: [
142+
{
143+
ns: 'db.sourceCollection',
144+
cardinality: 1,
145+
fields: ['field1'],
146+
},
147+
{
148+
ns: 'db.targetCollection',
149+
cardinality: 1,
150+
fields: ['field2'],
151+
},
152+
],
153+
isInferred: false,
154+
};
155+
break;
156+
case 'RemoveRelationship':
157+
placeholder = {
158+
type: 'RemoveRelationship',
159+
id: 'relationship1',
160+
relationshipId: 'relationship1',
161+
};
162+
break;
163+
default:
164+
throw new Error(`Unknown placeholder ${placeholder}`);
165+
}
166+
setApplyInput(JSON.stringify(placeholder, null, 2));
167+
},
168+
[setApplyInput]
169+
);
170+
121171
const modelStr = useMemo(() => {
122172
return JSON.stringify(model, null, 2);
123173
}, [model]);
@@ -172,6 +222,20 @@ const DiagramEditor: React.FunctionComponent<{
172222
></CodemirrorMultilineEditor>
173223
</div>
174224
<div className={editorContainerStyles} data-testid="apply-editor">
225+
<div className={editorContainerPlaceholderButtonStyles}>
226+
<Button
227+
onClick={applyPlaceholder('AddRelationship')}
228+
data-testid="placeholder-addrelationship-button"
229+
>
230+
Add relationship
231+
</Button>
232+
<Button
233+
onClick={applyPlaceholder('RemoveRelationship')}
234+
data-testid="placeholder-removerelationship-button"
235+
>
236+
Remove relationship
237+
</Button>
238+
</div>
175239
<div>
176240
<CodemirrorMultilineEditor
177241
language="json"

packages/compass-data-modeling/src/services/data-model-storage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const EditSchema = z.discriminatedUnion('type', [
4848
type: z.literal('RemoveRelationship'),
4949
id: z.string(),
5050
timestamp: z.string(),
51+
relationshipId: z.string(),
5152
}),
5253
]);
5354

packages/compass-data-modeling/src/store/diagram.ts

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export const diagramReducer: Reducer<DiagramState> = (
128128
};
129129
}
130130
if (isAction(action, DiagramActionTypes.APPLY_EDIT)) {
131-
console.log('Applying edit', action.edit);
132131
return {
133132
...state,
134133
edits: {
@@ -187,7 +186,14 @@ export function applyEdit(
187186
edit: Edit
188187
): DataModelingThunkAction<void, ApplyEditAction> {
189188
return (dispatch, getState, { dataModelStorage }) => {
190-
dispatch({ type: DiagramActionTypes.APPLY_EDIT, edit });
189+
dispatch({
190+
type: DiagramActionTypes.APPLY_EDIT,
191+
edit: {
192+
...edit,
193+
id: new UUID().toString(),
194+
timestamp: new Date().toISOString(),
195+
},
196+
});
191197
void dataModelStorage.save(getCurrentDiagramFromState(getState()));
192198
};
193199
}
@@ -246,24 +252,57 @@ function _applyEdit(edit: Edit, model?: StaticModel): StaticModel {
246252
if (!model) {
247253
throw new Error('Editing a model that has not been initialized');
248254
}
249-
if (edit.type === 'AddRelationship') {
250-
return {
251-
...model,
252-
relationships: [...model.relationships, edit.relationship],
253-
};
255+
switch (edit.type) {
256+
case 'AddRelationship': {
257+
return {
258+
...model,
259+
relationships: [...model.relationships, edit.relationship],
260+
};
261+
}
262+
case 'RemoveRelationship': {
263+
return {
264+
...model,
265+
relationships: model.relationships.filter(
266+
(relationship) => relationship.id !== edit.relationshipId
267+
),
268+
};
269+
}
270+
default: {
271+
return model;
272+
}
254273
}
255-
return model;
256274
}
257275

258276
export function getCurrentModel(
259-
diagram: MongoDBDataModelDescription
277+
description: MongoDBDataModelDescription
260278
): StaticModel {
261-
let model: StaticModel;
262-
for (const edit of diagram.edits) {
263-
console.log('Applying edit', edit, diagram);
264-
model = _applyEdit(edit, model);
279+
// Get the last 'SetModel' edit.
280+
const reversedSetModelEditIndex = description.edits
281+
.slice()
282+
.reverse()
283+
.findIndex((edit) => edit.type === 'SetModel');
284+
if (reversedSetModelEditIndex === -1) {
285+
throw new Error('No diagram model found.');
286+
}
287+
288+
// Calculate the actual index in the original array.
289+
const lastSetModelEditIndex =
290+
description.edits.length - 1 - reversedSetModelEditIndex;
291+
292+
// Start with the StaticModel from the last `SetModel` edit.
293+
if (description.edits[lastSetModelEditIndex].type !== 'SetModel') {
294+
throw new Error('Something went wrong, last edit is not a SetModel');
265295
}
266-
return model;
296+
let currentModel: StaticModel =
297+
description.edits[lastSetModelEditIndex].model;
298+
299+
// Apply all subsequent edits after the last `SetModel` edit.
300+
for (let i = lastSetModelEditIndex + 1; i < description.edits.length; i++) {
301+
const edit = description.edits[i];
302+
currentModel = _applyEdit(edit, currentModel);
303+
}
304+
305+
return currentModel;
267306
}
268307

269308
export function getCurrentDiagramFromState(

0 commit comments

Comments
 (0)