From cce62acb8ed0ecba1382c1721fdf269f68432a45 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Tue, 17 Jun 2025 13:34:56 +0200 Subject: [PATCH 01/17] extract diagram editor toolbar: --- .../src/components/diagram-editor-toolbar.tsx | 50 +++++++++++++++++++ .../src/components/diagram-editor.tsx | 46 ++--------------- 2 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx new file mode 100644 index 00000000000..cf8e7a434af --- /dev/null +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import type { DataModelingState } from '../store/reducer'; +import { redoEdit, showExportModal, undoEdit } from '../store/diagram'; +import { Icon, IconButton } from '@mongodb-js/compass-components'; + +const DiagramEditorToolbar: React.FunctionComponent<{ + step: DataModelingState['step']; + hasUndo: boolean; + hasRedo: boolean; + onUndoClick: () => void; + onRedoClick: () => void; + onExportClick: () => void; +}> = ({ step, hasUndo, onUndoClick, hasRedo, onRedoClick, onExportClick }) => { + if (step === 'NO_DIAGRAM_SELECTED') { + throw new Error('Unexpected'); + } + if (step !== 'EDITING') { + return null; + } + return ( + <> + + + + + + + + + + + ); +}; + +export default connect( + (state: DataModelingState) => { + const { diagram, step } = state; + return { + step: step, + hasUndo: (diagram?.edits.prev.length ?? 0) > 0, + hasRedo: (diagram?.edits.next.length ?? 0) > 0, + }; + }, + { + onUndoClick: undoEdit, + onRedoClick: redoEdit, + onExportClick: showExportModal, + } +)(DiagramEditorToolbar); diff --git a/packages/compass-data-modeling/src/components/diagram-editor.tsx b/packages/compass-data-modeling/src/components/diagram-editor.tsx index bddf93a84ea..5b2066d1413 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor.tsx @@ -4,14 +4,10 @@ import type { DataModelingState } from '../store/reducer'; import { applyEdit, getCurrentDiagramFromState, - redoEdit, selectCurrentModel, - undoEdit, } from '../store/diagram'; import { Banner, - Icon, - IconButton, CancelLoader, WorkspaceContainer, css, @@ -30,6 +26,8 @@ import { } from '@mongodb-js/diagramming'; import type { Edit, StaticModel } from '../services/data-model-storage'; import { UUID } from 'bson'; +import DiagramEditorToolbar from './diagram-editor-toolbar'; +import ExportDiagramModal from './export-diagram-modal'; const loadingContainerStyles = css({ width: '100%', @@ -109,10 +107,6 @@ const editorContainerPlaceholderButtonStyles = css({ const DiagramEditor: React.FunctionComponent<{ diagramLabel: string; step: DataModelingState['step']; - hasUndo: boolean; - onUndoClick: () => void; - hasRedo: boolean; - onRedoClick: () => void; model: StaticModel | null; editErrors?: string[]; onRetryClick: () => void; @@ -121,10 +115,6 @@ const DiagramEditor: React.FunctionComponent<{ }> = ({ diagramLabel, step, - hasUndo, - onUndoClick, - hasRedo, - onRedoClick, model, editErrors, onRetryClick, @@ -329,33 +319,9 @@ const DiagramEditor: React.FunctionComponent<{ } return ( - { - if (step !== 'EDITING') { - return null; - } - - return ( - <> - - - - - - - - ); - }} - > + }> {content} + ); }; @@ -365,8 +331,6 @@ export default connect( const { diagram, step } = state; return { step: step, - hasUndo: (diagram?.edits.prev.length ?? 0) > 0, - hasRedo: (diagram?.edits.next.length ?? 0) > 0, model: diagram ? selectCurrentModel(getCurrentDiagramFromState(state)) : null, @@ -375,8 +339,6 @@ export default connect( }; }, { - onUndoClick: undoEdit, - onRedoClick: redoEdit, onRetryClick: retryAnalysis, onCancelClick: cancelAnalysis, onApplyClick: applyEdit, From a43ed7ec9f4de2d185224b5d199d35cf543a937d Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Tue, 17 Jun 2025 13:36:01 +0200 Subject: [PATCH 02/17] add export modal --- .../src/components/export-diagram-modal.tsx | 151 ++++++++++++++++++ .../src/store/diagram.ts | 31 ++++ 2 files changed, 182 insertions(+) create mode 100644 packages/compass-data-modeling/src/components/export-diagram-modal.tsx diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx new file mode 100644 index 00000000000..db8d9ae89df --- /dev/null +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -0,0 +1,151 @@ +import React, { useCallback } from 'react'; +import { + Button, + css, + Icon, + Label, + Link, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + Radio, + RadioGroup, + spacing, + SpinLoader, +} from '@mongodb-js/compass-components'; +import { + closeExportModal, + selectCurrentModel, + getCurrentDiagramFromState, +} from '../store/diagram'; +import { connect } from 'react-redux'; +import type { DataModelingState } from '../store/reducer'; +import type { StaticModel } from '../services/data-model-storage'; + +const nbsp = '\u00a0'; + +const modelBodyStyles = css({ + paddingTop: spacing[600], +}); + +const exportFormatContainerStyles = css({ + display: 'flex', + flexDirection: 'column', + gap: spacing[300], +}); + +const radioGroupStyles = css({ + display: 'flex', + flexDirection: 'column', + gap: spacing[300], +}); + +const footerStyles = css({ + display: 'flex', + gap: spacing[200], +}); + +type ExportDiagramModalProps = { + isModalOpen: boolean; + diagramLabel: string; + model: StaticModel; + onCloseClick: () => void; +}; + +const ExportDiagramModal = ({ + isModalOpen, + diagramLabel, + model, + onCloseClick, +}: ExportDiagramModalProps) => { + const [exportFormat, setExportFormat] = React.useState<'json'>('json'); + const [isExporting, setIsExporting] = React.useState(false); + + const onExport = useCallback(() => { + if (!exportFormat) { + return; + } + setIsExporting(true); + // TODO: export + console.log( + `Exporting diagram "${diagramLabel}" in ${exportFormat} format...`, + model + ); + setIsExporting(false); + }, [exportFormat, model, diagramLabel]); + + return ( + {}}> + + Export the data modal to JSON Schema format. + {nbsp} + + Learn more + + + } + /> + +
+ + setExportFormat(e.target.value as 'json')} + > + + + {nbsp} + JSON Schema + + +
+
+ + + + +
+ ); +}; + +export default connect( + (state: DataModelingState) => { + const { diagram } = state; + if (!diagram) { + throw new Error('No exportable diagram found in state'); + } + const model = selectCurrentModel(getCurrentDiagramFromState(state)); + return { + model, + diagramLabel: diagram.name, + isModalOpen: Boolean(diagram?.isExportModalOpen), + }; + }, + { + onCloseClick: closeExportModal, + } +)(ExportDiagramModal); diff --git a/packages/compass-data-modeling/src/store/diagram.ts b/packages/compass-data-modeling/src/store/diagram.ts index d2846b5776c..86abc33022c 100644 --- a/packages/compass-data-modeling/src/store/diagram.ts +++ b/packages/compass-data-modeling/src/store/diagram.ts @@ -24,6 +24,7 @@ export type DiagramState = next: Edit[][]; }; editErrors?: string[]; + isExportModalOpen?: boolean; }) | null; // null when no diagram is currently open @@ -35,6 +36,8 @@ export enum DiagramActionTypes { APPLY_EDIT_FAILED = 'data-modeling/diagram/APPLY_EDIT_FAILED', UNDO_EDIT = 'data-modeling/diagram/UNDO_EDIT', REDO_EDIT = 'data-modeling/diagram/REDO_EDIT', + EXPORT_MODAL_OPENED = 'data-modeling/diagram/EXPORT_MODAL_OPENED', + EXPORT_MODAL_CLOSED = 'data-modeling/diagram/EXPORT_MODAL_CLOSED', } export type OpenDiagramAction = { @@ -71,6 +74,14 @@ export type RedoEditAction = { type: DiagramActionTypes.REDO_EDIT; }; +type ExportModalOpenedAction = { + type: DiagramActionTypes.EXPORT_MODAL_OPENED; +}; + +type ExportModalClosedAction = { + type: DiagramActionTypes.EXPORT_MODAL_CLOSED; +}; + export type DiagramActions = | OpenDiagramAction | DeleteDiagramAction @@ -190,6 +201,18 @@ export const diagramReducer: Reducer = ( updatedAt: new Date().toISOString(), }; } + if (isAction(action, DiagramActionTypes.EXPORT_MODAL_OPENED)) { + return { + ...state, + isExportModalOpen: true, + }; + } + if (isAction(action, DiagramActionTypes.EXPORT_MODAL_CLOSED)) { + return { + ...state, + isExportModalOpen: false, + }; + } return state; }; @@ -358,4 +381,12 @@ export function getCurrentDiagramFromState( return { id, connectionId, name, edits, createdAt, updatedAt }; } +export function showExportModal(): ExportModalOpenedAction { + return { type: DiagramActionTypes.EXPORT_MODAL_OPENED }; +} + +export function closeExportModal(): ExportModalClosedAction { + return { type: DiagramActionTypes.EXPORT_MODAL_CLOSED }; +} + export const selectCurrentModel = memoize(getCurrentModel); From 39793bd0fb9e476595c77cb1b85cdd7d6c71efe6 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 07:44:42 +0200 Subject: [PATCH 03/17] json export --- .../src/components/export-diagram-modal.tsx | 32 +++++++----------- .../src/services/export-diagram.ts | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 packages/compass-data-modeling/src/services/export-diagram.ts diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index db8d9ae89df..c8b879348bf 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useState } from 'react'; import { Button, css, @@ -12,7 +12,6 @@ import { Radio, RadioGroup, spacing, - SpinLoader, } from '@mongodb-js/compass-components'; import { closeExportModal, @@ -22,6 +21,7 @@ import { import { connect } from 'react-redux'; import type { DataModelingState } from '../store/reducer'; import type { StaticModel } from '../services/data-model-storage'; +import { exportToJson } from '../services/export-diagram'; const nbsp = '\u00a0'; @@ -49,7 +49,7 @@ const footerStyles = css({ type ExportDiagramModalProps = { isModalOpen: boolean; diagramLabel: string; - model: StaticModel; + model: StaticModel | null; onCloseClick: () => void; }; @@ -59,24 +59,17 @@ const ExportDiagramModal = ({ model, onCloseClick, }: ExportDiagramModalProps) => { - const [exportFormat, setExportFormat] = React.useState<'json'>('json'); - const [isExporting, setIsExporting] = React.useState(false); + const [exportFormat, setExportFormat] = useState<'json' | null>(null); const onExport = useCallback(() => { - if (!exportFormat) { + if (!exportFormat || !model) { return; } - setIsExporting(true); - // TODO: export - console.log( - `Exporting diagram "${diagramLabel}" in ${exportFormat} format...`, - model - ); - setIsExporting(false); + exportToJson(diagramLabel, model); }, [exportFormat, model, diagramLabel]); return ( - {}}> + void onExport()} data-testid="export-button" - isLoading={isExporting} - loadingIndicator={} > Export @@ -135,13 +126,12 @@ const ExportDiagramModal = ({ export default connect( (state: DataModelingState) => { const { diagram } = state; - if (!diagram) { - throw new Error('No exportable diagram found in state'); - } - const model = selectCurrentModel(getCurrentDiagramFromState(state)); + const model = diagram + ? selectCurrentModel(getCurrentDiagramFromState(state)) + : null; return { model, - diagramLabel: diagram.name, + diagramLabel: diagram?.name ?? 'Schema Preview', isModalOpen: Boolean(diagram?.isExportModalOpen), }; }, diff --git a/packages/compass-data-modeling/src/services/export-diagram.ts b/packages/compass-data-modeling/src/services/export-diagram.ts new file mode 100644 index 00000000000..107bbe0bc71 --- /dev/null +++ b/packages/compass-data-modeling/src/services/export-diagram.ts @@ -0,0 +1,33 @@ +import type { StaticModel } from './data-model-storage'; + +export function exportToJson(fileName: string, model: StaticModel) { + const json = getExportJsonFromModel(model); + const blob = new Blob([JSON.stringify(json, null, 2)], { + type: 'application/json', + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = fileName; + link.click(); + setTimeout(() => { + window.URL.revokeObjectURL(url); + link.remove(); + }, 0); +} + +export function getExportJsonFromModel({ + collections, + relationships, +}: StaticModel) { + return { + collections: Object.fromEntries( + collections.map((collection) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { displayPosition, indexes, ...restOfTheCollection } = collection; + return [collection.ns, restOfTheCollection]; + }) + ), + relationships, + }; +} From e47687e7bb31bd0da67b0cd528c67e311524508a Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 09:49:01 +0200 Subject: [PATCH 04/17] tests --- .../diagram-editor-toolbar.spec.tsx | 75 ++++ .../src/components/diagram-editor-toolbar.tsx | 6 +- .../src/components/export-diagram-modal.tsx | 2 +- .../src/services/export-diagram.spec.ts | 22 ++ .../test/fixtures/flights-model.json | 323 ++++++++++++++++++ 5 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx create mode 100644 packages/compass-data-modeling/src/services/export-diagram.spec.ts create mode 100644 packages/compass-data-modeling/test/fixtures/flights-model.json diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx new file mode 100644 index 00000000000..ffb6fc26331 --- /dev/null +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { expect } from 'chai'; +import { render, screen, userEvent } from '@mongodb-js/testing-library-compass'; +import { DiagramEditorToolbar } from './diagram-editor-toolbar'; +import sinon from 'sinon'; + +function renderDiagramEditorToolbar( + props: Partial> = {} +) { + render( + {}} + onRedoClick={() => {}} + onExportClick={() => {}} + {...props} + /> + ); +} + +describe('DiagramEditorToolbar', function () { + it('throws if step is NO_DIAGRAM_SELECTED', function () { + expect(() => { + renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); + }).to.throw('Unexpected'); + }); + + it('renders nothing if step is not EDITING', function () { + renderDiagramEditorToolbar({ step: 'ANALYSIS_CANCELED' }); + expect(() => screen.getByTestId('diagram-editor-toolbar')).to.throw; + }); + + context('undo button', function () { + it('renders it disabled if hasUndo is false', function () { + renderDiagramEditorToolbar({ hasUndo: false }); + const undoButton = screen.getByRole('button', { name: 'Undo' }); + expect(undoButton).to.have.attribute('aria-disabled', 'true'); + }); + it('renders it enabled if hasUndo is true and calls onUndoClick', function () { + const undoSpy = sinon.spy(); + renderDiagramEditorToolbar({ hasUndo: true, onUndoClick: undoSpy }); + const undoButton = screen.getByRole('button', { name: 'Undo' }); + expect(undoButton).to.have.attribute('aria-disabled', 'false'); + userEvent.click(undoButton); + expect(undoSpy).to.have.been.calledOnce; + }); + }); + + context('redo button', function () { + it('renders it disabled if hasRedo is false', function () { + renderDiagramEditorToolbar({ hasRedo: false }); + const redoButton = screen.getByRole('button', { name: 'Redo' }); + expect(redoButton).to.have.attribute('aria-disabled', 'true'); + }); + it('renders it enabled if hasRedo is true and calls onRedoClick', function () { + const redoSpy = sinon.spy(); + renderDiagramEditorToolbar({ hasRedo: true, onRedoClick: redoSpy }); + const redoButton = screen.getByRole('button', { name: 'Redo' }); + expect(redoButton).to.have.attribute('aria-disabled', 'false'); + userEvent.click(redoButton); + expect(redoSpy).to.have.been.calledOnce; + }); + }); + + it('renders export buttona and calls onExportClick', function () { + const exportSpy = sinon.spy(); + renderDiagramEditorToolbar({ onExportClick: exportSpy }); + const exportButton = screen.getByRole('button', { name: 'Export' }); + expect(exportButton).to.exist; + userEvent.click(exportButton); + expect(exportSpy).to.have.been.calledOnce; + }); +}); diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx index cf8e7a434af..87b3463d25c 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx @@ -4,7 +4,7 @@ import type { DataModelingState } from '../store/reducer'; import { redoEdit, showExportModal, undoEdit } from '../store/diagram'; import { Icon, IconButton } from '@mongodb-js/compass-components'; -const DiagramEditorToolbar: React.FunctionComponent<{ +export const DiagramEditorToolbar: React.FunctionComponent<{ step: DataModelingState['step']; hasUndo: boolean; hasRedo: boolean; @@ -19,7 +19,7 @@ const DiagramEditorToolbar: React.FunctionComponent<{ return null; } return ( - <> +
@@ -29,7 +29,7 @@ const DiagramEditorToolbar: React.FunctionComponent<{ - +
); }; diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index c8b879348bf..da2547874d8 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -74,7 +74,7 @@ const ExportDiagramModal = ({ title="Export data model" subtitle={
- Export the data modal to JSON Schema format. + Export the data modal to JSON format. {nbsp} [rest.ns, rest]) + ); + expect(json.collections).to.deep.equal(expectedCollections); + + expect(json.relationships.length).to.equal( + FlightModel.relationships.length + ); + }); + }); +}); diff --git a/packages/compass-data-modeling/test/fixtures/flights-model.json b/packages/compass-data-modeling/test/fixtures/flights-model.json new file mode 100644 index 00000000000..13fc64f3de8 --- /dev/null +++ b/packages/compass-data-modeling/test/fixtures/flights-model.json @@ -0,0 +1,323 @@ +{ + "collections": [ + { + "ns": "flights.airlines", + "jsonSchema": { + "bsonType": "object", + "required": [ + "_id", + "active", + "airline", + "alias", + "base", + "country", + "iata", + "icao", + "name" + ], + "properties": { + "_id": { + "bsonType": "objectId" + }, + "active": { + "bsonType": "string" + }, + "airline": { + "bsonType": "int" + }, + "alias": { + "bsonType": ["string", "int"] + }, + "alliance": { + "bsonType": "string" + }, + "base": { + "bsonType": "string" + }, + "country": { + "bsonType": "string" + }, + "iata": { + "bsonType": "string" + }, + "icao": { + "bsonType": "string" + }, + "name": { + "bsonType": "string" + } + } + }, + "indexes": [], + "displayPosition": [144.04516098441445, 226.78180342288712] + }, + { + "ns": "flights.airports", + "jsonSchema": { + "bsonType": "object", + "required": [ + "_id", + "Altitude", + "Country", + "IATA", + "ICAO", + "Latitude", + "Longitude", + "Name" + ], + "properties": { + "_id": { + "bsonType": "int" + }, + "Altitude": { + "bsonType": "int" + }, + "City": { + "bsonType": "string" + }, + "Country": { + "bsonType": "string" + }, + "IATA": { + "bsonType": "string" + }, + "ICAO": { + "bsonType": "string" + }, + "Latitude": { + "bsonType": "double" + }, + "Longitude": { + "bsonType": "double" + }, + "Name": { + "bsonType": "string" + } + } + }, + "indexes": [], + "displayPosition": [157.74741328703078, 614.6105002761217] + }, + { + "ns": "flights.airports_coordinates_for_schema", + "jsonSchema": { + "bsonType": "object", + "required": ["_id", "coordinates", "Country", "Name"], + "properties": { + "_id": { + "bsonType": "int" + }, + "coordinates": { + "bsonType": "array", + "items": { + "bsonType": "double" + } + }, + "Country": { + "bsonType": "string" + }, + "Name": { + "bsonType": "string" + } + } + }, + "indexes": [], + "displayPosition": [611.3592580503537, 238.3680626820135] + }, + { + "ns": "flights.countries", + "jsonSchema": { + "bsonType": "object", + "required": ["_id", "iso_code", "name"], + "properties": { + "_id": { + "bsonType": "objectId" + }, + "dafif_code": { + "bsonType": "string" + }, + "iso_code": { + "bsonType": "string" + }, + "name": { + "bsonType": "string" + } + } + }, + "indexes": [], + "displayPosition": [156.9088146439409, 808.1350158017262] + }, + { + "ns": "flights.planes", + "jsonSchema": { + "bsonType": "object", + "required": ["_id", "IATA", "ICAO", "name"], + "properties": { + "_id": { + "bsonType": "objectId" + }, + "IATA": { + "bsonType": "string" + }, + "ICAO": { + "bsonType": "string" + }, + "name": { + "bsonType": "string" + } + } + }, + "indexes": [], + "displayPosition": [479.9432289278143, 650.1759375929954] + }, + { + "ns": "flights.routes", + "jsonSchema": { + "bsonType": "object", + "required": [ + "_id", + "airline", + "airline_id", + "destination_airport", + "destination_airport_id", + "equipment", + "source_airport", + "source_airport_id", + "stops" + ], + "properties": { + "_id": { + "bsonType": "objectId" + }, + "airline": { + "bsonType": "string" + }, + "airline_id": { + "bsonType": "string" + }, + "codeshare": { + "bsonType": "string" + }, + "destination_airport": { + "bsonType": "string" + }, + "destination_airport_id": { + "bsonType": "string" + }, + "equipment": { + "bsonType": "string" + }, + "source_airport": { + "bsonType": "string" + }, + "source_airport_id": { + "bsonType": "string" + }, + "stops": { + "bsonType": "int" + } + } + }, + "indexes": [], + "displayPosition": [853.3477815091105, 168.4596944341812] + } + ], + "relationships": [ + { + "id": "6f776467-4c98-476b-9b71-1f8a724e6c2c", + "relationship": [ + { + "ns": "flights.airlines", + "cardinality": 1, + "fields": ["country"] + }, + { + "ns": "flights.countries", + "cardinality": 1, + "fields": ["name"] + } + ], + "isInferred": false + }, + { + "id": "204b1fc0-601f-4d62-bba3-38fade71e049", + "relationship": [ + { + "ns": "flights.countries", + "cardinality": 1, + "fields": ["name"] + }, + { + "ns": "flights.airports", + "cardinality": 1, + "fields": ["Country"] + } + ], + "isInferred": false + }, + { + "id": "b04ae9eb-aecf-4273-b38c-97c1b7569769", + "relationship": [ + { + "ns": "flights.airlines", + "cardinality": 1, + "fields": ["iata", "icao"] + }, + { + "ns": "flights.planes", + "cardinality": 1, + "fields": ["IATA", "ICAO"] + } + ], + "isInferred": false + }, + { + "id": "1913d93f-6751-453c-abf1-5df7f37fe7eb", + "relationship": [ + { + "ns": "flights.airports", + "cardinality": 1, + "fields": ["Name"] + }, + { + "ns": "flights.airports_coordinates", + "cardinality": 1, + "fields": ["Name"] + } + ], + "isInferred": false + }, + { + "id": "1913d93f-6751-453c-abf1-5df7f37fe7eb", + "relationship": [ + { + "ns": "flights.airports", + "cardinality": 1, + "fields": ["Name"] + }, + { + "ns": "flights.airports_coordinates", + "cardinality": 1, + "fields": ["Name"] + } + ], + "isInferred": false + }, + { + "id": "1913d93f-6751-453c-abf1-5df7f37fe7eb", + "relationship": [ + { + "ns": "flights.airports", + "cardinality": 1, + "fields": ["Name"] + }, + { + "ns": "flights.airports_coordinates_for_schema", + "cardinality": 1, + "fields": ["Name"] + } + ], + "isInferred": false + } + ] +} From dbc1ca0eff6282689e4798a5d6b72981f09a14c3 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 10:02:58 +0200 Subject: [PATCH 05/17] close modal --- .../src/components/export-diagram-modal.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index da2547874d8..c663586b29a 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -66,7 +66,8 @@ const ExportDiagramModal = ({ return; } exportToJson(diagramLabel, model); - }, [exportFormat, model, diagramLabel]); + onCloseClick(); + }, [exportFormat, onCloseClick, model, diagramLabel]); return ( From 087936c75a50ea9a361ec0550d7ac6dc3dbbca57 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 12:29:23 +0200 Subject: [PATCH 06/17] tests --- .../src/components/export-diagram-modal.tsx | 11 +- .../src/services/export-diagram.spec.ts | 2 +- .../compass-e2e-tests/helpers/selectors.ts | 5 + .../tests/data-modeling-tab.test.ts | 167 ++++++++++++++---- 4 files changed, 147 insertions(+), 38 deletions(-) diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index c663586b29a..c679f87b62d 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -70,7 +70,11 @@ const ExportDiagramModal = ({ }, [exportFormat, onCloseClick, model, diagramLabel]); return ( - + setExportFormat(e.target.value as 'json')} > - + {nbsp} - JSON Schema + JSON
diff --git a/packages/compass-data-modeling/src/services/export-diagram.spec.ts b/packages/compass-data-modeling/src/services/export-diagram.spec.ts index fe9ea3328c8..2e4be35e2b5 100644 --- a/packages/compass-data-modeling/src/services/export-diagram.spec.ts +++ b/packages/compass-data-modeling/src/services/export-diagram.spec.ts @@ -5,7 +5,7 @@ import FlightModel from '../../test/fixtures/flights-model.json'; describe('export-diagram', function () { context('json export', function () { it('should convert a model to JSON', function () { - const json = getExportJsonFromModel(FlightModel); + const json = getExportJsonFromModel(FlightModel as any); const expectedCollections = Object.fromEntries( FlightModel.collections diff --git a/packages/compass-e2e-tests/helpers/selectors.ts b/packages/compass-e2e-tests/helpers/selectors.ts index 0f66ed83304..2a4e6050760 100644 --- a/packages/compass-e2e-tests/helpers/selectors.ts +++ b/packages/compass-e2e-tests/helpers/selectors.ts @@ -1446,6 +1446,11 @@ export const DataModelApplyEditor = `${DataModelEditor} [data-testid="apply-edit export const DataModelEditorApplyButton = `${DataModelApplyEditor} [data-testid="apply-button"]`; export const DataModelUndoButton = 'button[aria-label="Undo"]'; export const DataModelRedoButton = 'button[aria-label="Redo"]'; +export const DataModelExportButton = 'button[aria-label="Export"]'; +export const DataModelExportModal = '[data-testid="export-diagram-modal"]'; +export const DataModelExportJsonOption = `${DataModelExportModal} input[aria-label="JSON"]`; +export const DataModelExportModalConfirmButton = + '[data-testid="export-button"]'; export const DataModelsListItem = (diagramName: string) => `[data-testid="saved-diagram-card"][data-diagram-name="${diagramName}"]`; export const DataModelsListItemActions = (diagramName: string) => diff --git a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts index 5789ca11e1e..f8ca8597322 100644 --- a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts +++ b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts @@ -9,9 +9,14 @@ import { import type { Compass } from '../helpers/compass'; import * as Selectors from '../helpers/selectors'; import { - createNestedDocumentsCollection, createNumbersCollection, + createNumbersStringCollection, } from '../helpers/insert-data'; +import { + cleanUpDownloadedFile, + waitForFileDownload, +} from '../helpers/downloads'; +import { readFileSync } from 'fs'; type DiagramInstance = { getNodes: () => Array<{ @@ -19,6 +24,49 @@ type DiagramInstance = { }>; }; +async function setupDiagram( + browser: CompassBrowser, + options: { + diagramName: string; + connectionName: string; + databaseName: string; + } +) { + await browser.navigateToDataModeling(); + + // Click on create new data model button + await browser.clickVisible(Selectors.CreateNewDataModelButton); + + // Fill in model details + await browser.setValueVisible( + Selectors.CreateDataModelNameInput, + options.diagramName + ); + await browser.clickVisible(Selectors.CreateDataModelConfirmButton); + + // Select existing connection + await browser.selectOption( + Selectors.CreateDataModelConnectionSelector, + options.connectionName + ); + await browser.clickVisible(Selectors.CreateDataModelConfirmButton); + + // Select a database + await browser.selectOption( + Selectors.CreateDataModelDatabaseSelector, + options.databaseName + ); + await browser.clickVisible(Selectors.CreateDataModelConfirmButton); + + // TODO: Confirm all collections are selected by default (COMPASS-9309) + // Note: We'll need to change the UI, right now the labels are disconnected from the checkboxes + await browser.clickVisible(Selectors.CreateDataModelConfirmButton); + + // Wait for the diagram editor to load + const dataModelEditor = browser.$(Selectors.DataModelEditor); + await dataModelEditor.waitForDisplayed(); +} + async function getDiagramNodes(browser: CompassBrowser): Promise { const nodes = await browser.execute(function (selector) { const node = document.querySelector(selector); @@ -35,16 +83,20 @@ async function getDiagramNodes(browser: CompassBrowser): Promise { describe('Data Modeling tab', function () { let compass: Compass; let browser: CompassBrowser; + let exportFileName: string; before(async function () { compass = await init(this.test?.fullTitle()); browser = compass.browser; await browser.setupDefaultConnections(); await browser.setFeature('enableDataModeling', true); + if (exportFileName) { + cleanUpDownloadedFile(exportFileName); + } }); beforeEach(async function () { - await createNestedDocumentsCollection('testCollection1'); + await createNumbersStringCollection('testCollection1'); await createNumbersCollection('testCollection2'); await browser.disconnectAll(); await browser.connectToDefaults(); @@ -58,43 +110,20 @@ describe('Data Modeling tab', function () { afterEach(async function () { await screenshotIfFailed(compass, this.currentTest); + if (exportFileName) { + cleanUpDownloadedFile(exportFileName); + } }); it('creates a new data model using an existing connection', async function () { - await browser.navigateToDataModeling(); - - // Click on create new data model button - await browser.clickVisible(Selectors.CreateNewDataModelButton); - - // Fill in model details const dataModelName = 'Test Data Model'; - await browser.setValueVisible( - Selectors.CreateDataModelNameInput, - dataModelName - ); - await browser.clickVisible(Selectors.CreateDataModelConfirmButton); + await setupDiagram(browser, { + diagramName: dataModelName, + connectionName: DEFAULT_CONNECTION_NAME_1, + databaseName: 'test', + }); - // Select existing connection - await browser.selectOption( - Selectors.CreateDataModelConnectionSelector, - DEFAULT_CONNECTION_NAME_1 - ); - await browser.clickVisible(Selectors.CreateDataModelConfirmButton); - - // Select a database - await browser.selectOption( - Selectors.CreateDataModelDatabaseSelector, - 'test' - ); - await browser.clickVisible(Selectors.CreateDataModelConfirmButton); - - // TODO: Confirm all collections are selected by default (COMPASS-9309) - // Note: We'll need to change the UI, right now the labels are disconnected from the checkboxes - await browser.clickVisible(Selectors.CreateDataModelConfirmButton); - - // Wait for the diagram editor to load const dataModelEditor = browser.$(Selectors.DataModelEditor); - await dataModelEditor.waitForDisplayed(); let nodes = await getDiagramNodes(browser); expect(nodes).to.have.lengthOf(2); @@ -163,4 +192,76 @@ describe('Data Modeling tab', function () { .$(Selectors.DataModelsListItem(dataModelName)) .waitForDisplayed({ reverse: true }); }); + + it('exports the data model to JSON', async function () { + const dataModelName = 'Test Export Model'; + exportFileName = `${dataModelName}.json`; + await setupDiagram(browser, { + diagramName: dataModelName, + connectionName: DEFAULT_CONNECTION_NAME_1, + databaseName: 'test', + }); + + await browser.clickVisible(Selectors.DataModelExportButton); + const exportModal = browser.$(Selectors.DataModelExportModal); + await exportModal.waitForDisplayed(); + + await browser.clickParent(Selectors.DataModelExportJsonOption); + await browser.clickVisible(Selectors.DataModelExportModalConfirmButton); + + const { fileExists, filePath } = await waitForFileDownload( + exportFileName, + browser + ); + expect(fileExists).to.be.true; + + const content = readFileSync(filePath, 'utf-8'); + const model = JSON.parse(content); + + // Within beforeEach hook, we create these two collections + expect(model).to.deep.equal({ + collections: { + 'test.testCollection1': { + ns: 'test.testCollection1', + jsonSchema: { + bsonType: 'object', + required: ['_id', 'i', 'iString', 'j'], + properties: { + _id: { + bsonType: 'objectId', + }, + i: { + bsonType: 'int', + }, + iString: { + bsonType: 'string', + }, + j: { + bsonType: 'int', + }, + }, + }, + }, + 'test.testCollection2': { + ns: 'test.testCollection2', + jsonSchema: { + bsonType: 'object', + required: ['_id', 'i', 'j'], + properties: { + _id: { + bsonType: 'objectId', + }, + i: { + bsonType: 'int', + }, + j: { + bsonType: 'int', + }, + }, + }, + }, + }, + relationships: [], + }); + }); }); From 6c21b63cb4e9b2170374ac7accb88b1d002edc9c Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 12:41:07 +0200 Subject: [PATCH 07/17] ensure test run --- packages/compass-e2e-tests/tests/data-modeling-tab.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts index f8ca8597322..210120eb35c 100644 --- a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts +++ b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts @@ -88,14 +88,14 @@ describe('Data Modeling tab', function () { before(async function () { compass = await init(this.test?.fullTitle()); browser = compass.browser; + }); + + beforeEach(async function () { await browser.setupDefaultConnections(); await browser.setFeature('enableDataModeling', true); if (exportFileName) { cleanUpDownloadedFile(exportFileName); } - }); - - beforeEach(async function () { await createNumbersStringCollection('testCollection1'); await createNumbersCollection('testCollection2'); await browser.disconnectAll(); From b7d8dcfb90120407e9ee07d75b72a126c84a7c05 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 12:50:49 +0200 Subject: [PATCH 08/17] fix toast --- packages/compass-components/src/components/toast-body.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compass-components/src/components/toast-body.tsx b/packages/compass-components/src/components/toast-body.tsx index e5c6b6c3b7e..4db9514e306 100644 --- a/packages/compass-components/src/components/toast-body.tsx +++ b/packages/compass-components/src/components/toast-body.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link } from './leafygreen'; +import { Link, Body } from './leafygreen'; import { css } from '@leafygreen-ui/emotion'; const toastBodyFlexStyles = css({ @@ -34,7 +34,7 @@ export function ToastBody({ }) { return (
-

{statusMessage}

+ {statusMessage} {!!actionHandler && ( Date: Fri, 20 Jun 2025 12:54:43 +0200 Subject: [PATCH 09/17] fix electron test --- .../src/components/diagram-editor-toolbar.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx index ffb6fc26331..441331c421d 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx @@ -24,7 +24,7 @@ describe('DiagramEditorToolbar', function () { it('throws if step is NO_DIAGRAM_SELECTED', function () { expect(() => { renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); - }).to.throw('Unexpected'); + }).to.throw; }); it('renders nothing if step is not EDITING', function () { From f9bcc51b35d2eb858a0e1bf9c5c00e60d3a87ebe Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Fri, 20 Jun 2025 16:36:12 +0200 Subject: [PATCH 10/17] fix link --- .../src/components/export-diagram-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index c679f87b62d..66df6c01715 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -82,7 +82,7 @@ const ExportDiagramModal = ({ Export the data modal to JSON format. {nbsp} From b65f4c842582b7fa6ec1ecde895959cbc818d84f Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Mon, 23 Jun 2025 11:49:24 +0200 Subject: [PATCH 11/17] ensure its thrown --- .../src/components/diagram-editor-toolbar.spec.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx index 441331c421d..10039ae3a07 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx @@ -24,12 +24,12 @@ describe('DiagramEditorToolbar', function () { it('throws if step is NO_DIAGRAM_SELECTED', function () { expect(() => { renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); - }).to.throw; + }).to.throw(); }); it('renders nothing if step is not EDITING', function () { renderDiagramEditorToolbar({ step: 'ANALYSIS_CANCELED' }); - expect(() => screen.getByTestId('diagram-editor-toolbar')).to.throw; + expect(() => screen.getByTestId('diagram-editor-toolbar')).to.throw(); }); context('undo button', function () { From adc19a15e756e972ffd455cc24f1c97e6d499db6 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Mon, 23 Jun 2025 12:04:32 +0200 Subject: [PATCH 12/17] asset number of selected collections --- packages/compass-e2e-tests/tests/data-modeling-tab.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts index 210120eb35c..f28ee0cc1ff 100644 --- a/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts +++ b/packages/compass-e2e-tests/tests/data-modeling-tab.test.ts @@ -58,8 +58,11 @@ async function setupDiagram( ); await browser.clickVisible(Selectors.CreateDataModelConfirmButton); - // TODO: Confirm all collections are selected by default (COMPASS-9309) - // Note: We'll need to change the UI, right now the labels are disconnected from the checkboxes + // Ensure that all the collections are selected by default + const text = await browser.$(Selectors.CreateDataModelModal).getText(); + // 2 is based on the collections we create in beforeEach hook + expect(text).to.contain('2/2 total collections selected.'); + await browser.clickVisible(Selectors.CreateDataModelConfirmButton); // Wait for the diagram editor to load From 6c41226177f9b389e61b89ab451690c58647f8a3 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Mon, 23 Jun 2025 13:39:57 +0200 Subject: [PATCH 13/17] fix modal styles --- .../src/components/export-diagram-modal.tsx | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx index 66df6c01715..91bde0a96a7 100644 --- a/packages/compass-data-modeling/src/components/export-diagram-modal.tsx +++ b/packages/compass-data-modeling/src/components/export-diagram-modal.tsx @@ -29,16 +29,16 @@ const modelBodyStyles = css({ paddingTop: spacing[600], }); -const exportFormatContainerStyles = css({ +const contentContainerStyles = css({ display: 'flex', flexDirection: 'column', gap: spacing[300], }); -const radioGroupStyles = css({ +const radioItemStyles = css({ display: 'flex', - flexDirection: 'column', - gap: spacing[300], + alignItems: 'center', + gap: spacing[200], }); const footerStyles = css({ @@ -92,18 +92,20 @@ const ExportDiagramModal = ({ } /> -
+
- setExportFormat(e.target.value as 'json')} - > - + +
- {nbsp} - JSON - + setExportFormat('json')} + > + JSON + +
From 7fa048044c8eb9c62e6f178e0277461b8c5d6350 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Tue, 24 Jun 2025 10:55:10 +0200 Subject: [PATCH 14/17] return null for tests --- .../src/components/diagram-editor-toolbar.spec.tsx | 10 ++++++---- .../src/components/diagram-editor-toolbar.tsx | 5 +---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx index 10039ae3a07..75b4a115529 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx @@ -21,10 +21,12 @@ function renderDiagramEditorToolbar( } describe('DiagramEditorToolbar', function () { - it('throws if step is NO_DIAGRAM_SELECTED', function () { - expect(() => { - renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); - }).to.throw(); + it('renders nothing if step is NO_DIAGRAM_SELECTED', function () { + // We should be technically throwing when step is NO_DIAGRAM_SELECTED, + // but the test fails on electron when asserting that. So we are + // returning null for NO_DIAGRAM_SELECTED step and testing it. + renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); + expect(() => screen.getByTestId('diagram-editor-toolbar')).to.throw(); }); it('renders nothing if step is not EDITING', function () { diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx index 87b3463d25c..ce74d4549f9 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx @@ -12,10 +12,7 @@ export const DiagramEditorToolbar: React.FunctionComponent<{ onRedoClick: () => void; onExportClick: () => void; }> = ({ step, hasUndo, onUndoClick, hasRedo, onRedoClick, onExportClick }) => { - if (step === 'NO_DIAGRAM_SELECTED') { - throw new Error('Unexpected'); - } - if (step !== 'EDITING') { + if (step === 'NO_DIAGRAM_SELECTED' || step !== 'EDITING') { return null; } return ( From ffef0b7fa601146b2139955f9f8087bb11e6be6b Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Tue, 24 Jun 2025 11:02:44 +0200 Subject: [PATCH 15/17] remove comment --- .../src/components/diagram-editor-toolbar.spec.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx index 75b4a115529..4f763944145 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.spec.tsx @@ -22,9 +22,6 @@ function renderDiagramEditorToolbar( describe('DiagramEditorToolbar', function () { it('renders nothing if step is NO_DIAGRAM_SELECTED', function () { - // We should be technically throwing when step is NO_DIAGRAM_SELECTED, - // but the test fails on electron when asserting that. So we are - // returning null for NO_DIAGRAM_SELECTED step and testing it. renderDiagramEditorToolbar({ step: 'NO_DIAGRAM_SELECTED' }); expect(() => screen.getByTestId('diagram-editor-toolbar')).to.throw(); }); From 467dbbb17ee30e2bf822c4de3d455aed1d8816ad Mon Sep 17 00:00:00 2001 From: Basit <1305718+mabaasit@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:41:21 +0530 Subject: [PATCH 16/17] Update packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx Co-authored-by: Sergey Petushkov --- .../src/components/diagram-editor-toolbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx index ce74d4549f9..8c2e1e9c999 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor-toolbar.tsx @@ -12,7 +12,7 @@ export const DiagramEditorToolbar: React.FunctionComponent<{ onRedoClick: () => void; onExportClick: () => void; }> = ({ step, hasUndo, onUndoClick, hasRedo, onRedoClick, onExportClick }) => { - if (step === 'NO_DIAGRAM_SELECTED' || step !== 'EDITING') { + if (step !== 'EDITING') { return null; } return ( From 69e315fca396083a8f1d8e89e795848d484b27b6 Mon Sep 17 00:00:00 2001 From: Basit Chonka Date: Tue, 24 Jun 2025 13:29:37 +0200 Subject: [PATCH 17/17] flip export props --- .../compass-data-modeling/src/services/export-diagram.spec.ts | 2 +- packages/compass-data-modeling/src/services/export-diagram.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compass-data-modeling/src/services/export-diagram.spec.ts b/packages/compass-data-modeling/src/services/export-diagram.spec.ts index 2e4be35e2b5..9f7fc5fdd17 100644 --- a/packages/compass-data-modeling/src/services/export-diagram.spec.ts +++ b/packages/compass-data-modeling/src/services/export-diagram.spec.ts @@ -10,7 +10,7 @@ describe('export-diagram', function () { const expectedCollections = Object.fromEntries( FlightModel.collections // eslint-disable-next-line @typescript-eslint/no-unused-vars - .map(({ displayPosition, indexes, ...rest }) => [rest.ns, rest]) + .map(({ ns, jsonSchema, ...rest }) => [ns, { ns, jsonSchema }]) ); expect(json.collections).to.deep.equal(expectedCollections); diff --git a/packages/compass-data-modeling/src/services/export-diagram.ts b/packages/compass-data-modeling/src/services/export-diagram.ts index 107bbe0bc71..53eb166aa69 100644 --- a/packages/compass-data-modeling/src/services/export-diagram.ts +++ b/packages/compass-data-modeling/src/services/export-diagram.ts @@ -24,8 +24,8 @@ export function getExportJsonFromModel({ collections: Object.fromEntries( collections.map((collection) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { displayPosition, indexes, ...restOfTheCollection } = collection; - return [collection.ns, restOfTheCollection]; + const { ns, jsonSchema, ...ignoredProps } = collection; + return [ns, { ns, jsonSchema }]; }) ), relationships,