Skip to content

Commit 88b2077

Browse files
authored
feat(data-modeling): add note editing to collections and relationships COMPASS-9654 (#7171)
* feat(data-modeling): add note editing to collections and relationships * chore(data-modeling): add test for note editing in collection drawer
1 parent e529bce commit 88b2077

File tree

8 files changed

+183
-47
lines changed

8 files changed

+183
-47
lines changed

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

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,37 @@ import {
66
Button,
77
IconButton,
88
css,
9-
FormFieldContainer,
109
palette,
1110
spacing,
1211
TextInput,
1312
Icon,
13+
TextArea,
1414
} from '@mongodb-js/compass-components';
1515
import {
1616
createNewRelationship,
1717
deleteRelationship,
1818
selectCurrentModelFromState,
1919
selectRelationship,
20+
updateCollectionNote,
2021
} from '../../store/diagram';
2122
import type { DataModelingState } from '../../store/reducer';
2223
import { getDefaultRelationshipName } from '../../utils';
23-
import DMDrawerSection from './dm-drawer-section';
24+
import {
25+
DMDrawerSection,
26+
DMFormFieldContainer,
27+
} from './drawer-section-components';
28+
import { useChangeOnBlur } from './use-change-on-blur';
2429

2530
type CollectionDrawerContentProps = {
2631
namespace: string;
2732
relationships: Relationship[];
2833
onCreateNewRelationshipClick: (namespace: string) => void;
2934
onEditRelationshipClick: (rId: string) => void;
3035
onDeleteRelationshipClick: (rId: string) => void;
36+
note?: string;
37+
onNoteChange: (namespace: string, note: string) => void;
3138
};
3239

33-
const formFieldContainerStyles = css({
34-
marginBottom: spacing[400],
35-
marginTop: spacing[400],
36-
});
37-
3840
const titleBtnStyles = css({
3941
marginLeft: 'auto',
4042
maxHeight: 20, // To match accordion line height
@@ -76,18 +78,24 @@ const CollectionDrawerContent: React.FunctionComponent<
7678
onCreateNewRelationshipClick,
7779
onEditRelationshipClick,
7880
onDeleteRelationshipClick,
81+
note = '',
82+
onNoteChange,
7983
}) => {
84+
const noteInputProps = useChangeOnBlur(note, (newNote) => {
85+
onNoteChange(namespace, newNote);
86+
});
87+
8088
return (
8189
<>
8290
<DMDrawerSection label="Collection properties">
83-
<FormFieldContainer className={formFieldContainerStyles}>
91+
<DMFormFieldContainer>
8492
<TextInput
8593
label="Name"
8694
sizeVariant="small"
8795
value={namespace}
8896
disabled={true}
8997
/>
90-
</FormFieldContainer>
98+
</DMFormFieldContainer>
9199
</DMDrawerSection>
92100

93101
<DMDrawerSection
@@ -149,26 +157,36 @@ const CollectionDrawerContent: React.FunctionComponent<
149157
)}
150158
</div>
151159
</DMDrawerSection>
160+
161+
<DMDrawerSection label="Notes">
162+
<DMFormFieldContainer>
163+
<TextArea label="" aria-label="Notes" {...noteInputProps}></TextArea>
164+
</DMFormFieldContainer>
165+
</DMDrawerSection>
152166
</>
153167
);
154168
};
155169

156170
export default connect(
157171
(state: DataModelingState, ownProps: { namespace: string }) => {
172+
const model = selectCurrentModelFromState(state);
158173
return {
159-
relationships: selectCurrentModelFromState(state).relationships.filter(
160-
(r) => {
161-
const [local, foreign] = r.relationship;
162-
return (
163-
local.ns === ownProps.namespace || foreign.ns === ownProps.namespace
164-
);
165-
}
166-
),
174+
note:
175+
model.collections.find((collection) => {
176+
return collection.ns === ownProps.namespace;
177+
})?.note ?? '',
178+
relationships: model.relationships.filter((r) => {
179+
const [local, foreign] = r.relationship;
180+
return (
181+
local.ns === ownProps.namespace || foreign.ns === ownProps.namespace
182+
);
183+
}),
167184
};
168185
},
169186
{
170187
onCreateNewRelationshipClick: createNewRelationship,
171188
onEditRelationshipClick: selectRelationship,
172189
onDeleteRelationshipClick: deleteRelationship,
190+
onNoteChange: updateCollectionNote,
173191
}
174192
)(CollectionDrawerContent);

packages/compass-data-modeling/src/components/drawer/diagram-editor-side-panel.spec.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ describe('DiagramEditorSidePanel', function () {
6868
expect(screen.queryByTestId('data-modeling-drawer')).to.eq(null);
6969
});
7070

71-
it('should render a collection context drawer when collection is clicked', async function () {
71+
it('should render and edit a collection in collection context drawer when collection is clicked', async function () {
7272
const result = renderDrawer();
7373
result.plugin.store.dispatch(selectCollection('flights.airlines'));
7474

@@ -77,6 +77,24 @@ describe('DiagramEditorSidePanel', function () {
7777
expect(nameInput).to.be.visible;
7878
expect(nameInput).to.have.value('flights.airlines');
7979
});
80+
81+
userEvent.click(screen.getByRole('textbox', { name: 'Notes' }));
82+
userEvent.type(
83+
screen.getByRole('textbox', { name: 'Notes' }),
84+
'Note about the collection'
85+
);
86+
userEvent.tab();
87+
88+
const modifiedCollection = selectCurrentModelFromState(
89+
result.plugin.store.getState()
90+
).collections.find((coll) => {
91+
return coll.ns === 'flights.airlines';
92+
});
93+
94+
expect(modifiedCollection).to.have.property(
95+
'note',
96+
'Note about the collection'
97+
);
8098
});
8199

82100
it('should render a relationship context drawer when relations is clicked', async function () {
@@ -187,6 +205,13 @@ describe('DiagramEditorSidePanel', function () {
187205
await comboboxSelectItem('Foreign collection', 'countries');
188206
await comboboxSelectItem('Foreign field', 'iso_code');
189207

208+
userEvent.click(screen.getByRole('textbox', { name: 'Notes' }));
209+
userEvent.type(
210+
screen.getByRole('textbox', { name: 'Notes' }),
211+
'Note about the relationship'
212+
);
213+
userEvent.tab();
214+
190215
// We should be testing through rendered UI but as it's really hard to make
191216
// diagram rendering in tests property, we are just validating the final
192217
// model here
@@ -210,6 +235,11 @@ describe('DiagramEditorSidePanel', function () {
210235
cardinality: 100,
211236
},
212237
]);
238+
239+
expect(modifiedRelationship).to.have.property(
240+
'note',
241+
'Note about the relationship'
242+
);
213243
});
214244

215245
it('should delete a relationship from collection', async function () {
@@ -234,7 +264,8 @@ describe('DiagramEditorSidePanel', function () {
234264
);
235265

236266
await waitFor(() => {
237-
expect(screen.queryByText('Airport Country')).not.to.exist;
267+
expect(screen.queryByText('countries.name → airports.Country')).not.to
268+
.exist;
238269
});
239270
});
240271
});

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ function DiagramEditorSidePanel({
2222
if (selectedItems.type === 'collection') {
2323
content = (
2424
<CollectionDrawerContent
25+
key={selectedItems.id}
2526
namespace={selectedItems.id}
2627
></CollectionDrawerContent>
2728
);
2829
} else if (selectedItems.type === 'relationship') {
2930
content = (
3031
<RelationshipDrawerContent
32+
key={selectedItems.id}
3133
relationshipId={selectedItems.id}
3234
></RelationshipDrawerContent>
3335
);

packages/compass-data-modeling/src/components/drawer/dm-drawer-section.tsx renamed to packages/compass-data-modeling/src/components/drawer/drawer-section-components.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
spacing,
66
cx,
77
useDarkMode,
8+
FormFieldContainer,
89
} from '@mongodb-js/compass-components';
910
import React from 'react';
1011

@@ -25,6 +26,7 @@ const darkModeContainerStyles = css({
2526
const accordionTitleStyles = css({
2627
width: '100%',
2728
textTransform: 'uppercase',
29+
marginBottom: spacing[400],
2830
});
2931

3032
const buttonStyles = css({
@@ -33,7 +35,7 @@ const buttonStyles = css({
3335
alignItems: 'center',
3436
});
3537

36-
const DMDrawerSection: React.FC<{
38+
export const DMDrawerSection: React.FC<{
3739
label: React.ReactNode;
3840
}> = ({ label, children }) => {
3941
const darkMode = useDarkMode();
@@ -52,4 +54,25 @@ const DMDrawerSection: React.FC<{
5254
);
5355
};
5456

55-
export default DMDrawerSection;
57+
const formFieldContainerStyles = css({
58+
marginBottom: spacing[400],
59+
marginTop: spacing[400],
60+
'&:first-child': {
61+
marginTop: 0,
62+
},
63+
'&:last-child': {
64+
marginBottom: 0,
65+
},
66+
});
67+
68+
export const DMFormFieldContainer: typeof FormFieldContainer = ({
69+
className,
70+
...props
71+
}) => {
72+
return (
73+
<FormFieldContainer
74+
{...props}
75+
className={cx(formFieldContainerStyles, className)}
76+
></FormFieldContainer>
77+
);
78+
};

0 commit comments

Comments
 (0)