Skip to content

Commit 1e43c79

Browse files
authored
fix(browser-repl): keep operation in progress COMPASS-8576 (#2284)
1 parent d790fd0 commit 1e43c79

File tree

10 files changed

+1067
-823
lines changed

10 files changed

+1067
-823
lines changed

package-lock.json

Lines changed: 193 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/browser-repl/README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,20 @@ const runtime = new IframeRuntime(serviceProvider);
3131
Shell is a React component with the following properties:
3232

3333
- `runtime: Runtime`: The runtime used to evaluate code.
34-
- `onOutputChanged?: (output: readonly ShellOutputEntry[]) => void`: A function called each time the output changes with an array of `ShellOutputEntryes`.
35-
- `onHistoryChanged?: (history: readonly string[]) => void`: A function called each time the history changes with an array of history entries ordered from the most recent to the oldest entry.
34+
- `onOutputChanged?: (output: ShellOutputEntry[]) => void`: A function called each time the output changes with an array of `ShellOutputEntries`.
35+
- `onHistoryChanged?: (history: string[]) => void`: A function called each time the history changes with an array of history entries ordered from the most recent to the oldest entry.
36+
- `onEditorChanged?: (editor: EditorRef | null) => void`: A function called each time the editor ref changes. Can be used to call editor methods.
37+
- `onOperationStarted?: () => void`: A function called when an operation has begun.
38+
- `onOperationEnd?: () => void`: A function called when an operation has completed (both error and success).
3639
- `redactInfo?: boolean`: If set, the shell will omit or redact entries containing sensitive info from history. Defaults to `false`.
3740
- `maxOutputLength?: number`: The maxiumum number of lines to keep in the output. Defaults to `1000`.
3841
- `maxHistoryLength?: number`: The maxiumum number of lines to keep in the history. Defaults to `1000`.
39-
- `initialOutput?: readonly ShellOutputEntry[]`: An array of entries to be displayed in the output area. Can be used to restore the output between sessions, or to setup a greeting message. **Note**: new entries will not be appended to the array.
40-
- `initialHistory?: readonly string[]`: An array of history entries to prepopulate the history.
42+
- `initialEvaluate?: string|string[]`: A set of input strings to evaluate right after shell is mounted.
43+
- `initialText?: string`: The initial text for the input field.
44+
- `output?: ShellOutputEntry[]`: An array of entries to be displayed in the output area. Can be used to restore the output between sessions, or to setup a greeting message. **Note**: new entries will not be appended to the array.
45+
- `history?: readonly string[]`: An array of history entries to prepopulate the history.
4146
Can be used to restore the history between sessions. Entries must be ordered from the most recent to the oldest. Note: new entries will not be appended to the array.
47+
- `isOperationInProgress?: boolean`: Can be used to restore the value between sessions.
4248

4349
### `ShellOutputEntry`
4450

packages/browser-repl/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"depcheck": "depcheck",
3636
"compile": "tsc -p tsconfig.json",
3737
"prettier": "prettier",
38-
"reformat": "npm run prettier -- --write . && npm run eslint --fix"
38+
"reformat": "npm run prettier -- --write . && npm run eslint --fix",
39+
"sync-to-compass": "node scripts/sync-to-compass.js"
3940
},
4041
"config": {
4142
"unsafe-perm": true
@@ -76,6 +77,9 @@
7677
"@mongodb-js/prettier-config-devtools": "^1.0.1",
7778
"@mongodb-js/tsconfig-mongosh": "^1.0.0",
7879
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.8",
80+
"@testing-library/dom": "^8.20.1",
81+
"@testing-library/react": "^12.1.5",
82+
"@testing-library/user-event": "^13.5.0",
7983
"@types/numeral": "^2.0.2",
8084
"@types/react": "^16.9.17",
8185
"@types/react-dom": "^18.0.8",
@@ -96,6 +100,7 @@
96100
"karma-mocha-reporter": "^2.2.5",
97101
"karma-typescript": "^5.5.4",
98102
"karma-webpack": "^5.0.0",
103+
"lodash": "^4.17.21",
99104
"path-browserify": "^1.0.1",
100105
"prettier": "^2.8.8",
101106
"prop-types": "^15.7.2",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* eslint-disable no-console */
2+
'use strict';
3+
const fs = require('fs');
4+
const path = require('path');
5+
const child_process = require('child_process');
6+
const { debounce } = require('lodash');
7+
8+
if (!process.env.COMPASS_HOME) {
9+
throw new Error('Missing required environment variable $COMPASS_HOME.');
10+
}
11+
12+
const packageDir = path.resolve(__dirname, '..');
13+
const srcDir = path.resolve(__dirname, '..', 'src');
14+
const libDir = path.resolve(__dirname, '..', 'lib');
15+
16+
const destDir = path.dirname(
17+
child_process.execFileSync(
18+
'node',
19+
['-p', "require.resolve('@mongosh/browser-repl')"],
20+
{ cwd: process.env.COMPASS_HOME, encoding: 'utf-8' }
21+
)
22+
);
23+
24+
console.log({ packageDir, srcDir, libDir, destDir });
25+
26+
const compileAndCopy = debounce(
27+
function () {
28+
try {
29+
child_process.execFileSync('npm', ['run', 'compile'], {
30+
cwd: packageDir,
31+
encoding: 'utf-8',
32+
});
33+
} catch (err) {
34+
if (err.code) {
35+
// Spawning child process failed
36+
console.error(err.code);
37+
} else {
38+
// Child was spawned but exited with non-zero exit code
39+
// Error contains any stdout and stderr from the child
40+
const { stdout, stderr } = err;
41+
42+
console.log(stdout);
43+
console.error(stderr);
44+
}
45+
}
46+
fs.cpSync(libDir, destDir, { recursive: true });
47+
console.log('done.');
48+
},
49+
1_000,
50+
{
51+
leading: true,
52+
trailing: true,
53+
}
54+
);
55+
56+
const srcWatcher = fs.watch(
57+
srcDir,
58+
{ recursive: true },
59+
function (eventType, filename) {
60+
console.log(eventType, filename);
61+
compileAndCopy();
62+
}
63+
);
64+
65+
function cleanup() {
66+
srcWatcher.close();
67+
}
68+
69+
for (const evt of ['SIGINT', 'SIGTERM']) {
70+
process.on(evt, cleanup);
71+
}
72+
73+
// do an initial copy on startup
74+
compileAndCopy();

packages/browser-repl/src/components/password-prompt.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ export class PasswordPrompt extends Component<PasswordPromptProps> {
3939

4040
render(): JSX.Element {
4141
return (
42-
<label id="password-promt-label" className={passwordPrompt}>
42+
<label id="password-prompt-label" className={passwordPrompt}>
4343
{this.props.prompt}:&nbsp;
4444
<TextInput
45-
aria-labelledby="password-promt-label"
45+
data-testid="password-prompt"
46+
aria-labelledby="password-prompt-label"
4647
type="password"
4748
onKeyDown={this.onKeyDown}
4849
className={passwordPropmtInputStyles}

packages/browser-repl/src/components/shell-input.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,14 @@ export class ShellInput extends Component<ShellInputProps, ShellInputState> {
109109
};
110110

111111
private onEnter = async (): Promise<void> => {
112+
const value = this.state.currentValue;
113+
// clear the value before evaluating the input because it could take a long
114+
// time
115+
this.setState({ currentValue: '' });
116+
112117
if (this.props.onInput) {
113-
await this.props.onInput(this.state.currentValue);
118+
await this.props.onInput(value);
114119
}
115-
116-
this.setState({ currentValue: '' });
117120
};
118121

119122
render(): JSX.Element {

0 commit comments

Comments
 (0)