Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ describe('CollectionHeaderActions [Component]', function () {
onOpenMockDataModal={sinon.stub()}
hasSchemaAnalysisData={true}
analyzedSchemaDepth={2}
schemaAnalysisStatus="complete"
schemaAnalysisError={null}
isCollectionEmpty={false}
hasUnsupportedStateError={false}
{...props}
/>
</WorkspacesServiceProvider>
Expand Down Expand Up @@ -354,7 +355,9 @@ describe('CollectionHeaderActions [Component]', function () {
isReadonly: false,
hasSchemaAnalysisData: true,
analyzedSchemaDepth: MAX_COLLECTION_NESTING_DEPTH + 1,
schemaAnalysisStatus: 'complete',
schemaAnalysisError: null,
isCollectionEmpty: false,
hasUnsupportedStateError: false,
onOpenMockDataModal: sinon.stub(),
},
{},
Expand All @@ -374,11 +377,37 @@ describe('CollectionHeaderActions [Component]', function () {
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: false,
schemaAnalysisStatus: 'error',
schemaAnalysisError: {
errorType: 'unsupportedState',
errorMessage: 'Unsupported state',
},
isCollectionEmpty: false,
hasUnsupportedStateError: true,
onOpenMockDataModal: sinon.stub(),
},
{},
atlasConnectionInfo
);

const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
expect(button).to.exist;
expect(button).to.have.attribute('aria-disabled', 'true');
});

it('should disable button when collection is empty', async function () {
await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: false,
schemaAnalysisError: {
errorType: 'empty',
errorMessage: 'No documents found in the collection to analyze.',
},
isCollectionEmpty: true,
hasUnsupportedStateError: false,
onOpenMockDataModal: sinon.stub(),
},
{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,7 @@ import {
useTrackOnChange,
type TrackFunction,
} from '@mongodb-js/compass-telemetry/provider';
import {
SCHEMA_ANALYSIS_STATE_ANALYZING,
type SchemaAnalysisStatus,
type SchemaAnalysisError,
} from '../../schema-analysis-types';
import { type SchemaAnalysisError } from '../../schema-analysis-types';
import { MAX_COLLECTION_NESTING_DEPTH } from '../mock-data-generator-modal/utils';
import {
buildChartsUrl,
Expand Down Expand Up @@ -61,7 +57,8 @@ type CollectionHeaderActionsProps = {
hasSchemaAnalysisData: boolean;
schemaAnalysisError: SchemaAnalysisError | null;
analyzedSchemaDepth: number;
schemaAnalysisStatus: SchemaAnalysisStatus | null;
isCollectionEmpty: boolean;
hasUnsupportedStateError: boolean;
};

const CollectionHeaderActions: React.FunctionComponent<
Expand All @@ -76,8 +73,9 @@ const CollectionHeaderActions: React.FunctionComponent<
onOpenMockDataModal,
hasSchemaAnalysisData,
analyzedSchemaDepth,
schemaAnalysisStatus,
schemaAnalysisError,
isCollectionEmpty,
hasUnsupportedStateError,
}: CollectionHeaderActionsProps) => {
const connectionInfo = useConnectionInfo();
const { id: connectionId, atlasMetadata } = connectionInfo;
Expand Down Expand Up @@ -117,21 +115,11 @@ const CollectionHeaderActions: React.FunctionComponent<
const exceedsMaxNestingDepth =
analyzedSchemaDepth > MAX_COLLECTION_NESTING_DEPTH;

const isCollectionEmpty =
!hasSchemaAnalysisData &&
schemaAnalysisStatus !== SCHEMA_ANALYSIS_STATE_ANALYZING;

const hasSchemaAnalysisUnsupportedStateError = Boolean(
schemaAnalysisError && schemaAnalysisError.errorType === 'unsupportedState'
);

const isView = isReadonly && sourceName && !editViewName;

const showViewEdit = isView && !preferencesReadWrite;
const shouldDisableMockDataButton =
!hasSchemaAnalysisData ||
exceedsMaxNestingDepth ||
hasSchemaAnalysisUnsupportedStateError;
!hasSchemaAnalysisData || exceedsMaxNestingDepth;

const onMockDataGeneratorCtaButtonClicked = useCallback(() => {
track('Mock Data Generator Opened', {
Expand Down Expand Up @@ -189,7 +177,7 @@ const CollectionHeaderActions: React.FunctionComponent<
enabled={
exceedsMaxNestingDepth ||
isCollectionEmpty ||
hasSchemaAnalysisUnsupportedStateError
hasUnsupportedStateError
}
trigger={
<div>
Expand All @@ -206,7 +194,7 @@ const CollectionHeaderActions: React.FunctionComponent<
}
>
<>
{hasSchemaAnalysisUnsupportedStateError ? (
{hasUnsupportedStateError ? (
<span className={tooltipMessageStyles}>
{schemaAnalysisError?.errorMessage}
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ import { connect } from 'react-redux';
import { openMockDataGeneratorModal } from '../../modules/collection-tab';
import type { CollectionState } from '../../modules/collection-tab';
import {
SCHEMA_ANALYSIS_STATE_COMPLETE,
SCHEMA_ANALYSIS_STATE_ERROR,
SCHEMA_ANALYSIS_STATE_COMPLETE,
type SchemaAnalysisStatus,
type SchemaAnalysisError,
} from '../../schema-analysis-types';
import {
selectHasSchemaAnalysisData,
selectIsCollectionEmpty,
selectHasUnsupportedStateError,
} from '../../stores/collection-tab';

const collectionHeaderStyles = css({
padding: spacing[400],
Expand Down Expand Up @@ -73,6 +78,8 @@ type CollectionHeaderProps = {
analyzedSchemaDepth: number;
schemaAnalysisStatus: SchemaAnalysisStatus | null;
schemaAnalysisError: SchemaAnalysisError | null;
isCollectionEmpty: boolean;
hasUnsupportedStateError: boolean;
};

const getInsightsForPipeline = (pipeline: any[], isAtlas: boolean) => {
Expand Down Expand Up @@ -110,8 +117,9 @@ const CollectionHeader: React.FunctionComponent<CollectionHeaderProps> = ({
onOpenMockDataModal,
hasSchemaAnalysisData,
analyzedSchemaDepth,
schemaAnalysisStatus,
schemaAnalysisError,
isCollectionEmpty,
hasUnsupportedStateError,
}) => {
const darkMode = useDarkMode();
const showInsights = usePreference('showInsights');
Expand Down Expand Up @@ -192,8 +200,9 @@ const CollectionHeader: React.FunctionComponent<CollectionHeaderProps> = ({
onOpenMockDataModal={onOpenMockDataModal}
hasSchemaAnalysisData={hasSchemaAnalysisData}
analyzedSchemaDepth={analyzedSchemaDepth}
schemaAnalysisStatus={schemaAnalysisStatus}
schemaAnalysisError={schemaAnalysisError}
isCollectionEmpty={isCollectionEmpty}
hasUnsupportedStateError={hasUnsupportedStateError}
/>
</div>
<MockDataGeneratorModal />
Expand All @@ -209,15 +218,14 @@ const mapStateToProps = (state: CollectionState) => {
schemaAnalysis && schemaAnalysis.status === SCHEMA_ANALYSIS_STATE_ERROR
? schemaAnalysis.error
: null,
hasSchemaAnalysisData:
schemaAnalysis &&
schemaAnalysis.status === SCHEMA_ANALYSIS_STATE_COMPLETE &&
Object.keys(schemaAnalysis.processedSchema).length > 0,
hasSchemaAnalysisData: selectHasSchemaAnalysisData(state),
analyzedSchemaDepth:
schemaAnalysis && schemaAnalysis.status === SCHEMA_ANALYSIS_STATE_COMPLETE
? schemaAnalysis.schemaMetadata.maxNestingDepth
: 0,
schemaAnalysisStatus: schemaAnalysis?.status || null,
isCollectionEmpty: selectIsCollectionEmpty(state),
hasUnsupportedStateError: selectHasUnsupportedStateError(state),
};
};

Expand Down
16 changes: 15 additions & 1 deletion packages/compass-collection/src/modules/collection-tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ const DEFAULT_SAMPLE_SIZE = 100;

const NO_DOCUMENTS_ERROR = 'No documents found in the collection to analyze.';

export class EmptyCollectionError extends Error {
constructor() {
super(NO_DOCUMENTS_ERROR);
this.name = 'EmptyCollectionError';
}
}

function isAction<A extends AnyAction>(
action: AnyAction,
type: A['type']
Expand All @@ -68,6 +75,13 @@ function getErrorDetails(error: Error): SchemaAnalysisError {
};
}

if (error instanceof EmptyCollectionError) {
return {
errorType: 'empty',
errorMessage: error.message,
};
}

const errorCode = (error as MongoError).code;
const errorMessage = error.message || 'Unknown error';
let errorType: SchemaAnalysisError['errorType'] = 'general';
Expand Down Expand Up @@ -756,7 +770,7 @@ export const analyzeCollectionSchema = (): CollectionThunkAction<
logger.debug(NO_DOCUMENTS_ERROR);
dispatch({
type: CollectionActions.SchemaAnalysisFailed,
error: new Error(NO_DOCUMENTS_ERROR),
error: new EmptyCollectionError(),
});
return;
}
Expand Down
7 changes: 6 additions & 1 deletion packages/compass-collection/src/schema-analysis-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export type SchemaAnalysisStartedState = {

export type SchemaAnalysisError = {
errorMessage: string;
errorType: 'timeout' | 'highComplexity' | 'general' | 'unsupportedState';
errorType:
| 'timeout'
| 'highComplexity'
| 'general'
| 'unsupportedState'
| 'empty';
};

export type SchemaAnalysisErrorState = {
Expand Down
Loading
Loading