Skip to content

Commit

Permalink
fix(compass-schema): complexity and size limits COMPASS-8905 COMPASS-…
Browse files Browse the repository at this point in the history
  • Loading branch information
paula-stacho authored Feb 24, 2025
1 parent 25ecd73 commit edd6d03
Show file tree
Hide file tree
Showing 16 changed files with 387 additions and 1,105 deletions.
1,210 changes: 185 additions & 1,025 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/compass-aggregations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
"mongodb-instance-model": "^12.26.2",
"mongodb-ns": "^2.4.2",
"mongodb-query-parser": "^4.3.0",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"prop-types": "^15.7.2",
"re-resizable": "^6.9.0",
"react": "^17.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const actionButtonStyles = css({
marginLeft: 'auto',
});

type DismissProps =
| { dismissible: true; onClose: () => void }
| { dismissible?: false; onClose?: never };

function Summary({ messages }: { messages: string[] }): React.ReactElement {
if (messages.length === 1) {
return <div>{messages[0]}</div>;
Expand Down Expand Up @@ -80,14 +84,17 @@ const BannerWithSummary: React.FunctionComponent<
} & (
| { actionText: string; onAction(): void }
| { actionText?: never; onAction?: never }
)
) &
DismissProps
> = ({
['data-testid']: dataTestId,
messages,
onAction,
actionText,
variant,
className,
dismissible,
onClose,
}) => {
const _messages = useMemo(() => {
return !Array.isArray(messages) ? [messages] : messages;
Expand All @@ -98,6 +105,8 @@ const BannerWithSummary: React.FunctionComponent<
data-testid={dataTestId}
variant={variant}
className={cx(bannerStyle, className)}
dismissible={dismissible}
onClose={onClose}
>
<div className={summaryStyles}>
<Summary messages={_messages}></Summary>
Expand All @@ -124,7 +133,8 @@ export const ErrorSummary: React.FunctionComponent<
} & (
| { actionText: string; onAction(): void }
| { actionText?: never; onAction?: never }
)
) &
DismissProps
> = ({ className, errors, ...props }) => {
return (
<BannerWithSummary
Expand All @@ -144,7 +154,8 @@ export const WarningSummary: React.FunctionComponent<
} & (
| { actionText: string; onAction(): void }
| { actionText?: never; onAction?: never }
)
) &
DismissProps
> = ({ className, warnings, ...props }) => {
return (
<BannerWithSummary
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-field-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"@mongodb-js/compass-logging": "^1.6.2",
"hadron-app-registry": "^9.4.2",
"lodash": "^4.17.21",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"react": "^17.0.2",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-generative-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"compass-preferences-model": "^2.33.2",
"hadron-app-registry": "^9.4.2",
"mongodb": "^6.12.0",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"react": "^17.0.2",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-import-export/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"mongodb-data-service": "^22.25.2",
"mongodb-ns": "^2.4.2",
"mongodb-query-parser": "^4.3.0",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"papaparse": "^5.3.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-query-bar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"mongodb-ns": "^2.4.2",
"mongodb-query-parser": "^4.3.0",
"mongodb-query-util": "^2.4.2",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"react": "^17.0.2",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"lodash": "^4.17.21",
"mongodb": "^6.12.0",
"mongodb-query-util": "^2.4.2",
"mongodb-schema": "^12.3.2",
"mongodb-schema": "^12.4.0",
"numeral": "^1.5.6",
"prop-types": "^15.7.2",
"react": "^17.0.2",
Expand Down
19 changes: 14 additions & 5 deletions packages/compass-schema/src/components/compass-schema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ import { getAtlasPerformanceAdvisorLink } from '../utils';
import { useIsLastAppliedQueryOutdated } from '@mongodb-js/compass-query-bar';
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
import type { RootState } from '../stores/store';
import { startAnalysis, stopAnalysis } from '../stores/schema-analysis-reducer';
import {
analysisErrorDismissed,
type SchemaAnalysisError,
startAnalysis,
stopAnalysis,
} from '../stores/schema-analysis-reducer';
import { openExportSchema } from '../stores/schema-export-reducer';
import ExportSchemaModal from './export-schema-modal';
import ExportSchemaLegacyBanner from './export-schema-legacy-banner';
Expand Down Expand Up @@ -371,22 +376,24 @@ const PerformanceAdvisorBanner = () => {

const Schema: React.FunctionComponent<{
analysisState: AnalysisState;
errorMessage?: string;
error?: SchemaAnalysisError;
maxTimeMS?: number;
schema: MongodbSchema | null;
count?: number;
resultId?: string;
onExportSchemaClicked: () => void;
onStartAnalysis: () => Promise<void>;
onStopAnalysis: () => void;
onDismissError: () => void;
}> = ({
analysisState,
errorMessage,
error,
schema,
resultId,
onExportSchemaClicked,
onStartAnalysis,
onStopAnalysis,
onDismissError,
}) => {
const onApplyClicked = useCallback(() => {
void onStartAnalysis();
Expand All @@ -410,7 +417,8 @@ const Schema: React.FunctionComponent<{
onExportSchemaClicked={onExportSchemaClicked}
onResetClicked={onApplyClicked}
analysisState={analysisState}
errorMessage={errorMessage || ''}
error={error}
onDismissError={onDismissError}
isOutdated={!!outdated}
sampleSize={schema ? schema.count : 0}
schemaResultId={resultId || ''}
Expand Down Expand Up @@ -440,13 +448,14 @@ const Schema: React.FunctionComponent<{
export default connect(
(state: RootState) => ({
analysisState: state.schemaAnalysis.analysisState,
errorMessage: state.schemaAnalysis.errorMessage,
error: state.schemaAnalysis.error,
schema: state.schemaAnalysis.schema,
resultId: state.schemaAnalysis.resultId,
}),
{
onStartAnalysis: startAnalysis,
onStopAnalysis: () => stopAnalysis(),
onExportSchemaClicked: openExportSchema,
onDismissError: analysisErrorDismissed,
}
)(Schema);
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ describe('SchemaToolbar', function () {
<MockQueryBarPlugin {...(queryBarProps as any)}>
<SchemaToolbar
analysisState="complete"
errorMessage={''}
error={undefined}
isOutdated={false}
onAnalyzeSchemaClicked={() => {}}
onResetClicked={() => {}}
sampleSize={10}
schemaResultId="123"
onExportSchemaClicked={() => {}}
onDismissError={() => {}}
{...props}
/>
</MockQueryBarPlugin>,
Expand All @@ -60,23 +61,54 @@ describe('SchemaToolbar', function () {
sinon.restore();
});

it("renders errors when they're passed", function () {
renderSchemaToolbar({
analysisState: 'error',
errorMessage: 'test error msg',
describe('errors', function () {
it('renders general error', function () {
renderSchemaToolbar({
analysisState: 'initial',
error: {
errorType: 'general',
errorMessage: 'test error msg',
},
});

expect(screen.getByText(testErrorMessage)).to.be.visible;
expect(screen.getByTestId('schema-toolbar-error-message')).to.be.visible;
});

expect(screen.getByText(testErrorMessage)).to.be.visible;
expect(screen.getByTestId('schema-toolbar-error-message')).to.be.visible;
});
it('renders timeout error', function () {
renderSchemaToolbar({
analysisState: 'initial',
error: {
errorType: 'timeout',
errorMessage: 'test error msg',
},
});

it('does not render errors when the analysis state is not error', function () {
renderSchemaToolbar({
errorMessage: 'test error msg',
expect(screen.getByTestId('schema-toolbar-timeout-message')).to.be
.visible;
expect(
screen.getByTestId('schema-toolbar-timeout-message').textContent
).to.include('Please try increasing the maxTimeMS');
});

expect(screen.queryByText(testErrorMessage)).to.not.exist;
expect(screen.queryByTestId('schema-toolbar-error-message')).to.not.exist;
it('renders complexity abort error', function () {
renderSchemaToolbar({
analysisState: 'initial',
error: {
errorType: 'highComplexity',
errorMessage: 'test error msg',
},
});

expect(screen.getByTestId('schema-toolbar-complexity-abort-message')).to
.be.visible;
expect(
screen.getByRole('link', { name: 'Learn more' })
).to.have.attribute(
'href',
'https://www.mongodb.com/docs/manual/data-modeling/design-antipatterns/bloated-documents/'
);
});
});

it('renders the sample size count', function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useMemo } from 'react';
import {
Banner,
BannerVariant,
Body,
Button,
ErrorSummary,
Expand All @@ -11,12 +13,10 @@ import {
} from '@mongodb-js/compass-components';
import { usePreference } from 'compass-preferences-model/provider';
import type { AnalysisState } from '../../constants/analysis-states';
import {
ANALYSIS_STATE_ERROR,
ANALYSIS_STATE_TIMEOUT,
ANALYSIS_STATE_COMPLETE,
} from '../../constants/analysis-states';
import { ANALYSIS_STATE_COMPLETE } from '../../constants/analysis-states';
import { QueryBar } from '@mongodb-js/compass-query-bar';
import { type SchemaAnalysisError } from '../../stores/schema-analysis-reducer';
import { DISTINCT_FIELDS_ABORT_THRESHOLD } from '../../modules/schema-analysis';

const schemaToolbarStyles = css({
display: 'flex',
Expand Down Expand Up @@ -60,18 +60,20 @@ const SCHEMA_ANALYSIS_DOCS_LINK =

type SchemaToolbarProps = {
analysisState: AnalysisState;
errorMessage: string;
error?: SchemaAnalysisError;
isOutdated: boolean;
onAnalyzeSchemaClicked: () => void;
onExportSchemaClicked: () => void;
onResetClicked: () => void;
onDismissError: () => void;
sampleSize: number;
schemaResultId: string;
};

const SchemaToolbar: React.FunctionComponent<SchemaToolbarProps> = ({
analysisState,
errorMessage,
error,
onDismissError,
isOutdated,
onAnalyzeSchemaClicked,
onExportSchemaClicked,
Expand Down Expand Up @@ -130,14 +132,37 @@ const SchemaToolbar: React.FunctionComponent<SchemaToolbarProps> = ({
</div>
</div>
)}
{analysisState === ANALYSIS_STATE_ERROR && (
{error?.errorType === 'general' && (
<ErrorSummary
data-testid="schema-toolbar-error-message"
errors={[`${ERROR_WARNING}: ${errorMessage}`]}
errors={[`${ERROR_WARNING}: ${error.errorMessage}`]}
dismissible={true}
onClose={onDismissError}
/>
)}
{error?.errorType === 'timeout' && (
<WarningSummary
data-testid="schema-toolbar-timeout-message"
warnings={[INCREASE_MAX_TIME_MS_HINT_MESSAGE]}
dismissible={true}
onClose={onDismissError}
/>
)}
{analysisState === ANALYSIS_STATE_TIMEOUT && (
<WarningSummary warnings={[INCREASE_MAX_TIME_MS_HINT_MESSAGE]} />
{error?.errorType === 'highComplexity' && (
<Banner
variant={BannerVariant.Danger}
data-testid="schema-toolbar-complexity-abort-message"
dismissible={true}
onClose={onDismissError}
>
The analysis was aborted because the number of fields exceeds{' '}
{DISTINCT_FIELDS_ABORT_THRESHOLD}. Consider breaking up your data into
more collections with smaller documents, and using references to
consolidate the data you need.&nbsp;
<Link href="https://www.mongodb.com/docs/manual/data-modeling/design-antipatterns/bloated-documents/">
Learn more
</Link>
</Banner>
)}
{analysisState === ANALYSIS_STATE_COMPLETE && isOutdated && (
<WarningSummary warnings={[OUTDATED_WARNING_MESSAGE]} />
Expand Down
6 changes: 1 addition & 5 deletions packages/compass-schema/src/constants/analysis-states.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
export const ANALYSIS_STATE_INITIAL = 'initial';
export const ANALYSIS_STATE_ANALYZING = 'analyzing';
export const ANALYSIS_STATE_ERROR = 'error';
export const ANALYSIS_STATE_COMPLETE = 'complete';
export const ANALYSIS_STATE_TIMEOUT = 'timeout';

export type AnalysisState =
| typeof ANALYSIS_STATE_INITIAL
| typeof ANALYSIS_STATE_ANALYZING
| typeof ANALYSIS_STATE_ERROR
| typeof ANALYSIS_STATE_COMPLETE
| typeof ANALYSIS_STATE_TIMEOUT;
| typeof ANALYSIS_STATE_COMPLETE;
Loading

0 comments on commit edd6d03

Please sign in to comment.