Skip to content

Commit

Permalink
fix(browser-repl): keep operation in progress COMPASS-8576 (#2284)
Browse files Browse the repository at this point in the history
  • Loading branch information
lerouxb authored Dec 13, 2024
1 parent d790fd0 commit 1e43c79
Show file tree
Hide file tree
Showing 10 changed files with 1,067 additions and 823 deletions.
193 changes: 193 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions packages/browser-repl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ const runtime = new IframeRuntime(serviceProvider);
Shell is a React component with the following properties:

- `runtime: Runtime`: The runtime used to evaluate code.
- `onOutputChanged?: (output: readonly ShellOutputEntry[]) => void`: A function called each time the output changes with an array of `ShellOutputEntryes`.
- `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.
- `onOutputChanged?: (output: ShellOutputEntry[]) => void`: A function called each time the output changes with an array of `ShellOutputEntries`.
- `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.
- `onEditorChanged?: (editor: EditorRef | null) => void`: A function called each time the editor ref changes. Can be used to call editor methods.
- `onOperationStarted?: () => void`: A function called when an operation has begun.
- `onOperationEnd?: () => void`: A function called when an operation has completed (both error and success).
- `redactInfo?: boolean`: If set, the shell will omit or redact entries containing sensitive info from history. Defaults to `false`.
- `maxOutputLength?: number`: The maxiumum number of lines to keep in the output. Defaults to `1000`.
- `maxHistoryLength?: number`: The maxiumum number of lines to keep in the history. Defaults to `1000`.
- `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.
- `initialHistory?: readonly string[]`: An array of history entries to prepopulate the history.
- `initialEvaluate?: string|string[]`: A set of input strings to evaluate right after shell is mounted.
- `initialText?: string`: The initial text for the input field.
- `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.
- `history?: readonly string[]`: An array of history entries to prepopulate the history.
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.
- `isOperationInProgress?: boolean`: Can be used to restore the value between sessions.

### `ShellOutputEntry`

Expand Down
7 changes: 6 additions & 1 deletion packages/browser-repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"depcheck": "depcheck",
"compile": "tsc -p tsconfig.json",
"prettier": "prettier",
"reformat": "npm run prettier -- --write . && npm run eslint --fix"
"reformat": "npm run prettier -- --write . && npm run eslint --fix",
"sync-to-compass": "node scripts/sync-to-compass.js"
},
"config": {
"unsafe-perm": true
Expand Down Expand Up @@ -76,6 +77,9 @@
"@mongodb-js/prettier-config-devtools": "^1.0.1",
"@mongodb-js/tsconfig-mongosh": "^1.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.8",
"@testing-library/dom": "^8.20.1",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^13.5.0",
"@types/numeral": "^2.0.2",
"@types/react": "^16.9.17",
"@types/react-dom": "^18.0.8",
Expand All @@ -96,6 +100,7 @@
"karma-mocha-reporter": "^2.2.5",
"karma-typescript": "^5.5.4",
"karma-webpack": "^5.0.0",
"lodash": "^4.17.21",
"path-browserify": "^1.0.1",
"prettier": "^2.8.8",
"prop-types": "^15.7.2",
Expand Down
74 changes: 74 additions & 0 deletions packages/browser-repl/scripts/sync-to-compass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* eslint-disable no-console */
'use strict';
const fs = require('fs');
const path = require('path');
const child_process = require('child_process');
const { debounce } = require('lodash');

if (!process.env.COMPASS_HOME) {
throw new Error('Missing required environment variable $COMPASS_HOME.');
}

const packageDir = path.resolve(__dirname, '..');
const srcDir = path.resolve(__dirname, '..', 'src');
const libDir = path.resolve(__dirname, '..', 'lib');

const destDir = path.dirname(
child_process.execFileSync(
'node',
['-p', "require.resolve('@mongosh/browser-repl')"],
{ cwd: process.env.COMPASS_HOME, encoding: 'utf-8' }
)
);

console.log({ packageDir, srcDir, libDir, destDir });

const compileAndCopy = debounce(
function () {
try {
child_process.execFileSync('npm', ['run', 'compile'], {
cwd: packageDir,
encoding: 'utf-8',
});
} catch (err) {
if (err.code) {
// Spawning child process failed
console.error(err.code);
} else {
// Child was spawned but exited with non-zero exit code
// Error contains any stdout and stderr from the child
const { stdout, stderr } = err;

console.log(stdout);
console.error(stderr);
}
}
fs.cpSync(libDir, destDir, { recursive: true });
console.log('done.');
},
1_000,
{
leading: true,
trailing: true,
}
);

const srcWatcher = fs.watch(
srcDir,
{ recursive: true },
function (eventType, filename) {
console.log(eventType, filename);
compileAndCopy();
}
);

function cleanup() {
srcWatcher.close();
}

for (const evt of ['SIGINT', 'SIGTERM']) {
process.on(evt, cleanup);
}

// do an initial copy on startup
compileAndCopy();
5 changes: 3 additions & 2 deletions packages/browser-repl/src/components/password-prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ export class PasswordPrompt extends Component<PasswordPromptProps> {

render(): JSX.Element {
return (
<label id="password-promt-label" className={passwordPrompt}>
<label id="password-prompt-label" className={passwordPrompt}>
{this.props.prompt}:&nbsp;
<TextInput
aria-labelledby="password-promt-label"
data-testid="password-prompt"
aria-labelledby="password-prompt-label"
type="password"
onKeyDown={this.onKeyDown}
className={passwordPropmtInputStyles}
Expand Down
9 changes: 6 additions & 3 deletions packages/browser-repl/src/components/shell-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,14 @@ export class ShellInput extends Component<ShellInputProps, ShellInputState> {
};

private onEnter = async (): Promise<void> => {
const value = this.state.currentValue;
// clear the value before evaluating the input because it could take a long
// time
this.setState({ currentValue: '' });

if (this.props.onInput) {
await this.props.onInput(this.state.currentValue);
await this.props.onInput(value);
}

this.setState({ currentValue: '' });
};

render(): JSX.Element {
Expand Down
Loading

0 comments on commit 1e43c79

Please sign in to comment.