Skip to content

Commit

Permalink
feat(browser-repl): allow to set initial input (#2051)
Browse files Browse the repository at this point in the history
  • Loading branch information
gribnoysup authored Jul 3, 2024
1 parent e24c78c commit 48ba90f
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 9 deletions.
6 changes: 3 additions & 3 deletions packages/browser-repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
"exports": {
".": {
"types": "./lib/index.d.ts",
"require": "./lib/index.js"
"default": "./lib/index.js"
},
"./shell": {
"types": "./lib/components/shell.d.ts",
"require": "./lib/components/shell.js"
"default": "./lib/components/shell.js"
},
"./package.json": {
"require": "./package.json"
"default": "./package.json"
}
},
"scripts": {
Expand Down
5 changes: 4 additions & 1 deletion packages/browser-repl/src/components/shell-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ interface ShellInputProps {
prompt?: string;
onSigInt?(): Promise<boolean>;
editorRef?: (editor: EditorRef | null) => void;
initialText?: string;
onTextChange?: (text: string) => void;
}

interface ShellInputState {
Expand All @@ -29,7 +31,7 @@ interface ShellInputState {

export class ShellInput extends Component<ShellInputProps, ShellInputState> {
readonly state: ShellInputState = {
currentValue: '',
currentValue: this.props.initialText ?? '',
readOnly: false,
};

Expand Down Expand Up @@ -61,6 +63,7 @@ export class ShellInput extends Component<ShellInputProps, ShellInputState> {
}

private onChange = (value: string): void => {
this.props.onTextChange?.(value);
this.setState({ currentValue: value });
};

Expand Down
7 changes: 7 additions & 0 deletions packages/browser-repl/src/components/shell.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -516,4 +516,11 @@ describe('<Shell />', function () {
expect(wrapper.find('ShellInput').prop('prompt')).to.equal('abc>');
});
});

it('sets initial text for the shell input', function () {
wrapper = mount(
<Shell runtime={fakeRuntime} initialInput="db.coll.find({})" />
);
expect(wrapper.find('Editor').prop('value')).to.eq('db.coll.find({})');
});
});
32 changes: 29 additions & 3 deletions packages/browser-repl/src/components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ interface ShellProps {
*/
onHistoryChanged: (history: readonly string[]) => void;

/**
* A function called each time the text in the shell input is changed
*/
onInputChanged?: (input: string) => void;

/* If set, the shell will omit or redact entries containing sensitive
* info from history. Defaults to `false`.
*/
Expand All @@ -85,6 +90,16 @@ interface ShellProps {
*/
onOperationEnd: () => void;

/**
* Initial value in the shell input field
*/
initialInput?: string;

/**
* A set of input strings to evaluate right after shell is mounted
*/
initialEvaluate?: string | string[];

/* An array of entries to be displayed in the output area.
*
* Can be used to restore the output between sessions, or to setup
Expand Down Expand Up @@ -128,6 +143,7 @@ export class Shell extends Component<ShellProps, ShellState> {
onOutputChanged: noop,
maxOutputLength: 1000,
maxHistoryLength: 1000,
initialInput: '',
initialOutput: [],
initialHistory: [],
};
Expand All @@ -147,8 +163,16 @@ export class Shell extends Component<ShellProps, ShellState> {

componentDidMount(): void {
this.scrollToBottom();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.updateShellPrompt();
void this.updateShellPrompt().then(async () => {
if (this.props.initialEvaluate) {
const evalLines = Array.isArray(this.props.initialEvaluate)
? this.props.initialEvaluate
: [this.props.initialEvaluate];
for (const input of evalLines) {
await this.onInput(input);
}
}
});
}

componentDidUpdate(): void {
Expand Down Expand Up @@ -351,7 +375,7 @@ export class Shell extends Component<ShellProps, ShellState> {
this.editor = editor;
};

private focusEditor = (): void => {
focusEditor = (): void => {
this.editor?.focus();
};

Expand Down Expand Up @@ -379,6 +403,8 @@ export class Shell extends Component<ShellProps, ShellState> {

return (
<ShellInput
initialText={this.props.initialInput}
onTextChange={this.props.onInputChanged}
prompt={this.state.shellPrompt}
autocompleter={this.props.runtime}
history={this.state.history}
Expand Down
40 changes: 38 additions & 2 deletions packages/browser-repl/src/sandbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
const [redactInfo, setRedactInfo] = useState(false);
const [maxOutputLength, setMaxOutputLength] = useState(1000);
const [maxHistoryLength, setMaxHistoryLength] = useState(1000);
const [initialInput, setInitialInput] = useState('');
const [initialEvaluate, setInitialEvaluate] = useState<string[]>([]);
const [initialOutput] = useState<ShellOutputEntry[]>([
{ format: 'output', value: { foo: 1, bar: true, buz: function () {} } },
]);
Expand All @@ -171,8 +173,8 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
}, []);

const key = useMemo(() => {
return initialHistory.join('');
}, [initialHistory]);
return initialHistory.concat(initialInput, initialEvaluate).join('');
}, [initialHistory, initialInput, initialEvaluate]);

return (
<div className={sandboxContainer}>
Expand All @@ -183,6 +185,8 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
redactInfo={redactInfo}
maxOutputLength={maxOutputLength}
maxHistoryLength={maxHistoryLength}
initialInput={initialInput}
initialEvaluate={initialEvaluate.filter(Boolean)}
initialOutput={initialOutput}
initialHistory={initialHistory.filter(Boolean)}
/>
Expand Down Expand Up @@ -263,6 +267,38 @@ const IframeRuntimeExample: React.FunctionComponent = () => {
className={cx(textarea, textInput)}
/>
</FormFieldContainer>

<FormFieldContainer className={formField}>
<Label id="initialInputLabel" htmlFor="initialInput">
initialInput
</Label>
<Description>Initial value in the shell input field</Description>
<TextInput
className={textInput}
aria-labelledby="initialInputLabel"
value={initialInput}
onChange={(evt) => {
setInitialInput(evt.currentTarget.value);
}}
/>
</FormFieldContainer>

<FormFieldContainer className={formField}>
<Label id="initialEvaluateLabel" htmlFor="initialEvaluate">
initialEvaluate
</Label>
<Description>
A set of input strings to evaluate right after shell is mounted
</Description>
<TextArea
aria-labelledby="initialEvaluate"
value={initialEvaluate.join('\n')}
onChange={(evt) => {
setInitialEvaluate(evt.currentTarget.value.split('\n'));
}}
className={cx(textarea, textInput)}
/>
</FormFieldContainer>
</div>
</div>
);
Expand Down

0 comments on commit 48ba90f

Please sign in to comment.