From 53e3259a991a80af997cef0733331a7969cbc73c Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 21 May 2025 18:37:00 +0200 Subject: [PATCH 1/5] fix: track usage of uuid subtype 3 vs 4 COMPASS-9359 --- package-lock.json | 2 ++ packages/compass-components/.depcheckrc | 1 + packages/compass-components/package.json | 1 + .../src/components/bson-value.tsx | 16 ++++++++++++---- .../src/components/document-list/document.tsx | 4 ++++ .../src/components/document-list/element.tsx | 4 ++++ .../src/components/editable-document.tsx | 18 ++++++++++++------ .../src/components/readonly-document.tsx | 18 +++++++++++++----- packages/compass-crud/src/stores/crud-store.ts | 2 ++ .../compass-telemetry/src/telemetry-events.ts | 10 +++++++++- 10 files changed, 60 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9efa053d593..6358a34dc5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42822,6 +42822,7 @@ }, "devDependencies": { "@emotion/css": "^11.11.2", + "@mongodb-js/compass-telemetry": "^1.7.0", "@mongodb-js/eslint-config-compass": "^1.3.9", "@mongodb-js/mocha-config-compass": "^1.6.8", "@mongodb-js/prettier-config-compass": "^1.2.8", @@ -55300,6 +55301,7 @@ "@leafygreen-ui/tokens": "^2.11.3", "@leafygreen-ui/tooltip": "^13.0.2", "@leafygreen-ui/typography": "^20.0.2", + "@mongodb-js/compass-telemetry": "^1.7.0", "@mongodb-js/eslint-config-compass": "^1.3.9", "@mongodb-js/mocha-config-compass": "^1.6.8", "@mongodb-js/prettier-config-compass": "^1.2.8", diff --git a/packages/compass-components/.depcheckrc b/packages/compass-components/.depcheckrc index ecd21cbbf6f..b46f85d6b53 100644 --- a/packages/compass-components/.depcheckrc +++ b/packages/compass-components/.depcheckrc @@ -1,6 +1,7 @@ ignores: [ '@mongodb-js/prettier-config-compass', '@mongodb-js/tsconfig-compass', + '@mongodb-js/compass-telemetry', '@types/chai-dom', '@emotion/css', ] diff --git a/packages/compass-components/package.json b/packages/compass-components/package.json index db870600a93..409c32df65b 100644 --- a/packages/compass-components/package.json +++ b/packages/compass-components/package.json @@ -99,6 +99,7 @@ "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.1", "@mongodb-js/tsconfig-compass": "^1.2.8", + "@mongodb-js/compass-telemetry": "^1.7.0", "@types/chai": "^4.2.21", "@types/chai-dom": "^0.0.10", "@types/mocha": "^9.0.0", diff --git a/packages/compass-components/src/components/bson-value.tsx b/packages/compass-components/src/components/bson-value.tsx index f8da5f485e5..1d9e3d9a26d 100644 --- a/packages/compass-components/src/components/bson-value.tsx +++ b/packages/compass-components/src/components/bson-value.tsx @@ -8,12 +8,14 @@ import { Icon, Link } from './leafygreen'; import { spacing } from '@leafygreen-ui/tokens'; import { css, cx } from '@leafygreen-ui/emotion'; import { Theme, useDarkMode } from '../hooks/use-theme'; +import type { TrackFunction } from '@mongodb-js/compass-telemetry'; -type ValueProps = +type ValueProps = ( | { [type in keyof TypeCastMap]: { type: type; value: TypeCastMap[type] }; }[keyof TypeCastMap] - | { type: 'DBRef'; value: DBRef }; + | { type: 'DBRef'; value: DBRef } +) & { track?: TrackFunction }; function truncate(str: string, length = 70): string { const truncated = str.slice(0, length); @@ -122,6 +124,7 @@ const ObjectIdValue: React.FunctionComponent> = ({ const BinaryValue: React.FunctionComponent> = ({ value, + track, }) => { const { stringifiedValue, title, additionalHints } = useMemo(() => { if (value.sub_type === Binary.SUBTYPE_ENCRYPTED) { @@ -144,7 +147,7 @@ const BinaryValue: React.FunctionComponent> = ({ } if (value.sub_type === Binary.SUBTYPE_UUID) { let uuid: string; - + track?.('UUID Encountered', { subtype: 4 }); try { // Try to get the pretty hex version of the UUID uuid = value.toUUID().toString(); @@ -188,6 +191,9 @@ const BinaryValue: React.FunctionComponent> = ({ }; } } + if (value.sub_type === Binary.SUBTYPE_UUID_OLD) { + track?.('UUID Encountered', { subtype: 3 }); + } return { stringifiedValue: `Binary.createFromBase64('${truncate( value.toString('base64'), @@ -374,7 +380,9 @@ const BSONValue: React.FunctionComponent = (props) => { case 'Date': return ; case 'Binary': - return ; + return ( + + ); case 'Int32': case 'Double': return ; diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index 2e2d9cb540c..3c2a0042add 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -15,6 +15,7 @@ import { calculateShowMoreToggleOffset, HadronElement } from './element'; import { usePrevious } from './use-previous'; import VisibleFieldsToggle from './visible-field-toggle'; import { documentTypography } from './typography'; +import type { TrackFunction } from '@mongodb-js/compass-telemetry'; function useHadronDocument(doc: HadronDocumentType) { const prevDoc = usePrevious(doc); @@ -85,6 +86,7 @@ const HadronDocument: React.FunctionComponent<{ editable?: boolean; editing?: boolean; onEditStart?: () => void; + track?: TrackFunction; extraGutterWidth?: number; }> = ({ value: document, @@ -92,6 +94,7 @@ const HadronDocument: React.FunctionComponent<{ editing = false, onEditStart, extraGutterWidth, + track, }) => { const { elements, visibleElements } = useHadronDocument(document); const [autoFocus, setAutoFocus] = useState<{ @@ -148,6 +151,7 @@ const HadronDocument: React.FunctionComponent<{ } : undefined } + track={track} lineNumberSize={visibleElements.length} onAddElement={(el) => { setAutoFocus({ diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index f41a90a0bf3..ce06ba33f4e 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -28,6 +28,7 @@ import { palette } from '@leafygreen-ui/palette'; import { Icon } from '../leafygreen'; import { useDarkMode } from '../../hooks/use-theme'; import VisibleFieldsToggle from './visible-field-toggle'; +import type { TrackFunction } from '@mongodb-js/compass-telemetry'; function getEditorByType(type: HadronElementType['type']) { switch (type) { @@ -414,6 +415,7 @@ export const HadronElement: React.FunctionComponent<{ editable: boolean; editingEnabled: boolean; onEditStart?: (id: string, field: 'key' | 'value' | 'type') => void; + track?: TrackFunction; lineNumberSize: number; onAddElement(el: HadronElementType): void; extraGutterWidth?: number; @@ -422,6 +424,7 @@ export const HadronElement: React.FunctionComponent<{ editable, editingEnabled, onEditStart, + track, lineNumberSize, onAddElement, extraGutterWidth = 0, @@ -688,6 +691,7 @@ export const HadronElement: React.FunctionComponent<{ )} diff --git a/packages/compass-crud/src/components/editable-document.tsx b/packages/compass-crud/src/components/editable-document.tsx index 9040e2378ff..275f34e6197 100644 --- a/packages/compass-crud/src/components/editable-document.tsx +++ b/packages/compass-crud/src/components/editable-document.tsx @@ -8,6 +8,7 @@ import { withPreferences } from 'compass-preferences-model/provider'; import { documentStyles, documentContentStyles } from './readonly-document'; import { getInsightsForDocument } from '../utils'; import type { CrudActions } from '../stores/crud-store'; +import { TelemetryContext } from '@mongodb-js/compass-telemetry/provider'; const documentElementsContainerStyles = css({ position: 'relative', @@ -245,12 +246,17 @@ class EditableDocument extends React.Component< */ renderElements() { return ( - + + {(track) => ( + + )} + ); } diff --git a/packages/compass-crud/src/components/readonly-document.tsx b/packages/compass-crud/src/components/readonly-document.tsx index f2cbc395b07..e9fb1fc03a5 100644 --- a/packages/compass-crud/src/components/readonly-document.tsx +++ b/packages/compass-crud/src/components/readonly-document.tsx @@ -6,6 +6,7 @@ import type { TypeCastMap } from 'hadron-type-checker'; import { withPreferences } from 'compass-preferences-model/provider'; import { getInsightsForDocument } from '../utils'; import { DocumentEvents } from 'hadron-document'; +import { TelemetryContext } from '@mongodb-js/compass-telemetry/provider'; type BSONObject = TypeCastMap['Object']; export const documentStyles = css({ @@ -132,11 +133,18 @@ class ReadonlyDocument extends React.Component< */ renderElements() { return ( - + + {(track) => ( + <> + + + )} + ); } diff --git a/packages/compass-crud/src/stores/crud-store.ts b/packages/compass-crud/src/stores/crud-store.ts index 3dee965b3b7..514cb53bd43 100644 --- a/packages/compass-crud/src/stores/crud-store.ts +++ b/packages/compass-crud/src/stores/crud-store.ts @@ -833,6 +833,7 @@ class CrudStoreImpl * @param {Number} page - The page that is being shown. */ async getPage(page: number) { + console.log('getPage'); const { ns, status, docsPerPage } = this.state; if (page < 0) { @@ -1560,6 +1561,7 @@ class CrudStoreImpl * This function is called when the collection filter changes. */ async refreshDocuments(onApply = false) { + console.log('refreshDocuments'); if (this.dataService && !this.dataService.isConnected()) { this.logger.log.warn( mongoLogId(1_001_000_072), diff --git a/packages/compass-telemetry/src/telemetry-events.ts b/packages/compass-telemetry/src/telemetry-events.ts index 3a5182ac913..5b046cf1458 100644 --- a/packages/compass-telemetry/src/telemetry-events.ts +++ b/packages/compass-telemetry/src/telemetry-events.ts @@ -2694,6 +2694,13 @@ type CreateIndexButtonClickedEvent = CommonEvent<{ }; }>; +type UUIDEncounteredEvent = CommonEvent<{ + name: 'UUID Encountered'; + payload: { + subtype: 3 | 4; + }; +}>; + export type TelemetryEvent = | AggregationCanceledEvent | AggregationCopiedEvent @@ -2816,4 +2823,5 @@ export type TelemetryEvent = | CumulativeLayoutShiftEvent | TimeToFirstByteEvent | ExperimentViewedEvent - | CreateIndexButtonClickedEvent; + | CreateIndexButtonClickedEvent + | UUIDEncounteredEvent; From 7a31f949037bbeec57c04914706e6a5bf890f2bb Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 21 May 2025 18:38:18 +0200 Subject: [PATCH 2/5] cleanup --- packages/compass-crud/src/stores/crud-store.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/compass-crud/src/stores/crud-store.ts b/packages/compass-crud/src/stores/crud-store.ts index 514cb53bd43..3dee965b3b7 100644 --- a/packages/compass-crud/src/stores/crud-store.ts +++ b/packages/compass-crud/src/stores/crud-store.ts @@ -833,7 +833,6 @@ class CrudStoreImpl * @param {Number} page - The page that is being shown. */ async getPage(page: number) { - console.log('getPage'); const { ns, status, docsPerPage } = this.state; if (page < 0) { @@ -1561,7 +1560,6 @@ class CrudStoreImpl * This function is called when the collection filter changes. */ async refreshDocuments(onApply = false) { - console.log('refreshDocuments'); if (this.dataService && !this.dataService.isConnected()) { this.logger.log.warn( mongoLogId(1_001_000_072), From dbf57c1fc4afefca752d991928c174bb8237c8f2 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 22 May 2025 11:32:03 +0200 Subject: [PATCH 3/5] use callback --- package-lock.json | 2 -- packages/compass-components/.depcheckrc | 1 - packages/compass-components/package.json | 1 - .../src/components/bson-value.tsx | 14 ++++++++------ .../src/components/document-list/document.tsx | 7 +++---- .../src/components/document-list/element.tsx | 7 +++---- .../src/components/editable-document.tsx | 6 +++++- .../src/components/readonly-document.tsx | 6 +++++- 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6358a34dc5d..9efa053d593 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42822,7 +42822,6 @@ }, "devDependencies": { "@emotion/css": "^11.11.2", - "@mongodb-js/compass-telemetry": "^1.7.0", "@mongodb-js/eslint-config-compass": "^1.3.9", "@mongodb-js/mocha-config-compass": "^1.6.8", "@mongodb-js/prettier-config-compass": "^1.2.8", @@ -55301,7 +55300,6 @@ "@leafygreen-ui/tokens": "^2.11.3", "@leafygreen-ui/tooltip": "^13.0.2", "@leafygreen-ui/typography": "^20.0.2", - "@mongodb-js/compass-telemetry": "^1.7.0", "@mongodb-js/eslint-config-compass": "^1.3.9", "@mongodb-js/mocha-config-compass": "^1.6.8", "@mongodb-js/prettier-config-compass": "^1.2.8", diff --git a/packages/compass-components/.depcheckrc b/packages/compass-components/.depcheckrc index b46f85d6b53..ecd21cbbf6f 100644 --- a/packages/compass-components/.depcheckrc +++ b/packages/compass-components/.depcheckrc @@ -1,7 +1,6 @@ ignores: [ '@mongodb-js/prettier-config-compass', '@mongodb-js/tsconfig-compass', - '@mongodb-js/compass-telemetry', '@types/chai-dom', '@emotion/css', ] diff --git a/packages/compass-components/package.json b/packages/compass-components/package.json index 409c32df65b..db870600a93 100644 --- a/packages/compass-components/package.json +++ b/packages/compass-components/package.json @@ -99,7 +99,6 @@ "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.1", "@mongodb-js/tsconfig-compass": "^1.2.8", - "@mongodb-js/compass-telemetry": "^1.7.0", "@types/chai": "^4.2.21", "@types/chai-dom": "^0.0.10", "@types/mocha": "^9.0.0", diff --git a/packages/compass-components/src/components/bson-value.tsx b/packages/compass-components/src/components/bson-value.tsx index 1d9e3d9a26d..b069ef8ef36 100644 --- a/packages/compass-components/src/components/bson-value.tsx +++ b/packages/compass-components/src/components/bson-value.tsx @@ -8,14 +8,13 @@ import { Icon, Link } from './leafygreen'; import { spacing } from '@leafygreen-ui/tokens'; import { css, cx } from '@leafygreen-ui/emotion'; import { Theme, useDarkMode } from '../hooks/use-theme'; -import type { TrackFunction } from '@mongodb-js/compass-telemetry'; type ValueProps = ( | { [type in keyof TypeCastMap]: { type: type; value: TypeCastMap[type] }; }[keyof TypeCastMap] | { type: 'DBRef'; value: DBRef } -) & { track?: TrackFunction }; +) & { onUUIDEncountered?: (subtype: 3 | 4) => void }; function truncate(str: string, length = 70): string { const truncated = str.slice(0, length); @@ -124,7 +123,7 @@ const ObjectIdValue: React.FunctionComponent> = ({ const BinaryValue: React.FunctionComponent> = ({ value, - track, + onUUIDEncountered, }) => { const { stringifiedValue, title, additionalHints } = useMemo(() => { if (value.sub_type === Binary.SUBTYPE_ENCRYPTED) { @@ -147,7 +146,7 @@ const BinaryValue: React.FunctionComponent> = ({ } if (value.sub_type === Binary.SUBTYPE_UUID) { let uuid: string; - track?.('UUID Encountered', { subtype: 4 }); + onUUIDEncountered?.(4); try { // Try to get the pretty hex version of the UUID uuid = value.toUUID().toString(); @@ -192,7 +191,7 @@ const BinaryValue: React.FunctionComponent> = ({ } } if (value.sub_type === Binary.SUBTYPE_UUID_OLD) { - track?.('UUID Encountered', { subtype: 3 }); + onUUIDEncountered?.(3); } return { stringifiedValue: `Binary.createFromBase64('${truncate( @@ -381,7 +380,10 @@ const BSONValue: React.FunctionComponent = (props) => { return ; case 'Binary': return ( - + ); case 'Int32': case 'Double': diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index 3c2a0042add..92dcc9a5ddf 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -15,7 +15,6 @@ import { calculateShowMoreToggleOffset, HadronElement } from './element'; import { usePrevious } from './use-previous'; import VisibleFieldsToggle from './visible-field-toggle'; import { documentTypography } from './typography'; -import type { TrackFunction } from '@mongodb-js/compass-telemetry'; function useHadronDocument(doc: HadronDocumentType) { const prevDoc = usePrevious(doc); @@ -86,7 +85,7 @@ const HadronDocument: React.FunctionComponent<{ editable?: boolean; editing?: boolean; onEditStart?: () => void; - track?: TrackFunction; + onUUIDEncountered?: (subtype: 3 | 4) => void; extraGutterWidth?: number; }> = ({ value: document, @@ -94,7 +93,7 @@ const HadronDocument: React.FunctionComponent<{ editing = false, onEditStart, extraGutterWidth, - track, + onUUIDEncountered, }) => { const { elements, visibleElements } = useHadronDocument(document); const [autoFocus, setAutoFocus] = useState<{ @@ -151,7 +150,7 @@ const HadronDocument: React.FunctionComponent<{ } : undefined } - track={track} + onUUIDEncountered={onUUIDEncountered} lineNumberSize={visibleElements.length} onAddElement={(el) => { setAutoFocus({ diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index ce06ba33f4e..7c4af78c5cf 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -28,7 +28,6 @@ import { palette } from '@leafygreen-ui/palette'; import { Icon } from '../leafygreen'; import { useDarkMode } from '../../hooks/use-theme'; import VisibleFieldsToggle from './visible-field-toggle'; -import type { TrackFunction } from '@mongodb-js/compass-telemetry'; function getEditorByType(type: HadronElementType['type']) { switch (type) { @@ -415,7 +414,7 @@ export const HadronElement: React.FunctionComponent<{ editable: boolean; editingEnabled: boolean; onEditStart?: (id: string, field: 'key' | 'value' | 'type') => void; - track?: TrackFunction; + onUUIDEncountered?: (subtype: 3 | 4) => void; lineNumberSize: number; onAddElement(el: HadronElementType): void; extraGutterWidth?: number; @@ -424,7 +423,7 @@ export const HadronElement: React.FunctionComponent<{ editable, editingEnabled, onEditStart, - track, + onUUIDEncountered, lineNumberSize, onAddElement, extraGutterWidth = 0, @@ -691,7 +690,7 @@ export const HadronElement: React.FunctionComponent<{ )} diff --git a/packages/compass-crud/src/components/editable-document.tsx b/packages/compass-crud/src/components/editable-document.tsx index 275f34e6197..e3a36116ec7 100644 --- a/packages/compass-crud/src/components/editable-document.tsx +++ b/packages/compass-crud/src/components/editable-document.tsx @@ -253,7 +253,11 @@ class EditableDocument extends React.Component< editable editing={this.state.editing} onEditStart={this.handleStartEditing.bind(this)} - track={track} + onUUIDEncountered={(subtype: 3 | 4) => { + track('UUID Encountered', { + subtype, + }); + }} /> )} diff --git a/packages/compass-crud/src/components/readonly-document.tsx b/packages/compass-crud/src/components/readonly-document.tsx index e9fb1fc03a5..f8cdaec9fa9 100644 --- a/packages/compass-crud/src/components/readonly-document.tsx +++ b/packages/compass-crud/src/components/readonly-document.tsx @@ -140,7 +140,11 @@ class ReadonlyDocument extends React.Component< value={this.props.doc} // Provide extra whitespace for the expand button extraGutterWidth={spacing[900]} - track={track} + onUUIDEncountered={(subtype: 3 | 4) => { + track('UUID Encountered', { + subtype, + }); + }} /> )} From 1cf3098ca61b442f0e285809566c2ad2f9949f12 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 22 May 2025 15:00:53 +0200 Subject: [PATCH 4/5] traverse docs --- .../src/components/bson-value.tsx | 17 ++-------- .../src/components/document-list/document.tsx | 3 -- .../src/components/document-list/element.tsx | 3 -- .../src/components/editable-document.tsx | 22 ++++--------- .../src/components/readonly-document.tsx | 24 +++++--------- .../compass-crud/src/stores/crud-store.ts | 26 +++++++++++++--- .../compass-telemetry/src/telemetry-events.ts | 1 + packages/hadron-document/src/document.ts | 26 +++++++++++++++- packages/hadron-document/src/element.ts | 31 ++++++++++++++++++- 9 files changed, 94 insertions(+), 59 deletions(-) diff --git a/packages/compass-components/src/components/bson-value.tsx b/packages/compass-components/src/components/bson-value.tsx index b069ef8ef36..e4ad3244411 100644 --- a/packages/compass-components/src/components/bson-value.tsx +++ b/packages/compass-components/src/components/bson-value.tsx @@ -9,12 +9,11 @@ import { spacing } from '@leafygreen-ui/tokens'; import { css, cx } from '@leafygreen-ui/emotion'; import { Theme, useDarkMode } from '../hooks/use-theme'; -type ValueProps = ( +type ValueProps = | { [type in keyof TypeCastMap]: { type: type; value: TypeCastMap[type] }; }[keyof TypeCastMap] - | { type: 'DBRef'; value: DBRef } -) & { onUUIDEncountered?: (subtype: 3 | 4) => void }; + | { type: 'DBRef'; value: DBRef }; function truncate(str: string, length = 70): string { const truncated = str.slice(0, length); @@ -123,7 +122,6 @@ const ObjectIdValue: React.FunctionComponent> = ({ const BinaryValue: React.FunctionComponent> = ({ value, - onUUIDEncountered, }) => { const { stringifiedValue, title, additionalHints } = useMemo(() => { if (value.sub_type === Binary.SUBTYPE_ENCRYPTED) { @@ -146,7 +144,6 @@ const BinaryValue: React.FunctionComponent> = ({ } if (value.sub_type === Binary.SUBTYPE_UUID) { let uuid: string; - onUUIDEncountered?.(4); try { // Try to get the pretty hex version of the UUID uuid = value.toUUID().toString(); @@ -190,9 +187,6 @@ const BinaryValue: React.FunctionComponent> = ({ }; } } - if (value.sub_type === Binary.SUBTYPE_UUID_OLD) { - onUUIDEncountered?.(3); - } return { stringifiedValue: `Binary.createFromBase64('${truncate( value.toString('base64'), @@ -379,12 +373,7 @@ const BSONValue: React.FunctionComponent = (props) => { case 'Date': return ; case 'Binary': - return ( - - ); + return ; case 'Int32': case 'Double': return ; diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx index 92dcc9a5ddf..2e2d9cb540c 100644 --- a/packages/compass-components/src/components/document-list/document.tsx +++ b/packages/compass-components/src/components/document-list/document.tsx @@ -85,7 +85,6 @@ const HadronDocument: React.FunctionComponent<{ editable?: boolean; editing?: boolean; onEditStart?: () => void; - onUUIDEncountered?: (subtype: 3 | 4) => void; extraGutterWidth?: number; }> = ({ value: document, @@ -93,7 +92,6 @@ const HadronDocument: React.FunctionComponent<{ editing = false, onEditStart, extraGutterWidth, - onUUIDEncountered, }) => { const { elements, visibleElements } = useHadronDocument(document); const [autoFocus, setAutoFocus] = useState<{ @@ -150,7 +148,6 @@ const HadronDocument: React.FunctionComponent<{ } : undefined } - onUUIDEncountered={onUUIDEncountered} lineNumberSize={visibleElements.length} onAddElement={(el) => { setAutoFocus({ diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx index 7c4af78c5cf..f41a90a0bf3 100644 --- a/packages/compass-components/src/components/document-list/element.tsx +++ b/packages/compass-components/src/components/document-list/element.tsx @@ -414,7 +414,6 @@ export const HadronElement: React.FunctionComponent<{ editable: boolean; editingEnabled: boolean; onEditStart?: (id: string, field: 'key' | 'value' | 'type') => void; - onUUIDEncountered?: (subtype: 3 | 4) => void; lineNumberSize: number; onAddElement(el: HadronElementType): void; extraGutterWidth?: number; @@ -423,7 +422,6 @@ export const HadronElement: React.FunctionComponent<{ editable, editingEnabled, onEditStart, - onUUIDEncountered, lineNumberSize, onAddElement, extraGutterWidth = 0, @@ -690,7 +688,6 @@ export const HadronElement: React.FunctionComponent<{ )} diff --git a/packages/compass-crud/src/components/editable-document.tsx b/packages/compass-crud/src/components/editable-document.tsx index e3a36116ec7..9040e2378ff 100644 --- a/packages/compass-crud/src/components/editable-document.tsx +++ b/packages/compass-crud/src/components/editable-document.tsx @@ -8,7 +8,6 @@ import { withPreferences } from 'compass-preferences-model/provider'; import { documentStyles, documentContentStyles } from './readonly-document'; import { getInsightsForDocument } from '../utils'; import type { CrudActions } from '../stores/crud-store'; -import { TelemetryContext } from '@mongodb-js/compass-telemetry/provider'; const documentElementsContainerStyles = css({ position: 'relative', @@ -246,21 +245,12 @@ class EditableDocument extends React.Component< */ renderElements() { return ( - - {(track) => ( - { - track('UUID Encountered', { - subtype, - }); - }} - /> - )} - + ); } diff --git a/packages/compass-crud/src/components/readonly-document.tsx b/packages/compass-crud/src/components/readonly-document.tsx index f8cdaec9fa9..f34085e9f37 100644 --- a/packages/compass-crud/src/components/readonly-document.tsx +++ b/packages/compass-crud/src/components/readonly-document.tsx @@ -6,7 +6,6 @@ import type { TypeCastMap } from 'hadron-type-checker'; import { withPreferences } from 'compass-preferences-model/provider'; import { getInsightsForDocument } from '../utils'; import { DocumentEvents } from 'hadron-document'; -import { TelemetryContext } from '@mongodb-js/compass-telemetry/provider'; type BSONObject = TypeCastMap['Object']; export const documentStyles = css({ @@ -133,22 +132,13 @@ class ReadonlyDocument extends React.Component< */ renderElements() { return ( - - {(track) => ( - <> - { - track('UUID Encountered', { - subtype, - }); - }} - /> - - )} - + <> + + ); } diff --git a/packages/compass-crud/src/stores/crud-store.ts b/packages/compass-crud/src/stores/crud-store.ts index 3dee965b3b7..78ecd786d3b 100644 --- a/packages/compass-crud/src/stores/crud-store.ts +++ b/packages/compass-crud/src/stores/crud-store.ts @@ -112,11 +112,13 @@ const INITIAL_BULK_UPDATE_TEXT = `{ export const fetchDocuments: ( dataService: DataService, + track: TrackFunction, serverVersion: string, isDataLake: boolean, ...args: Parameters ) => Promise = async ( dataService: DataService, + track: TrackFunction, serverVersion, isDataLake, ns, @@ -145,17 +147,31 @@ export const fetchDocuments: ( }; try { - return ( + let uuidSubtype3Count = 0; + let uuidSubtype4Count = 0; + const docs = ( await dataService.find(ns, filter, modifiedOptions, executionOptions) ).map((doc) => { const { __doc, __size, ...rest } = doc; + let hadronDoc: HadronDocument; if (__doc && __size && Object.keys(rest).length === 0) { - const hadronDoc = new HadronDocument(__doc); + hadronDoc = new HadronDocument(__doc); hadronDoc.size = Number(__size); - return hadronDoc; + } else { + hadronDoc = new HadronDocument(doc); } - return new HadronDocument(doc); + const { subtype3Count, subtype4Count } = hadronDoc.findUUIDs(); + uuidSubtype3Count += subtype3Count; + uuidSubtype4Count += subtype4Count; + return hadronDoc; }); + if (uuidSubtype3Count > 0) { + track('UUID Encountered', { subtype: 3, count: uuidSubtype3Count }); + } + if (uuidSubtype4Count > 0) { + track('UUID Encountered', { subtype: 4, count: uuidSubtype4Count }); + } + return docs; } catch (err) { // We are handling all the cases where the size calculating projection might // not work, but just in case we run into some other environment or use-case @@ -896,6 +912,7 @@ class CrudStoreImpl try { documents = await fetchDocuments( this.dataService, + this.track, this.state.version, this.state.isDataLake, ns, @@ -1733,6 +1750,7 @@ class CrudStoreImpl ), fetchDocuments( this.dataService, + this.track, this.state.version, this.state.isDataLake, ns, diff --git a/packages/compass-telemetry/src/telemetry-events.ts b/packages/compass-telemetry/src/telemetry-events.ts index 5b046cf1458..20133b20808 100644 --- a/packages/compass-telemetry/src/telemetry-events.ts +++ b/packages/compass-telemetry/src/telemetry-events.ts @@ -2698,6 +2698,7 @@ type UUIDEncounteredEvent = CommonEvent<{ name: 'UUID Encountered'; payload: { subtype: 3 | 4; + count: number; }; }>; diff --git a/packages/hadron-document/src/document.ts b/packages/hadron-document/src/document.ts index 76068b3d6de..50899a7c6fb 100644 --- a/packages/hadron-document/src/document.ts +++ b/packages/hadron-document/src/document.ts @@ -12,7 +12,7 @@ import type { BSONArray, BSONObject, BSONValue } from './utils'; import { objectToIdiomaticEJSON } from './utils'; import type { HadronEJSONOptions } from './utils'; import { DocumentEvents } from '.'; -import type { MongoServerError } from 'mongodb'; +import type { Binary, MongoServerError } from 'mongodb'; /** * The event constant. @@ -450,6 +450,30 @@ export class Document extends EventEmitter { }, 0); } + findUUIDs() { + let subtype4Count = 0; + let subtype3Count = 0; + for (const element of this.elements) { + if (element.currentType === 'Binary') { + if ((element.value as Binary).sub_type === 4) { + subtype4Count++; + } + if ((element.value as Binary).sub_type === 3) { + subtype3Count++; + } + } else if ( + element.currentType === 'Object' || + element.currentType === 'Array' + ) { + const { subtype3Count: sub3, subtype4Count: sub4 } = + element.findUUIDs(); + subtype3Count += sub3; + subtype4Count += sub4; + } + } + return { subtype3Count, subtype4Count }; + } + startEditing(elementId?: string, field?: 'key' | 'value' | 'type'): void { if (!this.editing) { this.editing = true; diff --git a/packages/hadron-document/src/element.ts b/packages/hadron-document/src/element.ts index 9898ed76bc6..d89ca86876d 100644 --- a/packages/hadron-document/src/element.ts +++ b/packages/hadron-document/src/element.ts @@ -10,7 +10,7 @@ import DateEditor from './editor/date'; import Events from './element-events'; import type Document from './document'; import type { TypeCastTypes } from 'hadron-type-checker'; -import type { ObjectId } from 'bson'; +import type { Binary, ObjectId } from 'bson'; import type { BSONArray, BSONObject, BSONValue } from './utils'; import { getDefaultValueForType } from './utils'; import { DocumentEvents, ElementEvents } from '.'; @@ -879,6 +879,35 @@ export class Element extends EventEmitter { ); } + findUUIDs(): { subtype4Count: number; subtype3Count: number } { + let subtype4Count = 0; + let subtype3Count = 0; + + if (!this.elements) { + return { subtype4Count, subtype3Count }; + } + for (const element of this.elements) { + if (element.currentType === 'Binary') { + if ((element.currentValue as Binary).sub_type === 4) { + subtype4Count++; + } + if ((element.currentValue as Binary).sub_type === 3) { + subtype3Count++; + } + } else if ( + element.currentType === 'Object' || + element.currentType === 'Array' + ) { + const { subtype3Count: sub3, subtype4Count: sub4 } = + element.findUUIDs(); + subtype3Count += sub3; + subtype4Count += sub4; + } + } + + return { subtype4Count, subtype3Count }; + } + private emitVisibleElementsChanged(targetElement: Element | Document = this) { if (targetElement.isRoot()) { targetElement.emit(DocumentEvents.VisibleElementsChanged, targetElement); From bcf88a656b73992f1711f2dc78c6f5a81ba2b31c Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 22 May 2025 15:21:42 +0200 Subject: [PATCH 5/5] update test --- .../src/stores/crud-store.spec.ts | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/compass-crud/src/stores/crud-store.spec.ts b/packages/compass-crud/src/stores/crud-store.spec.ts index 54000017a64..4b0459595d1 100644 --- a/packages/compass-crud/src/stores/crud-store.spec.ts +++ b/packages/compass-crud/src/stores/crud-store.spec.ts @@ -2296,6 +2296,7 @@ describe('store', function () { }); describe('fetchDocuments', function () { + const track = createNoopTrack(); let findResult: unknown[] = []; let csfleMode = 'disabled'; let find = sinon.stub().callsFake(() => { @@ -2323,7 +2324,7 @@ describe('store', function () { }); it('should call find with $bsonSize projection when mongodb version is >= 4.4, not connected to ADF and csfle is disabled', async function () { - await fetchDocuments(dataService, '5.0.0', false, 'test.test', {}); + await fetchDocuments(dataService, track, '5.0.0', false, 'test.test', {}); expect(find).to.have.been.calledOnce; expect(find.getCall(0)) .to.have.nested.property('args.2.projection') @@ -2334,6 +2335,7 @@ describe('store', function () { findResult = [{ __size: new Int32(42), __doc: { _id: 1 } }]; const docs = await fetchDocuments( dataService, + track, '4.0.0', false, 'test.test', @@ -2345,7 +2347,7 @@ describe('store', function () { }); it('should NOT call find with $bsonSize projection when mongodb version is < 4.4', async function () { - await fetchDocuments(dataService, '4.0.0', false, 'test.test', {}); + await fetchDocuments(dataService, track, '4.0.0', false, 'test.test', {}); expect(find).to.have.been.calledOnce; expect(find.getCall(0)).to.have.nested.property( 'args.2.projection', @@ -2354,7 +2356,7 @@ describe('store', function () { }); it('should NOT call find with $bsonSize projection when connected to ADF', async function () { - await fetchDocuments(dataService, '5.0.0', true, 'test.test', {}); + await fetchDocuments(dataService, track, '5.0.0', true, 'test.test', {}); expect(find).to.have.been.calledOnce; expect(find.getCall(0)).to.have.nested.property( 'args.2.projection', @@ -2364,7 +2366,7 @@ describe('store', function () { it('should NOT call find with $bsonSize projection when csfle is enabled', async function () { csfleMode = 'enabled'; - await fetchDocuments(dataService, '5.0.0', false, 'test.test', {}); + await fetchDocuments(dataService, track, '5.0.0', false, 'test.test', {}); expect(find).to.have.been.calledOnce; expect(find.getCall(0)).to.have.nested.property( 'args.2.projection', @@ -2375,6 +2377,7 @@ describe('store', function () { it('should keep user projection when provided', async function () { await fetchDocuments( dataService, + track, '5.0.0', false, 'test.test', @@ -2399,6 +2402,7 @@ describe('store', function () { const docs = await fetchDocuments( dataService, + track, '5.0.0', false, 'test.test', @@ -2419,7 +2423,14 @@ describe('store', function () { find = sinon.stub().rejects(new TypeError('🤷‍♂️')); try { - await fetchDocuments(dataService, '5.0.0', false, 'test.test', {}); + await fetchDocuments( + dataService, + track, + '5.0.0', + false, + 'test.test', + {} + ); expect.fail('Expected fetchDocuments to fail with error'); } catch (err) { expect(find).to.have.been.calledOnce; @@ -2431,7 +2442,14 @@ describe('store', function () { find = sinon.stub().rejects(new MongoServerError('Nope')); try { - await fetchDocuments(dataService, '3.0.0', true, 'test.test', {}); + await fetchDocuments( + dataService, + track, + '3.0.0', + true, + 'test.test', + {} + ); expect.fail('Expected fetchDocuments to fail with error'); } catch (err) { expect(find).to.have.been.calledOnce;