Skip to content

Commit 5cb9069

Browse files
authored
feat(data-modeling): field sidebar COMPASS-9659 (#7218)
1 parent bb7cdac commit 5cb9069

15 files changed

+1738
-400
lines changed

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

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
selectCurrentModelFromState,
1717
createNewRelationship,
1818
addCollection,
19+
selectField,
1920
} from '../store/diagram';
2021
import {
2122
Banner,
@@ -36,13 +37,13 @@ import {
3637
type EdgeProps,
3738
useDiagram,
3839
} from '@mongodb-js/diagramming';
39-
import type { StaticModel } from '../services/data-model-storage';
40+
import type { FieldPath, StaticModel } from '../services/data-model-storage';
4041
import DiagramEditorToolbar from './diagram-editor-toolbar';
4142
import ExportDiagramModal from './export-diagram-modal';
4243
import { DATA_MODELING_DRAWER_ID } from './drawer/diagram-editor-side-panel';
4344
import {
4445
collectionToDiagramNode,
45-
getSelectedFields,
46+
getHighlightedFields,
4647
relationshipToDiagramEdge,
4748
} from '../utils/nodes-and-edges';
4849

@@ -113,9 +114,16 @@ const DiagramContent: React.FunctionComponent<{
113114
onMoveCollection: (ns: string, newPosition: [number, number]) => void;
114115
onCollectionSelect: (namespace: string) => void;
115116
onRelationshipSelect: (rId: string) => void;
117+
onFieldSelect: (namespace: string, fieldPath: FieldPath) => void;
116118
onDiagramBackgroundClicked: () => void;
117119
selectedItems: SelectedItems;
118-
onCreateNewRelationship: (source: string, target: string) => void;
120+
onCreateNewRelationship: ({
121+
localNamespace,
122+
foreignNamespace,
123+
}: {
124+
localNamespace: string;
125+
foreignNamespace: string;
126+
}) => void;
119127
onRelationshipDrawn: () => void;
120128
}> = ({
121129
diagramLabel,
@@ -125,6 +133,7 @@ const DiagramContent: React.FunctionComponent<{
125133
onMoveCollection,
126134
onCollectionSelect,
127135
onRelationshipSelect,
136+
onFieldSelect,
128137
onDiagramBackgroundClicked,
129138
onCreateNewRelationship,
130139
onRelationshipDrawn,
@@ -153,7 +162,7 @@ const DiagramContent: React.FunctionComponent<{
153162
}, [model?.relationships, selectedItems]);
154163

155164
const nodes = useMemo<NodeProps[]>(() => {
156-
const selectedFields = getSelectedFields(
165+
const highlightedFields = getHighlightedFields(
157166
selectedItems,
158167
model?.relationships
159168
);
@@ -163,7 +172,11 @@ const DiagramContent: React.FunctionComponent<{
163172
selectedItems.type === 'collection' &&
164173
selectedItems.id === coll.ns;
165174
return collectionToDiagramNode(coll, {
166-
selectedFields,
175+
highlightedFields,
176+
selectedField:
177+
selectedItems?.type === 'field' && selectedItems.namespace === coll.ns
178+
? selectedItems.fieldPath
179+
: undefined,
167180
selected,
168181
isInRelationshipDrawingMode,
169182
});
@@ -219,7 +232,10 @@ const DiagramContent: React.FunctionComponent<{
219232

220233
const handleNodesConnect = useCallback(
221234
(source: string, target: string) => {
222-
onCreateNewRelationship(source, target);
235+
onCreateNewRelationship({
236+
localNamespace: source,
237+
foreignNamespace: target,
238+
});
223239
onRelationshipDrawn();
224240
},
225241
[onRelationshipDrawn, onCreateNewRelationship]
@@ -252,6 +268,12 @@ const DiagramContent: React.FunctionComponent<{
252268
onRelationshipSelect(edge.id);
253269
openDrawer(DATA_MODELING_DRAWER_ID);
254270
}}
271+
onFieldClick={(_evt, { id: fieldPath, nodeId: namespace }) => {
272+
_evt.stopPropagation(); // TODO(COMPASS-9659): should this be handled by the diagramming package?
273+
if (!Array.isArray(fieldPath)) return; // TODO(COMPASS-9659): could be avoided with generics in the diagramming package
274+
onFieldSelect(namespace, fieldPath);
275+
openDrawer(DATA_MODELING_DRAWER_ID);
276+
}}
255277
fitViewOptions={{
256278
maxZoom: 1,
257279
minZoom: 0.25,
@@ -282,6 +304,7 @@ const ConnectedDiagramContent = connect(
282304
onMoveCollection: moveCollection,
283305
onCollectionSelect: selectCollection,
284306
onRelationshipSelect: selectRelationship,
307+
onFieldSelect: selectField,
285308
onDiagramBackgroundClicked: selectBackground,
286309
onCreateNewRelationship: createNewRelationship,
287310
}

packages/compass-data-modeling/src/components/drawer/collection-drawer-content.tsx

Lines changed: 17 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,10 @@ import React, { useEffect, useMemo, useRef } from 'react';
22
import { connect } from 'react-redux';
33
import toNS from 'mongodb-ns';
44
import type {
5-
Relationship,
65
DataModelCollection,
6+
Relationship,
77
} from '../../services/data-model-storage';
8-
import {
9-
Badge,
10-
Button,
11-
IconButton,
12-
css,
13-
palette,
14-
spacing,
15-
TextInput,
16-
Icon,
17-
TextArea,
18-
} from '@mongodb-js/compass-components';
8+
import { TextInput, TextArea } from '@mongodb-js/compass-components';
199
import {
2010
createNewRelationship,
2111
deleteRelationship,
@@ -25,59 +15,30 @@ import {
2515
updateCollectionNote,
2616
} from '../../store/diagram';
2717
import type { DataModelingState } from '../../store/reducer';
28-
import { getDefaultRelationshipName } from '../../utils';
2918
import {
3019
DMDrawerSection,
3120
DMFormFieldContainer,
3221
} from './drawer-section-components';
3322
import { useChangeOnBlur } from './use-change-on-blur';
23+
import { RelationshipsSection } from './relationships-section';
3424

3525
type CollectionDrawerContentProps = {
3626
namespace: string;
3727
collections: DataModelCollection[];
3828
note?: string;
3929
relationships: Relationship[];
4030
isDraftCollection?: boolean;
41-
onCreateNewRelationshipClick: (namespace: string) => void;
31+
onCreateNewRelationshipClick: ({
32+
localNamespace,
33+
}: {
34+
localNamespace: string;
35+
}) => void;
4236
onEditRelationshipClick: (rId: string) => void;
4337
onDeleteRelationshipClick: (rId: string) => void;
4438
onNoteChange: (namespace: string, note: string) => void;
4539
onRenameCollection: (fromNS: string, toNS: string) => void;
4640
};
4741

48-
const titleBtnStyles = css({
49-
marginLeft: 'auto',
50-
maxHeight: 20, // To match accordion line height
51-
});
52-
53-
const emptyRelationshipMessageStyles = css({
54-
color: palette.gray.dark1,
55-
});
56-
57-
const relationshipsListStyles = css({
58-
display: 'flex',
59-
flexDirection: 'column',
60-
gap: spacing[200],
61-
});
62-
63-
const relationshipItemStyles = css({
64-
display: 'flex',
65-
alignItems: 'center',
66-
});
67-
68-
const relationshipNameStyles = css({
69-
flexGrow: 1,
70-
overflow: 'hidden',
71-
textOverflow: 'ellipsis',
72-
whiteSpace: 'nowrap',
73-
minWidth: 0,
74-
paddingRight: spacing[200],
75-
});
76-
77-
const relationshipContentStyles = css({
78-
marginTop: spacing[400],
79-
});
80-
8142
export function getIsCollectionNameValid(
8243
collectionName: string,
8344
namespaces: string[],
@@ -176,73 +137,15 @@ const CollectionDrawerContent: React.FunctionComponent<
176137
/>
177138
</DMFormFieldContainer>
178139
</DMDrawerSection>
179-
180-
<DMDrawerSection
181-
label={
182-
<>
183-
Relationships&nbsp;
184-
<Badge>{relationships.length}</Badge>
185-
<Button
186-
className={titleBtnStyles}
187-
size="xsmall"
188-
onClick={() => {
189-
onCreateNewRelationshipClick(namespace);
190-
}}
191-
>
192-
Add Relationship
193-
</Button>
194-
</>
195-
}
196-
>
197-
<div className={relationshipContentStyles}>
198-
{!relationships.length ? (
199-
<div className={emptyRelationshipMessageStyles}>
200-
This collection does not have any relationships yet.
201-
</div>
202-
) : (
203-
<ul className={relationshipsListStyles}>
204-
{relationships.map((r) => {
205-
const relationshipLabel = getDefaultRelationshipName(
206-
r.relationship
207-
);
208-
209-
return (
210-
<li
211-
key={r.id}
212-
data-relationship-id={r.id}
213-
className={relationshipItemStyles}
214-
>
215-
<span
216-
className={relationshipNameStyles}
217-
title={relationshipLabel}
218-
>
219-
{relationshipLabel}
220-
</span>
221-
<IconButton
222-
aria-label="Edit relationship"
223-
title="Edit relationship"
224-
onClick={() => {
225-
onEditRelationshipClick(r.id);
226-
}}
227-
>
228-
<Icon glyph="Edit" />
229-
</IconButton>
230-
<IconButton
231-
aria-label="Delete relationship"
232-
title="Delete relationship"
233-
onClick={() => {
234-
onDeleteRelationshipClick(r.id);
235-
}}
236-
>
237-
<Icon glyph="Trash" />
238-
</IconButton>
239-
</li>
240-
);
241-
})}
242-
</ul>
243-
)}
244-
</div>
245-
</DMDrawerSection>
140+
<RelationshipsSection
141+
relationships={relationships}
142+
emptyMessage="This collection does not have any relationships yet."
143+
onCreateNewRelationshipClick={() => {
144+
onCreateNewRelationshipClick({ localNamespace: namespace });
145+
}}
146+
onEditRelationshipClick={onEditRelationshipClick}
147+
onDeleteRelationshipClick={onDeleteRelationshipClick}
148+
/>
246149

247150
<DMDrawerSection label="Notes">
248151
<DMFormFieldContainer>

0 commit comments

Comments
 (0)