Skip to content

Commit d09cc6e

Browse files
committed
Fix regression bug in ActivityItemPrompt handling
1 parent e9a52b9 commit d09cc6e

2 files changed

Lines changed: 67 additions & 9 deletions

File tree

src/vs/workbench/contrib/positronConsole/browser/components/activityPrompt.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import './activityPrompt.css';
88

99
// React.
10-
import { KeyboardEvent, useCallback, useEffect, useRef } from 'react';
10+
import { KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react';
1111

1212
// Other dependencies.
1313
import { Emitter } from '../../../../../base/common/event.js';
@@ -61,9 +61,31 @@ export const ActivityPrompt = (props: ActivityPromptProps) => {
6161
const editorContainerRef = useRef<HTMLDivElement>(null);
6262
const editorRef = useRef<CodeEditorWidget | null>(null);
6363

64-
// Whether to use the password input (HTML input) or the editor (CodeEditorWidget).
64+
// State hooks.
65+
const [state, setState] = useState(props.activityItemPrompt.state);
66+
67+
// State change useEffect. Subscribes to prompt state changes and updates local state to trigger re-render.
68+
useEffect(() => {
69+
// Create a disposable store for the prompt state change subscription, and clean it up on unmount or when the prompt changes.
70+
const disposableStore = new DisposableStore();
71+
72+
// Subscribe to prompt state changes and update local state to trigger re-render.
73+
disposableStore.add(props.activityItemPrompt.onStateChanged(() => {
74+
setState(props.activityItemPrompt.state);
75+
}));
76+
77+
// Re-sync in case the state changed between render and this effect running.
78+
setState(props.activityItemPrompt.state);
79+
80+
// Clean up subscription on unmount or when prompt changes.
81+
return () => disposableStore.dispose();
82+
}, [props.activityItemPrompt]);
83+
84+
// A value that indicates whether to use the password input (HTML input) or the editor (CodeEditorWidget).
6585
const isPassword = props.activityItemPrompt.password;
66-
const isUnanswered = props.activityItemPrompt.state === ActivityItemPromptState.Unanswered;
86+
87+
// A value that indicates whether the prompt is currently unanswered.
88+
const isUnanswered = state === ActivityItemPromptState.Unanswered;
6789

6890
/**
6991
* Focuses the appropriate input element.
@@ -312,7 +334,7 @@ export const ActivityPrompt = (props: ActivityPromptProps) => {
312334

313335
// Determine what to render based on prompt state.
314336
let prompt;
315-
switch (props.activityItemPrompt.state) {
337+
switch (state) {
316338
// When the prompt is unanswered, render the appropriate input.
317339
case ActivityItemPromptState.Unanswered:
318340
if (isPassword) {

src/vs/workbench/services/positronConsole/browser/classes/activityItemPrompt.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/*---------------------------------------------------------------------------------------------
2-
* Copyright (C) 2023-2025 Posit Software, PBC. All rights reserved.
2+
* Copyright (C) 2023-2026 Posit Software, PBC. All rights reserved.
33
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { Emitter } from '../../../../../base/common/event.js';
67
import { ActivityItem, TrimScrollbackResult } from './activityItem.js';
78
import { formatOutputLinesForClipboard } from '../utils/clipboardUtils.js';
89
import { ANSIOutput, ANSIOutputLine } from '../../../../../base/common/ansiOutput.js';
@@ -20,17 +21,43 @@ export const enum ActivityItemPromptState {
2021
* ActivityItemPrompt class.
2122
*/
2223
export class ActivityItemPrompt extends ActivityItem {
24+
//#region Private Properties
25+
26+
/**
27+
* The state of the prompt.
28+
*/
29+
private _state = ActivityItemPromptState.Unanswered;
30+
31+
/**
32+
* An emitter that fires when the state of the prompt changes.
33+
*/
34+
private readonly _onStateChangedEmitter = new Emitter<void>();
35+
36+
//#endregion Private Properties
37+
2338
//#region Public Properties
2439

2540
/**
26-
* Gets the output lines.
41+
* Gets the state.
2742
*/
28-
readonly outputLines: readonly ANSIOutputLine[];
43+
get state() {
44+
return this._state;
45+
}
2946

3047
/**
31-
* Gets or sets the state.
48+
* Sets the state.
3249
*/
33-
state = ActivityItemPromptState.Unanswered;
50+
set state(state: ActivityItemPromptState) {
51+
if (state !== this._state) {
52+
this._state = state;
53+
this._onStateChangedEmitter.fire();
54+
}
55+
}
56+
57+
/**
58+
* Gets the output lines.
59+
*/
60+
readonly outputLines: readonly ANSIOutputLine[];
3461

3562
/**
3663
* Gets or sets the answer.
@@ -39,6 +66,15 @@ export class ActivityItemPrompt extends ActivityItem {
3966

4067
//#endregion Public Properties
4168

69+
//#region Public Events
70+
71+
/**
72+
* An event that fires when the state changes.
73+
*/
74+
public onStateChanged = this._onStateChangedEmitter.event;
75+
76+
//#endregion Public Events
77+
4278
//#region Constructor
4379

4480
/**

0 commit comments

Comments
 (0)