Skip to content

Commit a209444

Browse files
committed
add analysis in progress
1 parent 825aeef commit a209444

File tree

8 files changed

+396
-269
lines changed

8 files changed

+396
-269
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import { Banner, Button, css, spacing } from '@mongodb-js/compass-components';
3+
import { connect } from 'react-redux';
4+
import type { DataModelingState } from '../store/reducer';
5+
import { retryAnalysis } from '../store/analysis-process';
6+
7+
const bannerStyles = css({
8+
margin: spacing[200],
9+
'& > div': {
10+
display: 'flex',
11+
alignItems: 'center',
12+
},
13+
});
14+
15+
const bannerButtonStyles = css({
16+
marginLeft: 'auto',
17+
});
18+
19+
const AnalysisFailed = ({
20+
error,
21+
onRetryClick,
22+
}: {
23+
error: Error | null;
24+
onRetryClick: () => void;
25+
}) => {
26+
return (
27+
<Banner variant="danger" className={bannerStyles}>
28+
<div>Analysis failed: {error?.message}</div>
29+
<Button
30+
className={bannerButtonStyles}
31+
size="xsmall"
32+
onClick={onRetryClick}
33+
>
34+
Retry
35+
</Button>
36+
</Banner>
37+
);
38+
};
39+
40+
export default connect(
41+
({ step, analysisProgress: { error } }: DataModelingState) => {
42+
if (step !== 'ANALYSIS_FAILED') {
43+
throw new Error('Unexpected state when analyzing collections failed');
44+
}
45+
return { error };
46+
},
47+
{
48+
onRetryClick: retryAnalysis,
49+
}
50+
)(AnalysisFailed);
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React from 'react';
2+
import {
3+
Body,
4+
css,
5+
Subtitle,
6+
palette,
7+
cx,
8+
useDarkMode,
9+
Button,
10+
spacing,
11+
} from '@mongodb-js/compass-components';
12+
import { connect } from 'react-redux';
13+
import type { DataModelingState } from '../store/reducer';
14+
import { cancelAnalysis } from '../store/analysis-process';
15+
16+
const containerStyles = css({
17+
display: 'flex',
18+
justifyContent: 'center',
19+
alignItems: 'center',
20+
height: '100%',
21+
});
22+
const contentStyles = css({
23+
display: 'flex',
24+
flexDirection: 'column',
25+
gap: spacing[200],
26+
width: 600,
27+
});
28+
29+
const titleAndProgressStyles = css({
30+
display: 'flex',
31+
flexDirection: 'row',
32+
gap: 8,
33+
justifyContent: 'space-between',
34+
alignItems: 'center',
35+
});
36+
37+
const titleStyles = css({
38+
color: palette.green.dark2,
39+
textAlign: 'center',
40+
});
41+
42+
const titleDarkStyles = css({
43+
color: palette.green.light2,
44+
});
45+
46+
const actionContainerStyles = css({
47+
display: 'flex',
48+
justifyContent: 'center',
49+
marginTop: 32,
50+
});
51+
52+
const progressBarStyles = css({
53+
background: palette.gray.light1,
54+
borderRadius: spacing[100],
55+
height: spacing[200],
56+
width: '100%',
57+
});
58+
59+
const activeProgressBarStyles = css({
60+
backgroundImage: `linear-gradient(90deg, ${palette.blue.light1}, ${palette.blue.dark1}, ${palette.blue.light1})`,
61+
backgroundSize: '200% 100%',
62+
borderRadius: 4,
63+
height: '100%',
64+
content: '""',
65+
display: 'block',
66+
animation: 'animateBar 1s ease-in infinite',
67+
'@keyframes animateBar': {
68+
'0%': {
69+
backgroundPosition: '0 50%',
70+
},
71+
'50%': {
72+
backgroundPosition: '100% 50%',
73+
},
74+
'100%': {
75+
backgroundPosition: '0 50%',
76+
},
77+
},
78+
});
79+
80+
type AnalysisInProgressProps = {
81+
progress: number;
82+
description: string;
83+
onCancel: () => void;
84+
};
85+
86+
const AnalysisInProgress = ({
87+
progress,
88+
description,
89+
onCancel,
90+
}: AnalysisInProgressProps) => {
91+
const darkMode = useDarkMode();
92+
return (
93+
<div className={containerStyles}>
94+
<div className={contentStyles}>
95+
<div className={titleAndProgressStyles}>
96+
<Subtitle className={cx(titleStyles, darkMode && titleDarkStyles)}>
97+
Analyzing Documents ...
98+
</Subtitle>
99+
<Body>{progress}%</Body>
100+
</div>
101+
<div>
102+
<div className={progressBarStyles}>
103+
<div
104+
className={cx(activeProgressBarStyles)}
105+
style={{ width: `${progress}%` }}
106+
/>
107+
</div>
108+
</div>
109+
<Body>{description}</Body>
110+
<div className={actionContainerStyles}>
111+
<Button onClick={onCancel} variant="primaryOutline">
112+
Cancel
113+
</Button>
114+
</div>
115+
</div>
116+
</div>
117+
);
118+
};
119+
120+
export default connect(
121+
({
122+
step,
123+
analysisProgress: { currentAnalysisOptions, schemasAnalyzed },
124+
}: DataModelingState) => {
125+
if (!currentAnalysisOptions || step !== 'ANALYZING') {
126+
throw new Error('Unexpected state when analyzing collections');
127+
}
128+
const progress = currentAnalysisOptions
129+
? (schemasAnalyzed / currentAnalysisOptions.collections.length) * 100
130+
: 0;
131+
const description = `Analyzing ${schemasAnalyzed + 1} of ${
132+
currentAnalysisOptions.collections.length
133+
} collections`;
134+
return {
135+
progress: Math.round(progress),
136+
description,
137+
};
138+
},
139+
{
140+
onCancel: cancelAnalysis,
141+
}
142+
)(AnalysisInProgress);
Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,44 @@
11
import React from 'react';
22
import { connect } from 'react-redux';
3+
import { WorkspaceContainer } from '@mongodb-js/compass-components';
34
import DiagramEditor from './diagram-editor';
45
import SavedDiagramsList from './saved-diagrams-list';
56
import NewDiagramFormModal from './new-diagram-form';
7+
import EditingDiagramToolbar from './editing-diagram-toolbar';
8+
import AnalysisInProgress from './analysis-in-progress';
9+
import AnalysisFailed from './analysis-failed';
610
import type { DataModelingState } from '../store/reducer';
11+
import type { StepState } from '../store/step';
712

813
type DataModelingPluginInitialProps = {
9-
showList: boolean;
14+
step: StepState;
1015
};
1116

1217
const DataModeling: React.FunctionComponent<DataModelingPluginInitialProps> = ({
13-
showList,
18+
step,
1419
}) => {
1520
return (
16-
<>
17-
{showList ? (
18-
<SavedDiagramsList></SavedDiagramsList>
21+
<WorkspaceContainer
22+
// Currently toolbar is only shown when editing a diagram or viewing a list of diagrams.
23+
// When viewing diagrams, the component renders its own toolbar using VirtualGrid.
24+
toolbar={step === 'EDITING' ? <EditingDiagramToolbar /> : null}
25+
>
26+
{step === 'NO_DIAGRAM_SELECTED' ? (
27+
<SavedDiagramsList />
28+
) : step === 'ANALYZING' ? (
29+
<AnalysisInProgress />
30+
) : step === 'ANALYSIS_FAILED' ? (
31+
<AnalysisFailed />
1932
) : (
20-
<DiagramEditor></DiagramEditor>
33+
<DiagramEditor />
2134
)}
2235
<NewDiagramFormModal></NewDiagramFormModal>
23-
</>
36+
</WorkspaceContainer>
2437
);
2538
};
2639

27-
export default connect((state: DataModelingState) => {
40+
export default connect(({ step }: DataModelingState) => {
2841
return {
29-
showList: state.step === 'NO_DIAGRAM_SELECTED',
42+
step,
3043
};
3144
})(DataModeling);

0 commit comments

Comments
 (0)