Skip to content

Commit b371164

Browse files
committed
feat(compass-data-modeling): editing relationship via dragging COMPASS-9332
1 parent 6672d76 commit b371164

File tree

4 files changed

+100
-6
lines changed

4 files changed

+100
-6
lines changed

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ function renderDiagramEditorToolbar(
1212
step="EDITING"
1313
hasUndo={true}
1414
hasRedo={true}
15+
isInRelationshipDrawingMode={false}
1516
onUndoClick={() => {}}
1617
onRedoClick={() => {}}
1718
onExportClick={() => {}}
19+
onRelationshipDrawingToggle={() => {}}
1820
{...props}
1921
/>
2022
);
@@ -63,6 +65,36 @@ describe('DiagramEditorToolbar', function () {
6365
});
6466
});
6567

68+
context('add relationship button', function () {
69+
it('renders it active if isInRelationshipDrawingMode is true', function () {
70+
renderDiagramEditorToolbar({ isInRelationshipDrawingMode: true });
71+
const addButton = screen.getByRole('button', {
72+
name: 'Add Relationship',
73+
});
74+
expect(addButton).to.have.attribute('aria-pressed', 'true');
75+
});
76+
77+
it('does not render it active if isInRelationshipDrawingMode is false', function () {
78+
renderDiagramEditorToolbar({ isInRelationshipDrawingMode: false });
79+
const addButton = screen.getByRole('button', {
80+
name: 'Add Relationship',
81+
});
82+
expect(addButton).to.have.attribute('aria-pressed', 'false');
83+
});
84+
85+
it('clicking on it calls onRelationshipDrawingToggle', function () {
86+
const relationshipDrawingToggleSpy = sinon.spy();
87+
renderDiagramEditorToolbar({
88+
onRelationshipDrawingToggle: relationshipDrawingToggleSpy,
89+
});
90+
const addRelationshipButton = screen.getByRole('button', {
91+
name: 'Add Relationship',
92+
});
93+
userEvent.click(addRelationshipButton);
94+
expect(relationshipDrawingToggleSpy).to.have.been.calledOnce;
95+
});
96+
});
97+
6698
it('renders export button and calls onExportClick', function () {
6799
const exportSpy = sinon.spy();
68100
renderDiagramEditorToolbar({ onExportClick: exportSpy });

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
spacing,
1414
useDarkMode,
1515
transparentize,
16+
Tooltip,
1617
} from '@mongodb-js/compass-components';
1718

1819
const containerStyles = css({
@@ -44,10 +45,21 @@ export const DiagramEditorToolbar: React.FunctionComponent<{
4445
step: DataModelingState['step'];
4546
hasUndo: boolean;
4647
hasRedo: boolean;
48+
isInRelationshipDrawingMode: boolean;
4749
onUndoClick: () => void;
4850
onRedoClick: () => void;
4951
onExportClick: () => void;
50-
}> = ({ step, hasUndo, onUndoClick, hasRedo, onRedoClick, onExportClick }) => {
52+
onRelationshipDrawingToggle: () => void;
53+
}> = ({
54+
step,
55+
hasUndo,
56+
onUndoClick,
57+
hasRedo,
58+
onRedoClick,
59+
onExportClick,
60+
onRelationshipDrawingToggle,
61+
isInRelationshipDrawingMode,
62+
}) => {
5163
const darkmode = useDarkMode();
5264
if (step !== 'EDITING') {
5365
return null;
@@ -58,6 +70,20 @@ export const DiagramEditorToolbar: React.FunctionComponent<{
5870
data-testid="diagram-editor-toolbar"
5971
>
6072
<div className={toolbarGroupStyles}>
73+
<Tooltip
74+
trigger={
75+
<IconButton
76+
aria-label="Add Relationship"
77+
onClick={onRelationshipDrawingToggle}
78+
active={isInRelationshipDrawingMode}
79+
aria-pressed={isInRelationshipDrawingMode}
80+
>
81+
<Icon glyph="Relationship"></Icon>
82+
</IconButton>
83+
}
84+
>
85+
Drag from one collection to another to create a relationship.
86+
</Tooltip>
6187
<IconButton aria-label="Undo" disabled={!hasUndo} onClick={onUndoClick}>
6288
<Icon glyph="Undo"></Icon>
6389
</IconButton>

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

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
selectRelationship,
1919
selectBackground,
2020
type DiagramState,
21+
createNewRelationship,
2122
} from '../store/diagram';
2223
import {
2324
Banner,
@@ -231,6 +232,7 @@ const DiagramEditor: React.FunctionComponent<{
231232
onRelationshipSelect: (rId: string) => void;
232233
onDiagramBackgroundClicked: () => void;
233234
selectedItems: SelectedItems;
235+
onRelationshipDrawn: (source: string, target: string) => void;
234236
}> = ({
235237
diagramLabel,
236238
step,
@@ -242,6 +244,7 @@ const DiagramEditor: React.FunctionComponent<{
242244
onCollectionSelect,
243245
onRelationshipSelect,
244246
onDiagramBackgroundClicked,
247+
onRelationshipDrawn,
245248
selectedItems,
246249
}) => {
247250
const { log, mongoLogId } = useLogger('COMPASS-DATA-MODELING-DIAGRAM-EDITOR');
@@ -250,6 +253,8 @@ const DiagramEditor: React.FunctionComponent<{
250253
const diagram = useDiagram();
251254
const [areNodesReady, setAreNodesReady] = useState(false);
252255
const { openDrawer } = useDrawerActions();
256+
const [isInRelationshipDrawingMode, setIsInRelationshipDrawingMode] =
257+
useState(false);
253258

254259
const setDiagramContainerRef = useCallback(
255260
(ref: HTMLDivElement | null) => {
@@ -302,9 +307,27 @@ const DiagramEditor: React.FunctionComponent<{
302307
!!selectedItems &&
303308
selectedItems.type === 'collection' &&
304309
selectedItems.id === coll.ns,
310+
connectable: isInRelationshipDrawingMode,
311+
draggable: !isInRelationshipDrawingMode,
305312
})
306313
);
307-
}, [model?.collections, model?.relationships, selectedItems]);
314+
}, [
315+
model?.collections,
316+
model?.relationships,
317+
selectedItems,
318+
isInRelationshipDrawingMode,
319+
]);
320+
321+
const handleNodesConnect = useCallback(
322+
(source: string, target: string) => {
323+
onRelationshipDrawn(source, target);
324+
},
325+
[onRelationshipDrawn]
326+
);
327+
328+
const handleRelationshipDrawingToggle = useCallback(() => {
329+
setIsInRelationshipDrawingMode((prev) => !prev);
330+
}, []);
308331

309332
const applyInitialLayout = useCallback(async () => {
310333
try {
@@ -420,14 +443,25 @@ const DiagramEditor: React.FunctionComponent<{
420443
onNodeDragStop={(evt, node) => {
421444
onMoveCollection(node.id, [node.position.x, node.position.y]);
422445
}}
446+
onConnect={({ source, target }) => {
447+
handleNodesConnect(source, target);
448+
setIsInRelationshipDrawingMode(false);
449+
}}
423450
/>
424451
</div>
425452
</div>
426453
);
427454
}
428455

429456
return (
430-
<WorkspaceContainer toolbar={<DiagramEditorToolbar />}>
457+
<WorkspaceContainer
458+
toolbar={
459+
<DiagramEditorToolbar
460+
onRelationshipDrawingToggle={handleRelationshipDrawingToggle}
461+
isInRelationshipDrawingMode={isInRelationshipDrawingMode}
462+
/>
463+
}
464+
>
431465
{content}
432466
<ExportDiagramModal />
433467
</WorkspaceContainer>
@@ -454,6 +488,7 @@ export default connect(
454488
onMoveCollection: moveCollection,
455489
onCollectionSelect: selectCollection,
456490
onRelationshipSelect: selectRelationship,
491+
onRelationshipDrawn: createNewRelationship,
457492
onDiagramBackgroundClicked: selectBackground,
458493
}
459494
)(DiagramEditor);

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ export function selectBackground(): DiagramBackgroundSelectedAction {
322322
}
323323

324324
export function createNewRelationship(
325-
namespace: string
325+
localNamespace: string,
326+
foreignNamespace: string | null = null
326327
): DataModelingThunkAction<void, RelationSelectedAction> {
327328
return (dispatch, getState, { track }) => {
328329
const relationshipId = new UUID().toString();
@@ -335,8 +336,8 @@ export function createNewRelationship(
335336
relationship: {
336337
id: relationshipId,
337338
relationship: [
338-
{ ns: namespace, cardinality: 1, fields: null },
339-
{ ns: null, cardinality: 1, fields: null },
339+
{ ns: localNamespace, cardinality: 1, fields: null },
340+
{ ns: foreignNamespace, cardinality: 1, fields: null },
340341
],
341342
isInferred: false,
342343
},

0 commit comments

Comments
 (0)