Skip to content

Commit c84890e

Browse files
authored
Redesign WebSocket status bar: student-friendly by default, diagnostics in developer mode (#328)
Gate the WebSocket status bar on artemis.developerMode (removes the artemis.showWebSocketStatusBar setting): plain-language label and help tooltip for students, technical label and full diagnostics for developers, live re-render on developerMode toggle, click resets and reconnects. Closes #320
1 parent 1b491f9 commit c84890e

7 files changed

Lines changed: 485 additions & 97 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to the Artemis VS Code extension will be documented in this
44

55
## [Unreleased]
66

7+
### Changed
8+
9+
- **WebSocket status bar:** Removed the `artemis.showWebSocketStatusBar` setting. The connection indicator now appears automatically only when there is a problem; enable `artemis.developerMode` to keep it always visible with full diagnostics on hover. When the connection drops, students now see a plain-language explanation (no "WS" jargon) instead of a technical label.
10+
711
## [0.4.8] - 2026-06-24
812

913
### Changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ Configure the extension through VS Code settings (`Cmd+,` or `Ctrl+,`):
103103
- `artemis.showSetDefaultClonePathPrompt` - Ask to set a default clone folder on first clone
104104
- `artemis.startPage` - Which page to show after logging in
105105
- `artemis.showStartPageSuggestion` - Suggest configuring the start page when an exercise is detected
106-
- `artemis.showWebSocketStatusBar` - Show the WebSocket connection status in the status bar
107-
- `artemis.developerMode` - Enable developer mode (debug tools and extra diagnostics)
106+
- `artemis.developerMode` - Enable developer mode (debug tools, extra diagnostics, and an always-visible WebSocket status indicator)
108107

109108
## About Artemis
110109

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# WebSocket Status Bar Button Redesign
2+
3+
**Issue:** #320 — Re-evaluate: does the WebSocket status-bar item need the `artemis.showWebSocketStatusBar` setting?
4+
**Date:** 2026-06-24
5+
**Branch:** `worktree-ws-statusbar-dev-hover` (off `dev`)
6+
**Status:** Approved design, pending implementation plan
7+
8+
## Context
9+
10+
The WebSocket connection-status item in the status bar
11+
(`extension/src/extension/services/websocket/websocketStatusBar.ts`,
12+
`WebSocketStatusBarService`) is currently gated by a user setting
13+
`artemis.showWebSocketStatusBar` (boolean, default `false`).
14+
15+
Today's behavior:
16+
- On disconnect / reconnecting → item is **always shown** (red/yellow), setting ignored.
17+
- During connected operation → shown **only** when `showWebSocketStatusBar` is `true`.
18+
- Logged out → hidden unless the setting is `true`.
19+
- After reconnection with the setting off → 2s flash, then hidden.
20+
- Tooltip: a plain one-line string. Click: reset + reconnect (no-op while connecting/reconnecting).
21+
22+
A previous, richer version (commit `ec5f6d0d`, before a 588→165 line simplification)
23+
had a Markdown hover tooltip with full debug info and a QuickPick action menu. That
24+
was stripped out. This redesign brings back a focused, audience-aware version of the
25+
hover info and resolves #320.
26+
27+
#320 asks whether the dedicated setting earns its place. The genuinely useful signal
28+
(a connection problem) already surfaces automatically, independent of the setting. The
29+
only thing the setting adds is a permanent "connected" indicator during normal
30+
operation — niche, defaults off, and arguably clutter for students.
31+
32+
## Goals
33+
34+
- Remove the `artemis.showWebSocketStatusBar` configuration knob (resolves #320 as "remove").
35+
- Fold "always show the item" into the existing `artemis.developerMode` setting, which
36+
already governs status-bar diagnostics (e.g. the live struggle-detection score).
37+
- Give students a clear, plain-language explanation when the connection fails (the only
38+
moment a non-developer sees the item).
39+
- Give developers full WebSocket diagnostics on hover.
40+
41+
## Non-Goals
42+
43+
- No change to the click action (stays reset + reconnect).
44+
- No QuickPick / action-menu (Disconnect / Reset / Copy debug) — low value for a niche
45+
diagnostic, not worth the surface. Reconnect is the one in-context action and is the click.
46+
- No auth diagnostics (Cookie / JWT presence) in the dev hover — `getDiagnostics()` does
47+
not expose them today and they are not needed now (YAGNI). Can be added later if a
48+
real debugging need arises.
49+
50+
## Design
51+
52+
### 1. Visibility
53+
54+
`developerMode` replaces `showWebSocketStatusBar` 1:1 in the visibility logic:
55+
56+
- **developerMode ON** → item always visible (including the connected steady state, and
57+
while logged out — diagnostics).
58+
- **developerMode OFF** → visible only on problems (`disconnected` / `reconnecting`),
59+
plus the existing 2s flash after a successful reconnect; otherwise hidden. Logged out → hidden.
60+
61+
The "always show on problems" override and the logged-out gate are unchanged in shape;
62+
only the gating field switches from `_showStatusBar` to a developer-mode flag.
63+
64+
### 2. Button text (mode-dependent)
65+
66+
| State | Normal (student) | Developer |
67+
|-------|------------------|-----------|
68+
| connected | `$(plug) Artemis: connected` | `$(plug) WS Connected` |
69+
| connecting | `$(sync~spin) Artemis: connecting…` | `$(sync~spin) WS Connecting…` |
70+
| reconnecting | `$(sync~spin) Artemis: reconnecting (3/20)…` | `$(sync~spin) WS Reconnecting (3/20)…` |
71+
| disconnected | `$(debug-disconnect) Artemis: offline` | `$(debug-disconnect) WS Disconnected` |
72+
73+
Background colors unchanged: error (red) when disconnected, warning (yellow) when reconnecting.
74+
75+
### 3. Hover (tooltip) — three tiers
76+
77+
- **Normal + connected:** simple one-liner (e.g. "Connected to Artemis. Click to reconnect.").
78+
Rarely seen, since the item is hidden when connected in normal mode.
79+
- **Normal + reconnecting:**
80+
> **Reconnecting to Artemis… (3/20)**
81+
> Live updates are paused and will resume automatically.
82+
- **Normal + disconnected:**
83+
> **Connection to Artemis lost**
84+
> Live updates (build results, submission status, Iris) are paused.
85+
> Click to reconnect. If it keeps failing, check your internet connection or sign in again.
86+
- **Developer (all states):** rich `MarkdownString` built from
87+
`ArtemisWebsocketService.getDiagnostics()`:
88+
status, `clientConnected` / `clientActive`, reconnect `(attempts/max)`,
89+
`subscriptionCount` + subscription topics, `sessionId`, `serverUrl`, `websocketUrl`.
90+
91+
### 4. Click action
92+
93+
Unchanged: `resetConnectionState()` + `connect()`, no-op while `connecting` / `reconnecting`.
94+
Same in both modes.
95+
96+
### 5. Setting removal (#320)
97+
98+
Remove `artemis.showWebSocketStatusBar` everywhere:
99+
- `extension/package.json``contributes.configuration` entry (~line 179).
100+
- `extension/src/extension/utils/constants.ts``SHOW_WEBSOCKET_STATUS_BAR_KEY` (line 37).
101+
- `README.md` — the bullet listing the setting (line 106).
102+
- `websocketStatusBar.ts``_showStatusBar`, `_updateVisibilitySetting`, and the
103+
config-change listener; switch the listener to watch `DEVELOPER_MODE_KEY`.
104+
- `CHANGELOG.md` — new entry under `## [Unreleased]` (do not rename that heading).
105+
106+
CHANGELOG history (lines mentioning the setting in past releases) is left untouched.
107+
108+
## Affected Files
109+
110+
| File | Change |
111+
|------|--------|
112+
| `extension/src/extension/services/websocket/websocketStatusBar.ts` | Swap setting→developerMode; mode-dependent text; three-tier tooltip incl. dev diagnostics |
113+
| `extension/src/extension/utils/constants.ts` | Remove `SHOW_WEBSOCKET_STATUS_BAR_KEY` |
114+
| `extension/package.json` | Remove `artemis.showWebSocketStatusBar` config contribution |
115+
| `README.md` | Remove the setting's documentation bullet |
116+
| `CHANGELOG.md` | Add `[Unreleased]` entry |
117+
| `extension/test/unit/services/websocketStatusBar.test.ts` | Re-point setting tests to `developerMode`; add new tests |
118+
119+
No change required to `ArtemisWebsocketService``getDiagnostics()` already provides the
120+
data for the dev hover.
121+
122+
## Testing
123+
124+
`extension/test/unit/services/websocketStatusBar.test.ts` (mocha/vscode-test):
125+
126+
- Re-point existing `showWebSocketStatusBar`-based visibility tests to `developerMode`.
127+
- Keep: always-shown-on-problem, 2s reconnect flash, auth-gate, dispose tests.
128+
- Add:
129+
- developerMode ON → item visible while connected (and while logged out).
130+
- Dev hover tooltip contains diagnostics (e.g. `serverUrl`, subscription count).
131+
- Normal-mode button text uses plain-language labels ("Artemis: offline", etc.).
132+
- Normal-mode disconnected/reconnecting tooltip contains the friendly explanation.
133+
134+
All `extension/` checks must pass before completion: `npm test`, `npm run lint`,
135+
`npm run check-types` (tsc --noEmit catches unused locals that lint misses).
136+
137+
## Open Decisions
138+
139+
- **Auth diagnostics in dev hover:** OUT (YAGNI). Revisit only on a concrete need.
140+
141+
## Out of Scope / Future
142+
143+
- QuickPick action menu (Disconnect / Reset / Copy debug / Show debug doc).
144+
- Clickable command links inside the hover tooltip.
145+
- Exposing auth (Cookie/JWT) state via `getDiagnostics()`.

extension/package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "iris-thaumantias",
33
"displayName": "Artemis - TUM",
44
"description": "Artemis brings interactive learning to life with instant, individual feedback on programming exercises, quizzes, modeling tasks, and more. This VS Code extension integrates Iris, an LLM-based virtual assistant that supports students with instant answers about exercises, lectures, and learning performance. Iris provides context-aware, personalized assistance for programming exercises, encouraging independent problem-solving through subtle hints and guiding questions instead of giving full solutions.",
5-
"version": "0.4.8",
5+
"version": "0.4.9-dev",
66
"publisher": "aet-tum",
77
"license": "MIT",
88
"icon": "media/artemis-blue.png",
@@ -174,12 +174,7 @@
174174
"artemis.developerMode": {
175175
"type": "boolean",
176176
"default": false,
177-
"markdownDescription": "Enable developer mode to show debugging tools, including debug buttons in views and live struggle detection score in the status bar."
178-
},
179-
"artemis.showWebSocketStatusBar": {
180-
"type": "boolean",
181-
"default": false,
182-
"description": "Show the WebSocket connection status in the status bar during normal operation. When a connection failure occurs, the status bar item is always shown regardless of this setting."
177+
"markdownDescription": "Enable developer mode to show debugging tools, including debug buttons in views, the live struggle detection score, and the WebSocket connection status (with diagnostics on hover) in the status bar."
183178
},
184179
"artemis.defaultCommitMessage": {
185180
"type": "string",

extension/src/extension/services/websocket/websocketStatusBar.ts

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,23 @@ import { ArtemisWebsocketService } from './artemisWebsocketService';
1111
* StatusBar item showing WebSocket connection status.
1212
*
1313
* Visibility rules:
14-
* - When logged out: hidden unless `artemis.showWebSocketStatusBar` is true
15-
* (no WebSocket exists, so the default "needs attention on disconnect" rule
16-
* would surface a misleading red error indicator)
17-
* - When logged in:
18-
* - ALWAYS shown when disconnected or reconnecting
19-
* - Otherwise shown only when `artemis.showWebSocketStatusBar` is true
20-
* - After reconnection with setting off: 2s flash then hidden
14+
* - developerMode ON: always shown (any state, including connected and while
15+
* logged out) — diagnostics.
16+
* - developerMode OFF:
17+
* - shown when disconnected or reconnecting (a problem the user can act on)
18+
* - 2s flash after a successful reconnect, then hidden
19+
* - otherwise hidden (incl. logged out)
2120
*
22-
* Auth state is supplied externally via {@link setAuthenticated}; the service
23-
* does not own auth lifecycle.
24-
*
25-
* Click action: always reconnect (reset + connect). No-op while connecting.
21+
* Auth state is supplied externally via {@link setAuthenticated}.
22+
* Click action: reset + reconnect. No-op while connecting/reconnecting.
2623
*/
2724
export class WebSocketStatusBarService implements vscode.Disposable {
2825
private readonly _statusBarItem: vscode.StatusBarItem;
2926
private readonly _websocketService: ArtemisWebsocketService;
3027
private readonly _disposables: vscode.Disposable[] = [];
3128
private _stateSubscription?: vscode.Disposable;
3229
private _currentStatus: WebSocketDisplayStatus = 'disconnected';
33-
private _showStatusBar = false;
30+
private _isDevMode = false;
3431
private _isAuthenticated = false;
3532
private _reconnectHideTimeout?: ReturnType<typeof setTimeout>;
3633

@@ -56,7 +53,7 @@ export class WebSocketStatusBarService implements vscode.Disposable {
5653

5754
this._disposables.push(
5855
vscode.workspace.onDidChangeConfiguration(event => {
59-
if (event.affectsConfiguration(`${VSCODE_CONFIG.ARTEMIS_SECTION}.${VSCODE_CONFIG.SHOW_WEBSOCKET_STATUS_BAR_KEY}`)) {
56+
if (event.affectsConfiguration(`${VSCODE_CONFIG.ARTEMIS_SECTION}.${VSCODE_CONFIG.DEVELOPER_MODE_KEY}`)) {
6057
this._updateVisibilitySetting();
6158
}
6259
})
@@ -71,8 +68,8 @@ export class WebSocketStatusBarService implements vscode.Disposable {
7168

7269
private _updateVisibilitySetting(): void {
7370
const config = vscode.workspace.getConfiguration(VSCODE_CONFIG.ARTEMIS_SECTION);
74-
this._showStatusBar = config.get<boolean>(VSCODE_CONFIG.SHOW_WEBSOCKET_STATUS_BAR_KEY, false);
75-
this._applyVisibility();
71+
this._isDevMode = config.get<boolean>(VSCODE_CONFIG.DEVELOPER_MODE_KEY, false);
72+
this._updateStatusBarItem();
7673
}
7774

7875
private _refreshStatus(): void {
@@ -82,7 +79,7 @@ export class WebSocketStatusBarService implements vscode.Disposable {
8279
if (
8380
this._currentStatus === 'connected'
8481
&& previousStatus === 'reconnecting'
85-
&& !this._showStatusBar
82+
&& !this._isDevMode
8683
) {
8784
if (this._reconnectHideTimeout) {
8885
clearTimeout(this._reconnectHideTimeout);
@@ -110,10 +107,8 @@ export class WebSocketStatusBarService implements vscode.Disposable {
110107
}
111108

112109
private _applyVisibility(): void {
113-
// Logged out: there is no WebSocket to surface a state for. Honor the
114-
// explicit "always show" setting for diagnostics, otherwise hide.
115110
if (!this._isAuthenticated) {
116-
if (this._showStatusBar) {
111+
if (this._isDevMode) {
117112
this._statusBarItem.show();
118113
} else {
119114
this._statusBarItem.hide();
@@ -127,7 +122,7 @@ export class WebSocketStatusBarService implements vscode.Disposable {
127122

128123
if (needsAttention) {
129124
this._statusBarItem.show();
130-
} else if (this._showStatusBar) {
125+
} else if (this._isDevMode) {
131126
this._statusBarItem.show();
132127
} else if (this._reconnectHideTimeout) {
133128
this._statusBarItem.show();
@@ -139,31 +134,89 @@ export class WebSocketStatusBarService implements vscode.Disposable {
139134
private _updateStatusBarItem(): void {
140135
this._applyVisibility();
141136

137+
const attempts = this._websocketService.reconnectAttempts;
138+
142139
switch (this._currentStatus) {
143140
case 'connected':
144-
this._statusBarItem.text = '$(plug) WS Connected';
145-
this._statusBarItem.tooltip = 'WebSocket connected. Click to reconnect.';
141+
this._statusBarItem.text = this._isDevMode
142+
? '$(plug) WS Connected'
143+
: '$(plug) Artemis: connected';
146144
this._statusBarItem.backgroundColor = undefined;
147145
break;
148-
case 'reconnecting': {
149-
const attempts = this._websocketService.reconnectAttempts;
150-
this._statusBarItem.text = `$(sync~spin) Reconnecting (${attempts}/20)...`;
151-
this._statusBarItem.tooltip = 'WebSocket reconnecting...';
146+
case 'reconnecting':
147+
this._statusBarItem.text = this._isDevMode
148+
? `$(sync~spin) WS Reconnecting (${attempts}/20)...`
149+
: `$(sync~spin) Artemis: reconnecting (${attempts}/20)...`;
152150
this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
153151
break;
154-
}
155152
case 'connecting':
156-
this._statusBarItem.text = '$(sync~spin) WS Connecting...';
157-
this._statusBarItem.tooltip = 'WebSocket connecting...';
153+
this._statusBarItem.text = this._isDevMode
154+
? '$(sync~spin) WS Connecting...'
155+
: '$(sync~spin) Artemis: connecting...';
158156
this._statusBarItem.backgroundColor = undefined;
159157
break;
160158
case 'disconnected':
161159
default:
162-
this._statusBarItem.text = '$(debug-disconnect) WS Disconnected';
163-
this._statusBarItem.tooltip = 'WebSocket disconnected. Click to reconnect.';
160+
this._statusBarItem.text = this._isDevMode
161+
? '$(debug-disconnect) WS Disconnected'
162+
: '$(debug-disconnect) Artemis: offline';
164163
this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground');
165164
break;
166165
}
166+
167+
this._statusBarItem.tooltip = this._buildTooltip();
168+
}
169+
170+
private _buildTooltip(): string | vscode.MarkdownString {
171+
if (this._isDevMode) {
172+
return this._buildDevTooltip();
173+
}
174+
switch (this._currentStatus) {
175+
case 'reconnecting': {
176+
const md = new vscode.MarkdownString();
177+
const attempts = this._websocketService.reconnectAttempts;
178+
md.appendMarkdown(
179+
`**Reconnecting to Artemis... (${attempts}/20)**\n\n`
180+
+ `Live updates are paused and will resume automatically.`
181+
);
182+
return md;
183+
}
184+
case 'disconnected': {
185+
const md = new vscode.MarkdownString();
186+
md.appendMarkdown(
187+
`**Connection to Artemis lost**\n\n`
188+
+ `Live updates (build results, submission status, Iris) are paused.\n\n`
189+
+ `Click to reconnect. If it keeps failing, check your internet connection or sign in again.`
190+
);
191+
return md;
192+
}
193+
case 'connecting':
194+
return 'Connecting to Artemis...';
195+
case 'connected':
196+
default:
197+
return 'Connected to Artemis. Click to reconnect.';
198+
}
199+
}
200+
201+
private _buildDevTooltip(): vscode.MarkdownString {
202+
const d = this._websocketService.getDiagnostics();
203+
const md = new vscode.MarkdownString();
204+
md.appendMarkdown(`## WebSocket (dev)\n\n`);
205+
md.appendMarkdown(`**Status:** ${this._currentStatus}\n\n`);
206+
md.appendMarkdown(`**Connection:**\n`);
207+
md.appendMarkdown(`- clientConnected: ${d.clientConnected}\n`);
208+
md.appendMarkdown(`- clientActive: ${d.clientActive}\n`);
209+
md.appendMarkdown(`- reconnect: ${d.reconnectAttempts}/${d.maxReconnectAttempts}\n\n`);
210+
md.appendMarkdown(`**Subscriptions (${d.subscriptionCount}):**\n`);
211+
if (d.subscriptions.length > 0) {
212+
d.subscriptions.forEach(s => md.appendMarkdown(`- \`${s}\`\n`));
213+
} else {
214+
md.appendMarkdown(`- *none*\n`);
215+
}
216+
md.appendMarkdown(`\n**Session:** \`${d.sessionId}\`\n\n`);
217+
md.appendMarkdown(`**Server:** \`${d.serverUrl}\`\n\n`);
218+
md.appendMarkdown(`**WebSocket:** \`${d.websocketUrl}\`\n`);
219+
return md;
167220
}
168221

169222
private _clickInFlight = false;

extension/src/extension/utils/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ export const VSCODE_CONFIG = {
3434
DEFAULT_CLONE_PATH_KEY: 'defaultClonePath',
3535
SHOW_SET_DEFAULT_CLONE_PATH_PROMPT_KEY: 'showSetDefaultClonePathPrompt',
3636
DEVELOPER_MODE_KEY: 'developerMode',
37-
SHOW_WEBSOCKET_STATUS_BAR_KEY: 'showWebSocketStatusBar',
3837
START_PAGE_KEY: 'startPage',
3938
SHOW_START_PAGE_SUGGESTION_KEY: 'showStartPageSuggestion',
4039
DATA_COLLECTION_CONSENT_KEY: 'dataCollectionConsent',

0 commit comments

Comments
 (0)