Skip to content

Commit 92c3e3d

Browse files
authored
chore(compass-shell): convert to typescript COMPASS-7425 (#5079)
1 parent c18fdc5 commit 92c3e3d

22 files changed

+230
-98
lines changed

packages/compass-shell/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
"eslint": "^7.25.0",
8888
"hadron-app-registry": "^9.0.14",
8989
"mocha": "^10.2.0",
90+
"mongodb-data-service": "^22.15.0",
9091
"nyc": "^15.1.0",
9192
"prop-types": "^15.7.2",
9293
"react-dom": "^17.0.2",

packages/compass-shell/src/components/compass-shell/compass-shell.spec.jsx renamed to packages/compass-shell/src/components/compass-shell/compass-shell.spec.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function updateAndWaitAsync(wrapper) {
1717
const fakeRuntime = {
1818
evaluate: sinon.fake.returns({ printable: 'some result' }),
1919
setEvaluationListener: () => {},
20-
};
20+
} as any;
2121

2222
describe('CompassShell', function () {
2323
context('when rendered', function () {
@@ -65,7 +65,7 @@ describe('CompassShell', function () {
6565
context('when rendered expanded', function () {
6666
context('when runtime property is not present', function () {
6767
it('does not render a shell if runtime is null', function () {
68-
const wrapper = mount(<CompassShell runtime={null} />);
68+
const wrapper = mount(<CompassShell runtime={null} enableShell />);
6969
try {
7070
wrapper.setState({ height: 300 });
7171
wrapper.update();
@@ -112,11 +112,11 @@ describe('CompassShell', function () {
112112
});
113113

114114
it('renders a Resizable component', function () {
115-
expect(wrapper.find(ResizeHandle)).to.be.present();
115+
expect(wrapper.find(ResizeHandle)).to.exist;
116116
});
117117

118118
it('renders the info modal component', function () {
119-
expect(wrapper.find(ShellInfoModal)).to.be.present();
119+
expect(wrapper.find(ShellInfoModal)).to.exist;
120120
});
121121

122122
it('renders the Shell with an output change handler', function () {
@@ -134,6 +134,7 @@ describe('CompassShell', function () {
134134
{
135135
type: 'output',
136136
value: 'pineapple',
137+
format: 'output',
137138
},
138139
]}
139140
enableShell
@@ -147,6 +148,7 @@ describe('CompassShell', function () {
147148
{
148149
type: 'output',
149150
value: 'pineapple',
151+
format: 'output',
150152
},
151153
]);
152154

@@ -157,7 +159,7 @@ describe('CompassShell', function () {
157159
context('when historyStorage is not present', function () {
158160
it('passes an empty history to the Shell', function () {
159161
const wrapper = shallow(
160-
<CompassShell runtime={fakeRuntime} isExpanded enableShell />
162+
<CompassShell runtime={fakeRuntime} enableShell />
161163
);
162164

163165
expect(wrapper.find(Shell).prop('initialHistory')).to.deep.equal([]);
@@ -233,9 +235,8 @@ describe('CompassShell', function () {
233235

234236
const wrapper = shallow(
235237
<CompassShell
236-
runtime={{}}
238+
runtime={{} as any}
237239
historyStorage={fakeStorage}
238-
isExpanded
239240
enableShell
240241
/>
241242
);
@@ -252,9 +253,8 @@ describe('CompassShell', function () {
252253
it('saves the history when history changes', async function () {
253254
const wrapper = shallow(
254255
<CompassShell
255-
runtime={{}}
256+
runtime={{} as any}
256257
historyStorage={fakeStorage}
257-
isExpanded
258258
enableShell
259259
/>
260260
);
@@ -271,19 +271,21 @@ describe('CompassShell', function () {
271271
});
272272

273273
it('sets shellOutput on onShellOutputChanged', function () {
274-
const shell = new CompassShell({ isExpanded: true });
274+
const shell = new CompassShell({} as any);
275275

276276
shell.onShellOutputChanged([
277277
{
278278
type: 'output',
279279
value: 'some output',
280+
format: 'output',
280281
},
281282
]);
282283

283284
expect(shell.shellOutput).to.deep.equal([
284285
{
285286
type: 'output',
286287
value: 'some output',
288+
format: 'output',
287289
},
288290
]);
289291
});

packages/compass-shell/src/components/compass-shell/compass-shell.jsx renamed to packages/compass-shell/src/components/compass-shell/compass-shell.tsx

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import React, { Component, Fragment } from 'react';
22
import PropTypes from 'prop-types';
33
import { connect } from 'react-redux';
44
import { withPreferences } from 'compass-preferences-model';
5+
import type { Shell as ShellType } from '@mongosh/browser-repl';
56

67
// The browser-repl package.json defines exports['.'].require but not .module, hence require() instead of import
7-
const { Shell } = require('@mongosh/browser-repl');
8+
const { Shell } =
9+
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/consistent-type-imports
10+
require('@mongosh/browser-repl') as typeof import('@mongosh/browser-repl');
811
import {
912
ResizeHandle,
1013
ResizeDirection,
@@ -16,6 +19,9 @@ import {
1619

1720
import ShellInfoModal from '../shell-info-modal';
1821
import ShellHeader from '../shell-header';
22+
import type { WorkerRuntime } from '@mongosh/node-runtime-worker-thread';
23+
import type { HistoryStorage } from '../../modules/history-storage';
24+
import type { RootState } from '../../modules';
1925

2026
const compassShellStyles = css(
2127
{
@@ -50,13 +56,34 @@ function getMaxShellHeight() {
5056

5157
// Apply bounds to the shell height when resizing to ensure it's always
5258
// visible and usable to the user.
53-
function boundShellHeight(attemptedHeight) {
59+
function boundShellHeight(attemptedHeight: number): number {
5460
const maxHeight = getMaxShellHeight();
5561

5662
return Math.min(maxHeight, Math.max(shellMinHeightOpened, attemptedHeight));
5763
}
5864

59-
export class CompassShell extends Component {
65+
export interface CompassShellProps {
66+
emitShellPluginOpened?: () => void;
67+
runtime: WorkerRuntime | null;
68+
shellOutput?: ShellOutputEntry[];
69+
historyStorage?: HistoryStorage;
70+
enableShell: boolean;
71+
}
72+
73+
interface CompassShellState {
74+
height: number;
75+
prevHeight: number;
76+
initialHistory: string[] | null;
77+
isOperationInProgress: boolean;
78+
showInfoModal: boolean;
79+
}
80+
81+
type ShellOutputEntry = ShellType['state']['output'][number];
82+
83+
export class CompassShell extends Component<
84+
CompassShellProps,
85+
CompassShellState
86+
> {
6087
static propTypes = {
6188
emitShellPluginOpened: PropTypes.func,
6289
runtime: PropTypes.object,
@@ -65,15 +92,18 @@ export class CompassShell extends Component {
6592
enableShell: PropTypes.bool,
6693
};
6794

95+
shellRef = React.createRef<ShellType>();
96+
shellOutput: readonly ShellOutputEntry[];
97+
6898
static defaultProps = {
69-
emitShellPluginOpened: () => {},
99+
emitShellPluginOpened: () => {
100+
/* ignore */
101+
},
70102
runtime: null,
71103
};
72-
constructor(props) {
104+
constructor(props: CompassShellProps) {
73105
super(props);
74106

75-
this.shellRef = React.createRef();
76-
77107
this.shellOutput = this.props.shellOutput || [];
78108

79109
this.state = {
@@ -86,25 +116,28 @@ export class CompassShell extends Component {
86116
}
87117

88118
componentDidMount() {
89-
this.loadHistory();
119+
void this.loadHistory();
90120
window.addEventListener('beforeunload', this.terminateRuntime);
91121
}
92122

93-
componentDidUpdate(prevProps, prevState) {
123+
componentDidUpdate(
124+
prevProps: CompassShellProps,
125+
prevState: CompassShellState
126+
) {
94127
const { height } = this.state;
95128
if (
96129
prevState.height < shellMinHeightOpened &&
97130
height > shellMinHeightOpened
98131
) {
99-
this.props.emitShellPluginOpened();
132+
this.props.emitShellPluginOpened?.();
100133
}
101134
}
102135

103136
componentWillUnmount() {
104137
window.removeEventListener('beforeunload', this.terminateRuntime);
105138
}
106139

107-
onShellOutputChanged = (output) => {
140+
onShellOutputChanged = (output: readonly ShellOutputEntry[]) => {
108141
this.shellOutput = output;
109142
};
110143

@@ -122,21 +155,23 @@ export class CompassShell extends Component {
122155

123156
terminateRuntime = () => {
124157
if (this.props.runtime) {
125-
this.props.runtime.terminate();
158+
void this.props.runtime.terminate();
126159
}
127160
};
128161

129-
saveHistory = async (history) => {
130-
if (!this.props.historyStorage) {
131-
return;
132-
}
133-
134-
try {
135-
await this.props.historyStorage.save(history);
136-
} catch (error) {
137-
// eslint-disable-next-line no-console
138-
console.error(error);
139-
}
162+
saveHistory = (history: readonly string[]) => {
163+
void (async () => {
164+
if (!this.props.historyStorage) {
165+
return;
166+
}
167+
168+
try {
169+
await this.props.historyStorage.save([...history]);
170+
} catch (error) {
171+
// eslint-disable-next-line no-console
172+
console.error(error);
173+
}
174+
})();
140175
};
141176

142177
loadHistory = async () => {
@@ -158,19 +193,19 @@ export class CompassShell extends Component {
158193
}
159194
};
160195

161-
updateHeight(height) {
162-
this.setState(
163-
height > shellMinHeightOpened
164-
? {
165-
height,
166-
// Store the previous height to use when toggling open/close
167-
// when we resize while the shell is expanded.
168-
prevHeight: height,
169-
}
170-
: {
171-
height,
172-
}
173-
);
196+
updateHeight(height: number) {
197+
if (height > shellMinHeightOpened) {
198+
this.setState({
199+
height,
200+
// Store the previous height to use when toggling open/close
201+
// when we resize while the shell is expanded.
202+
prevHeight: height,
203+
});
204+
} else {
205+
this.setState({
206+
height,
207+
});
208+
}
174209
}
175210

176211
hideInfoModal() {
@@ -179,7 +214,8 @@ export class CompassShell extends Component {
179214

180215
focusEditor() {
181216
if (this.shellRef.current && window.getSelection()?.type !== 'Range') {
182-
this.shellRef.current.focusEditor();
217+
(this.shellRef.current as any) /* private ... */
218+
.focusEditor();
183219
}
184220
}
185221

@@ -266,7 +302,7 @@ export class CompassShell extends Component {
266302
}
267303
}
268304

269-
export default connect((state) => ({
305+
export default connect((state: RootState) => ({
270306
emitShellPluginOpened: () => {
271307
if (state.appRegistry && state.appRegistry.globalAppRegistry) {
272308
state.appRegistry.globalAppRegistry.emit('compass:compass-shell:opened');

packages/compass-shell/src/components/shell-header/shell-header.spec.jsx renamed to packages/compass-shell/src/components/shell-header/shell-header.spec.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ describe('ShellHeader', function () {
1717
beforeEach(function () {
1818
wrapper = mount(
1919
<ShellHeader
20+
darkMode={undefined}
2021
isExpanded
2122
isOperationInProgress={false}
2223
onShellToggleClicked={() => {}}
@@ -52,6 +53,7 @@ describe('ShellHeader', function () {
5253
beforeEach(function () {
5354
wrapper = mount(
5455
<ShellHeader
56+
darkMode={undefined}
5557
isExpanded={false}
5658
isOperationInProgress={false}
5759
onShellToggleClicked={() => {}}
@@ -87,6 +89,7 @@ describe('ShellHeader', function () {
8789
it('renders the loader', function () {
8890
const wrapper = mount(
8991
<ShellHeader
92+
darkMode={undefined}
9093
isExpanded={false}
9194
isOperationInProgress
9295
onShellToggleClicked={() => {}}
@@ -101,9 +104,10 @@ describe('ShellHeader', function () {
101104
);
102105

103106
context('when rendered', function () {
104-
it('has a button to toggle the container', async function () {
107+
it('has a button to toggle the container', function () {
105108
const wrapper = shallow(
106109
<ShellHeader
110+
darkMode={undefined}
107111
isExpanded={false}
108112
isOperationInProgress={false}
109113
onShellToggleClicked={() => {}}
@@ -112,9 +116,7 @@ describe('ShellHeader', function () {
112116
);
113117

114118
expect(wrapper.find('button').exists()).to.equal(true);
115-
expect(
116-
wrapper.find('[data-testid="shell-expand-button"]')
117-
).to.be.present();
119+
expect(wrapper.find('[data-testid="shell-expand-button"]')).to.exist;
118120

119121
wrapper.unmount();
120122
});

0 commit comments

Comments
 (0)