Skip to content

Commit d0bb22b

Browse files
paula-stachoAnemy
andauthored
feat: legacy to new schema export COMPASS-8798 (#6713)
--------- Co-authored-by: Rhys <[email protected]>
1 parent d44cfe7 commit d0bb22b

File tree

8 files changed

+723
-63
lines changed

8 files changed

+723
-63
lines changed

packages/compass-collection/src/stores/collection-tab.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ export function activatePlugin(
8080
store.dispatch(selectTab('Aggregations'));
8181
});
8282

83+
on(localAppRegistry, 'menu-share-schema-json', () => {
84+
store.dispatch(selectTab('Schema'));
85+
});
86+
8387
void collectionModel.fetchMetadata({ dataService }).then((metadata) => {
8488
store.dispatch(collectionMetadataFetched(metadata));
8589
});

packages/compass-schema/src/components/compass-schema.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import type { RootState } from '../stores/store';
3939
import { startAnalysis, stopAnalysis } from '../stores/schema-analysis-reducer';
4040
import { openExportSchema } from '../stores/schema-export-reducer';
4141
import ExportSchemaModal from './export-schema-modal';
42+
import ExportSchemaLegacyBanner from './export-schema-legacy-banner';
4243

4344
const rootStyles = css({
4445
width: '100%',
@@ -431,6 +432,7 @@ const Schema: React.FunctionComponent<{
431432
</WorkspaceContainer>
432433
</div>
433434
{enableExportSchema && <ExportSchemaModal />}
435+
{enableExportSchema && <ExportSchemaLegacyBanner />}
434436
</>
435437
);
436438
};

packages/compass-schema/src/components/export-schema-legacy-banner.tsx

Lines changed: 547 additions & 0 deletions
Large diffs are not rendered by default.

packages/compass-schema/src/stores/schema-analysis-reducer.ts

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
schemaContainsGeoData,
1919
} from '../modules/schema-analysis';
2020
import { capMaxTimeMSAtPreferenceLimit } from 'compass-preferences-model/provider';
21-
import { openToast } from '@mongodb-js/compass-components';
2221
import type { Circle, Layer, LayerGroup, Polygon } from 'leaflet';
2322
import { mongoLogId } from '@mongodb-js/compass-logging/provider';
2423
import type { SchemaThunkAction } from './store';
@@ -126,56 +125,6 @@ function resultId(): string {
126125
return new UUID().toString();
127126
}
128127

129-
export const handleSchemaShare = (): SchemaThunkAction<void> => {
130-
return (dispatch, getState, { namespace }) => {
131-
const {
132-
schemaAnalysis: { schema },
133-
} = getState();
134-
const hasSchema = schema !== null;
135-
if (hasSchema) {
136-
void navigator.clipboard.writeText(JSON.stringify(schema, null, ' '));
137-
}
138-
dispatch(_trackSchemaShared(hasSchema));
139-
openToast(
140-
'share-schema',
141-
hasSchema
142-
? {
143-
variant: 'success',
144-
title: 'Schema Copied',
145-
description: `The schema definition of ${namespace} has been copied to your clipboard in JSON format.`,
146-
timeout: 5_000,
147-
}
148-
: {
149-
variant: 'warning',
150-
title: 'Analyze Schema First',
151-
description: 'Please Analyze the Schema First from the Schema Tab.',
152-
timeout: 5_000,
153-
}
154-
);
155-
};
156-
};
157-
158-
export const _trackSchemaShared = (
159-
hasSchema: boolean
160-
): SchemaThunkAction<void> => {
161-
return (dispatch, getState, { track, connectionInfoRef }) => {
162-
const {
163-
schemaAnalysis: { schema },
164-
} = getState();
165-
// Use a function here to a) ensure that the calculations here
166-
// are only made when telemetry is enabled and b) that errors from
167-
// those calculations are caught and logged rather than displayed to
168-
// users as errors from the core schema sharing logic.
169-
const trackEvent = () => ({
170-
has_schema: hasSchema,
171-
schema_width: schema?.fields?.length ?? 0,
172-
schema_depth: schema ? calculateSchemaDepth(schema) : 0,
173-
geo_data: schema ? schemaContainsGeoData(schema) : false,
174-
});
175-
track('Schema Exported', trackEvent, connectionInfoRef.current);
176-
};
177-
};
178-
179128
const getInitialState = (): SchemaAnalysisState => ({
180129
analysisState: ANALYSIS_STATE_INITIAL,
181130
errorMessage: '',

packages/compass-schema/src/stores/schema-export-reducer.ts

Lines changed: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ import type {
99

1010
import type { SchemaThunkAction } from './store';
1111
import { isAction } from '../utils';
12-
import type { SchemaAccessor } from '../modules/schema-analysis';
12+
import {
13+
calculateSchemaDepth,
14+
schemaContainsGeoData,
15+
type SchemaAccessor,
16+
} from '../modules/schema-analysis';
17+
import { openToast } from '@mongodb-js/compass-components';
1318

1419
export type SchemaFormat =
1520
| 'standardJSON'
@@ -20,6 +25,8 @@ export type ExportStatus = 'inprogress' | 'complete' | 'error';
2025
export type SchemaExportState = {
2126
abortController?: AbortController;
2227
isOpen: boolean;
28+
isLegacyBannerOpen: boolean;
29+
legacyBannerChoice?: 'legacy' | 'export';
2330
exportedSchema?: string;
2431
exportFormat: SchemaFormat;
2532
errorMessage?: string;
@@ -34,11 +41,16 @@ const getInitialState = (): SchemaExportState => ({
3441
exportStatus: 'inprogress',
3542
exportedSchema: undefined,
3643
isOpen: false,
44+
isLegacyBannerOpen: false,
45+
legacyBannerChoice: undefined,
3746
});
3847

3948
export const enum SchemaExportActions {
4049
openExportSchema = 'schema-service/schema-export/openExportSchema',
4150
closeExportSchema = 'schema-service/schema-export/closeExportSchema',
51+
openLegacyBanner = 'schema-service/schema-export/openLegacyBanner',
52+
closeLegacyBanner = 'schema-service/schema-export/closeLegacyBanner',
53+
setLegacyBannerChoice = 'schema-service/schema-export/setLegacyBannerChoice',
4254
changeExportSchemaStatus = 'schema-service/schema-export/changeExportSchemaStatus',
4355
changeExportSchemaFormatStarted = 'schema-service/schema-export/changeExportSchemaFormatStarted',
4456
changeExportSchemaFormatComplete = 'schema-service/schema-export/changeExportSchemaFormatComplete',
@@ -263,6 +275,42 @@ export const schemaExportReducer: Reducer<SchemaExportState, Action> = (
263275
};
264276
}
265277

278+
if (
279+
isAction<openLegacyBannerAction>(
280+
action,
281+
SchemaExportActions.openLegacyBanner
282+
)
283+
) {
284+
return {
285+
...state,
286+
isLegacyBannerOpen: true,
287+
};
288+
}
289+
290+
if (
291+
isAction<closeLegacyBannerAction>(
292+
action,
293+
SchemaExportActions.closeLegacyBanner
294+
)
295+
) {
296+
return {
297+
...state,
298+
isLegacyBannerOpen: false,
299+
};
300+
}
301+
302+
if (
303+
isAction<setLegacyBannerChoiceAction>(
304+
action,
305+
SchemaExportActions.setLegacyBannerChoice
306+
)
307+
) {
308+
return {
309+
...state,
310+
legacyBannerChoice: action.choice,
311+
};
312+
}
313+
266314
if (
267315
isAction<ChangeExportSchemaFormatStartedAction>(
268316
action,
@@ -319,3 +367,110 @@ export const schemaExportReducer: Reducer<SchemaExportState, Action> = (
319367

320368
return state;
321369
};
370+
371+
// TODO clean out when phase out is confirmed COMPASS-8692
372+
export type openLegacyBannerAction = {
373+
type: SchemaExportActions.openLegacyBanner;
374+
};
375+
376+
export const openLegacyBanner = (): SchemaThunkAction<void> => {
377+
return (dispatch, getState) => {
378+
const choiceInState = getState().schemaExport.legacyBannerChoice;
379+
const savedChoice = choiceInState || localStorage.getItem(localStorageId);
380+
if (savedChoice) {
381+
if (savedChoice !== choiceInState) {
382+
dispatch({
383+
type: SchemaExportActions.setLegacyBannerChoice,
384+
choice: savedChoice,
385+
});
386+
}
387+
if (savedChoice === 'legacy') {
388+
dispatch(confirmedLegacySchemaShare());
389+
return;
390+
}
391+
if (savedChoice === 'export') {
392+
dispatch(openExportSchema());
393+
return;
394+
}
395+
}
396+
dispatch({ type: SchemaExportActions.openLegacyBanner });
397+
};
398+
};
399+
400+
export type closeLegacyBannerAction = {
401+
type: SchemaExportActions.closeLegacyBanner;
402+
};
403+
404+
export type setLegacyBannerChoiceAction = {
405+
type: SchemaExportActions.setLegacyBannerChoice;
406+
choice: 'legacy' | 'export';
407+
};
408+
409+
const localStorageId = 'schemaExportLegacyBannerChoice';
410+
411+
export const switchToSchemaExport = (): SchemaThunkAction<void> => {
412+
return (dispatch) => {
413+
dispatch({ type: SchemaExportActions.closeLegacyBanner });
414+
dispatch(openExportSchema());
415+
};
416+
};
417+
418+
export const confirmedLegacySchemaShare = (): SchemaThunkAction<void> => {
419+
return (dispatch, getState, { namespace }) => {
420+
const {
421+
schemaAnalysis: { schema },
422+
} = getState();
423+
const hasSchema = schema !== null;
424+
if (hasSchema) {
425+
void navigator.clipboard.writeText(JSON.stringify(schema, null, ' '));
426+
}
427+
dispatch(_trackSchemaShared(hasSchema));
428+
dispatch({ type: SchemaExportActions.closeLegacyBanner });
429+
openToast(
430+
'share-schema',
431+
hasSchema
432+
? {
433+
variant: 'success',
434+
title: 'Schema Copied',
435+
description: `The schema definition of ${namespace} has been copied to your clipboard in JSON format.`,
436+
timeout: 5_000,
437+
}
438+
: {
439+
variant: 'warning',
440+
title: 'Analyze Schema First',
441+
description:
442+
'Please analyze the schema in the schema tab before sharing the schema.',
443+
}
444+
);
445+
};
446+
};
447+
448+
export const _trackSchemaShared = (
449+
hasSchema: boolean
450+
): SchemaThunkAction<void> => {
451+
return (dispatch, getState, { track, connectionInfoRef }) => {
452+
const {
453+
schemaAnalysis: { schema },
454+
} = getState();
455+
// Use a function here to a) ensure that the calculations here
456+
// are only made when telemetry is enabled and b) that errors from
457+
// those calculations are caught and logged rather than displayed to
458+
// users as errors from the core schema sharing logic.
459+
const trackEvent = () => ({
460+
has_schema: hasSchema,
461+
schema_width: schema?.fields?.length ?? 0,
462+
schema_depth: schema ? calculateSchemaDepth(schema) : 0,
463+
geo_data: schema ? schemaContainsGeoData(schema) : false,
464+
});
465+
track('Schema Exported', trackEvent, connectionInfoRef.current);
466+
};
467+
};
468+
469+
export const stopShowingLegacyBanner = (
470+
choice: 'legacy' | 'export'
471+
): SchemaThunkAction<void> => {
472+
return (dispatch) => {
473+
localStorage.setItem(localStorageId, choice);
474+
dispatch({ type: SchemaExportActions.setLegacyBannerChoice, choice });
475+
};
476+
};

packages/compass-schema/src/stores/store.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@ import type { PreferencesAccess } from 'compass-preferences-model/provider';
1717
import type { FieldStoreService } from '@mongodb-js/compass-field-store';
1818
import type { QueryBarService } from '@mongodb-js/compass-query-bar';
1919
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
20-
import {
21-
schemaAnalysisReducer,
22-
handleSchemaShare,
23-
stopAnalysis,
24-
} from './schema-analysis-reducer';
20+
import { schemaAnalysisReducer, stopAnalysis } from './schema-analysis-reducer';
2521
import {
2622
cancelExportSchema,
23+
confirmedLegacySchemaShare,
24+
openLegacyBanner,
2725
schemaExportReducer,
2826
} from './schema-export-reducer';
2927
import type { InternalLayer } from '../modules/geo';
@@ -78,9 +76,14 @@ export function activateSchemaPlugin(
7876
* When `Share Schema as JSON` clicked in menu show a dialog message.
7977
*/
8078

81-
on(services.localAppRegistry, 'menu-share-schema-json', () =>
82-
store.dispatch(handleSchemaShare())
83-
);
79+
on(services.localAppRegistry, 'menu-share-schema-json', () => {
80+
const { enableExportSchema } = services.preferences.getPreferences();
81+
if (enableExportSchema) {
82+
store.dispatch(openLegacyBanner());
83+
return;
84+
}
85+
store.dispatch(confirmedLegacySchemaShare());
86+
});
8487

8588
addCleanup(() => store.dispatch(stopAnalysis()));
8689
addCleanup(() => store.dispatch(cancelExportSchema()));

packages/compass/src/main/menu.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ describe('CompassMenu', function () {
411411
submenu: [
412412
{
413413
accelerator: 'Alt+CmdOrCtrl+S',
414-
label: '&Share Schema as JSON',
414+
label: '&Share Schema as JSON (Legacy)',
415415
},
416416
{
417417
type: 'separator',
@@ -445,7 +445,7 @@ describe('CompassMenu', function () {
445445
submenu: [
446446
{
447447
accelerator: 'Alt+CmdOrCtrl+S',
448-
label: '&Share Schema as JSON',
448+
label: '&Share Schema as JSON (Legacy)',
449449
},
450450
{
451451
type: 'separator',

packages/compass/src/main/menu.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ function collectionSubMenu(
326326
): MenuItemConstructorOptions {
327327
const subMenu = [];
328328
subMenu.push({
329-
label: '&Share Schema as JSON',
329+
label: '&Share Schema as JSON (Legacy)',
330330
accelerator: 'Alt+CmdOrCtrl+S',
331331
click() {
332332
ipcMain?.broadcastFocused('window:menu-share-schema-json');

0 commit comments

Comments
 (0)