Skip to content

Commit a6f8780

Browse files
authored
chore(compass-crud): adjust cancel editing logic COMPASS-9564 (#7107)
1 parent f24ae53 commit a6f8780

File tree

21 files changed

+249
-199
lines changed

21 files changed

+249
-199
lines changed

packages/compass-components/src/components/document-list/document-edit-actions-footer.tsx

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useCallback, useEffect, useRef, useState } from 'react';
22
import type HadronDocument from 'hadron-document';
3-
import { Element } from 'hadron-document';
3+
import { DocumentEvents, ElementEvents } from 'hadron-document';
4+
import type { Element } from 'hadron-document';
45
import { Button } from '../leafygreen';
56
import { css } from '@leafygreen-ui/emotion';
67
import { palette } from '@leafygreen-ui/palette';
@@ -165,34 +166,40 @@ function useHadronDocumentStatus(
165166
updateStatus('DeleteError', err, errorDetails);
166167
};
167168

168-
doc.on(Element.Events.Added, onUpdate);
169-
doc.on(Element.Events.Edited, onUpdate);
170-
doc.on(Element.Events.Removed, onUpdate);
171-
doc.on(Element.Events.Reverted, onUpdate);
172-
doc.on(Element.Events.Invalid, onElementInvalid);
173-
doc.on(Element.Events.Valid, onElementValid);
174-
doc.on('update-start', onUpdateStart);
175-
doc.on('update-blocked', onUpdateBlocked);
176-
doc.on('update-success', onUpdateSuccess);
177-
doc.on('update-error', onUpdateError);
178-
doc.on('remove-start', onRemoveStart);
179-
doc.on('remove-success', onRemoveSuccess);
180-
doc.on('remove-error', onRemoveError);
169+
const onEditingFinished = () => {
170+
updateStatus('Initial');
171+
};
172+
173+
doc.on(ElementEvents.Added, onUpdate);
174+
doc.on(ElementEvents.Edited, onUpdate);
175+
doc.on(ElementEvents.Removed, onUpdate);
176+
doc.on(ElementEvents.Reverted, onUpdate);
177+
doc.on(ElementEvents.Invalid, onElementInvalid);
178+
doc.on(ElementEvents.Valid, onElementValid);
179+
doc.on(DocumentEvents.UpdateStarted, onUpdateStart);
180+
doc.on(DocumentEvents.UpdateBlocked, onUpdateBlocked);
181+
doc.on(DocumentEvents.UpdateSuccess, onUpdateSuccess);
182+
doc.on(DocumentEvents.UpdateError, onUpdateError);
183+
doc.on(DocumentEvents.RemoveStarted, onRemoveStart);
184+
doc.on(DocumentEvents.RemoveSuccess, onRemoveSuccess);
185+
doc.on(DocumentEvents.RemoveError, onRemoveError);
186+
doc.on(DocumentEvents.EditingFinished, onEditingFinished);
181187

182188
return () => {
183-
doc.on(Element.Events.Added, onUpdate);
184-
doc.off(Element.Events.Edited, onUpdate);
185-
doc.off(Element.Events.Removed, onUpdate);
186-
doc.off(Element.Events.Reverted, onUpdate);
187-
doc.off(Element.Events.Invalid, onElementInvalid);
188-
doc.off(Element.Events.Valid, onElementValid);
189-
doc.off('update-start', onUpdateStart);
190-
doc.off('update-blocked', onUpdateBlocked);
191-
doc.off('update-success', onUpdateSuccess);
192-
doc.off('update-error', onUpdateError);
193-
doc.off('remove-start', onRemoveStart);
194-
doc.off('remove-success', onRemoveSuccess);
195-
doc.off('remove-error', onRemoveError);
189+
doc.off(ElementEvents.Added, onUpdate);
190+
doc.off(ElementEvents.Edited, onUpdate);
191+
doc.off(ElementEvents.Removed, onUpdate);
192+
doc.off(ElementEvents.Reverted, onUpdate);
193+
doc.off(ElementEvents.Invalid, onElementInvalid);
194+
doc.off(ElementEvents.Valid, onElementValid);
195+
doc.off(DocumentEvents.UpdateStarted, onUpdateStart);
196+
doc.off(DocumentEvents.UpdateBlocked, onUpdateBlocked);
197+
doc.off(DocumentEvents.UpdateSuccess, onUpdateSuccess);
198+
doc.off(DocumentEvents.UpdateError, onUpdateError);
199+
doc.off(DocumentEvents.RemoveStarted, onRemoveStart);
200+
doc.off(DocumentEvents.RemoveSuccess, onRemoveSuccess);
201+
doc.off(DocumentEvents.RemoveError, onRemoveError);
202+
doc.off(DocumentEvents.EditingFinished, onEditingFinished);
196203
};
197204
}, [doc, updateStatus]);
198205

packages/compass-crud/src/components/table-view/full-width-cell-renderer.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
import type Document from 'hadron-document';
88
import type { CellEditorProps } from './cell-editor';
99
import type { GridActions } from '../../stores/grid-store';
10-
import type { Element } from 'hadron-document';
10+
import { DocumentEvents, type Element } from 'hadron-document';
1111
import type { BSONObject, CrudActions } from '../../stores/crud-store';
1212

1313
export type FullWidthCellRendererProps = Pick<
@@ -51,16 +51,22 @@ class FullWidthCellRenderer extends React.Component<
5151
* Subscribe to the update store on mount.
5252
*/
5353
componentDidMount() {
54-
this.doc.on('remove-success', this.handleRemoveSuccess);
55-
this.doc.on('update-success', this.handleUpdateSuccess);
54+
this.doc.on(DocumentEvents.RemoveSuccess, this.handleRemoveSuccess);
55+
this.doc.on(DocumentEvents.UpdateSuccess, this.handleUpdateSuccess);
5656
}
5757

5858
/**
5959
* Unsubscribe from the update store on unmount.
6060
*/
6161
componentWillUnmount() {
62-
this.doc.removeListener('remove-success', this.handleRemoveSuccess);
63-
this.doc.removeListener('update-success', this.handleUpdateSuccess);
62+
this.doc.removeListener(
63+
DocumentEvents.RemoveSuccess,
64+
this.handleRemoveSuccess
65+
);
66+
this.doc.removeListener(
67+
DocumentEvents.UpdateSuccess,
68+
this.handleUpdateSuccess
69+
);
6470
}
6571

6672
/**

packages/compass-crud/src/components/use-document-item-context-menu.spec.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('useDocumentItemContextMenu', function () {
103103
userEvent.click(screen.getByTestId('test-container'), { button: 2 });
104104

105105
// Should show "Stop editing" when editing
106-
expect(screen.getByText('Stop editing')).to.exist;
106+
expect(screen.getByText('Cancel editing')).to.exist;
107107
expect(screen.queryByText('Edit document')).to.not.exist;
108108
// But show other operations
109109
expect(screen.getByText('Expand all fields')).to.exist;
@@ -182,7 +182,7 @@ describe('useDocumentItemContextMenu', function () {
182182

183183
// Should show "Edit document" when not editing
184184
expect(screen.getByText('Edit document')).to.exist;
185-
expect(screen.queryByText('Stop editing')).to.not.exist;
185+
expect(screen.queryByText('Cancel editing')).to.not.exist;
186186

187187
// Click edit
188188
userEvent.click(screen.getByText('Edit document'), undefined, {
@@ -207,11 +207,11 @@ describe('useDocumentItemContextMenu', function () {
207207
userEvent.click(screen.getByTestId('test-container'), { button: 2 });
208208

209209
// Should show "Stop editing" when editing
210-
expect(screen.getByText('Stop editing')).to.exist;
210+
expect(screen.getByText('Cancel editing')).to.exist;
211211
expect(screen.queryByText('Edit document')).to.not.exist;
212212

213213
// Click stop editing
214-
userEvent.click(screen.getByText('Stop editing'), undefined, {
214+
userEvent.click(screen.getByText('Cancel editing'), undefined, {
215215
skipPointerEventsCheck: true,
216216
});
217217

packages/compass-crud/src/components/use-document-item-context-menu.tsx

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type HadronDocument from 'hadron-document';
2-
import { useContextMenuItems } from '@mongodb-js/compass-components';
2+
import { useContextMenuGroups } from '@mongodb-js/compass-components';
33

44
import type { DocumentProps } from './document';
55

@@ -15,57 +15,61 @@ export function useDocumentItemContextMenu({
1515
openInsertDocumentDialog,
1616
}: UseDocumentItemContextMenuProps) {
1717
const { expanded: isExpanded, editing: isEditing } = doc;
18-
return useContextMenuItems(
18+
return useContextMenuGroups(
1919
() => [
20-
{
21-
label: isExpanded ? 'Collapse all fields' : 'Expand all fields',
22-
onAction: () => {
23-
if (isExpanded) {
24-
doc.collapse();
25-
} else {
26-
doc.expand();
27-
}
28-
},
29-
},
30-
...(isEditable
31-
? [
32-
{
33-
label: isEditing ? 'Stop editing' : 'Edit document',
34-
onAction: () => {
35-
if (isEditing) {
36-
doc.finishEditing();
37-
} else {
38-
doc.startEditing();
39-
}
20+
[
21+
...(isEditable
22+
? [
23+
{
24+
label: isEditing ? 'Cancel editing' : 'Edit document',
25+
onAction: () => {
26+
if (isEditing) {
27+
doc.finishEditing();
28+
} else {
29+
doc.startEditing();
30+
}
31+
},
4032
},
41-
},
42-
]
43-
: []),
44-
{
45-
label: 'Copy document',
46-
onAction: () => {
47-
copyToClipboard?.(doc);
33+
]
34+
: []),
35+
],
36+
[
37+
{
38+
label: isExpanded ? 'Collapse all fields' : 'Expand all fields',
39+
onAction: () => {
40+
if (isExpanded) {
41+
doc.collapse();
42+
} else {
43+
doc.expand();
44+
}
45+
},
46+
},
47+
{
48+
label: 'Copy document',
49+
onAction: () => {
50+
copyToClipboard?.(doc);
51+
},
4852
},
49-
},
50-
...(isEditable
51-
? [
52-
{
53-
label: 'Clone document...',
54-
onAction: () => {
55-
const clonedDoc = doc.generateObject({
56-
excludeInternalFields: true,
57-
});
58-
void openInsertDocumentDialog?.(clonedDoc, true);
53+
...(isEditable
54+
? [
55+
{
56+
label: 'Clone document...',
57+
onAction: () => {
58+
const clonedDoc = doc.generateObject({
59+
excludeInternalFields: true,
60+
});
61+
void openInsertDocumentDialog?.(clonedDoc, true);
62+
},
5963
},
60-
},
61-
{
62-
label: 'Delete document',
63-
onAction: () => {
64-
doc.markForDeletion();
64+
{
65+
label: 'Delete document',
66+
onAction: () => {
67+
doc.markForDeletion();
68+
},
6569
},
66-
},
67-
]
68-
: []),
70+
]
71+
: []),
72+
],
6973
],
7074
[
7175
doc,

packages/compass-crud/src/stores/crud-store.spec.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ import { connect } from 'mongodb-data-service';
44
import AppRegistry, {
55
createActivateHelpers,
66
} from '@mongodb-js/compass-app-registry';
7-
import HadronDocument, { Element } from 'hadron-document';
7+
import HadronDocument, {
8+
DocumentEvents,
9+
Element,
10+
type DocumentEventsType,
11+
} from 'hadron-document';
812
import { MongoDBInstance } from 'mongodb-instance-model';
13+
import type { EventEmitter } from 'events';
914
import { once } from 'events';
1015
import sinon from 'sinon';
1116
import chai, { expect } from 'chai';
@@ -110,6 +115,15 @@ function waitForState(store, cb, timeout?: number) {
110115
return waitForStates(store, [cb], timeout);
111116
}
112117

118+
function onceDocumentEvent(
119+
doc: HadronDocument,
120+
event: DocumentEventsType
121+
): Promise<unknown[]> {
122+
// The once function was not meant for strongly typed events, so we need to
123+
// do some additional type casting.
124+
return once(doc as unknown as EventEmitter, event as string);
125+
}
126+
113127
const mockFieldStoreService = {
114128
updateFieldsFromDocuments() {},
115129
updateFieldsFromSchema() {},
@@ -503,7 +517,7 @@ describe('store', function () {
503517
});
504518

505519
it('sets the error for the document', function (done) {
506-
hadronDoc.on('remove-error', ({ message }) => {
520+
hadronDoc.on(DocumentEvents.RemoveError, ({ message }) => {
507521
expect(message).to.equal('error happened');
508522
done();
509523
});
@@ -547,11 +561,11 @@ describe('store', function () {
547561
done();
548562
}, store);
549563

550-
hadronDoc.on('update-blocked', () => {
564+
hadronDoc.on(DocumentEvents.UpdateBlocked, () => {
551565
done(new Error("Didn't expect update to be blocked."));
552566
});
553567

554-
hadronDoc.on('update-error', (errorMessage) => {
568+
hadronDoc.on(DocumentEvents.UpdateError, (errorMessage) => {
555569
done(
556570
new Error(
557571
`Didn't expect update to error. Errored with message: ${errorMessage}`
@@ -586,11 +600,11 @@ describe('store', function () {
586600
setTimeout(() => done(), 100);
587601
}, store);
588602

589-
hadronDoc.on('update-blocked', () => {
603+
hadronDoc.on(DocumentEvents.UpdateBlocked, () => {
590604
done(new Error("Didn't expect update to be blocked."));
591605
});
592606

593-
hadronDoc.on('update-error', (errorMessage) => {
607+
hadronDoc.on(DocumentEvents.UpdateError, (errorMessage) => {
594608
done(
595609
new Error(
596610
`Didn't expect update to error. Errored with message: ${errorMessage}`
@@ -613,7 +627,7 @@ describe('store', function () {
613627
});
614628

615629
it('sets the error for the document', function (done) {
616-
hadronDoc.on('update-error', ({ message }) => {
630+
hadronDoc.on(DocumentEvents.UpdateError, ({ message }) => {
617631
expect(message).to.equal(
618632
'Unable to update, no changes have been made.'
619633
);
@@ -636,7 +650,7 @@ describe('store', function () {
636650
});
637651

638652
it('sets the error for the document', function (done) {
639-
hadronDoc.on('update-error', ({ message }) => {
653+
hadronDoc.on(DocumentEvents.UpdateError, ({ message }) => {
640654
expect(message).to.equal('error happened');
641655
done();
642656
});
@@ -655,7 +669,7 @@ describe('store', function () {
655669
});
656670

657671
it('sets the update blocked for the document', function (done) {
658-
hadronDoc.on('update-blocked', () => {
672+
hadronDoc.on(DocumentEvents.UpdateBlocked, () => {
659673
done();
660674
});
661675

@@ -728,7 +742,7 @@ describe('store', function () {
728742
const invalidHadronDoc = new HadronDocument(doc);
729743
(invalidHadronDoc as any).getId = null;
730744

731-
invalidHadronDoc.on('update-error', ({ message }) => {
745+
invalidHadronDoc.on(DocumentEvents.UpdateError, ({ message }) => {
732746
expect(message).to.equal(
733747
'An error occured when attempting to update the document: this.getId is not a function'
734748
);
@@ -765,7 +779,10 @@ describe('store', function () {
765779
});
766780

767781
it('rejects the update and emits update-error', async function () {
768-
const updateErrorEvent = once(hadronDoc, 'update-error');
782+
const updateErrorEvent = onceDocumentEvent(
783+
hadronDoc,
784+
DocumentEvents.UpdateError
785+
);
769786

770787
await store.updateDocument(hadronDoc);
771788
expect((await updateErrorEvent)[0]).to.match(/Update blocked/);
@@ -998,7 +1015,7 @@ describe('store', function () {
9981015
});
9991016

10001017
it('sets the error for the document', function (done) {
1001-
hadronDoc.on('update-error', ({ message }) => {
1018+
hadronDoc.on(DocumentEvents.UpdateError, ({ message }) => {
10021019
expect(message).to.equal('error happened');
10031020
done();
10041021
});
@@ -1085,7 +1102,10 @@ describe('store', function () {
10851102
});
10861103

10871104
it('rejects the update and emits update-error', async function () {
1088-
const updateErrorEvent = once(hadronDoc, 'update-error');
1105+
const updateErrorEvent = onceDocumentEvent(
1106+
hadronDoc,
1107+
DocumentEvents.UpdateError
1108+
);
10891109

10901110
await store.replaceDocument(hadronDoc);
10911111
expect((await updateErrorEvent)[0]).to.match(/Update blocked/);

0 commit comments

Comments
 (0)