jupyterlab_claude_code_extension 1.1.16 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/icons.d.ts +1 -0
- package/lib/icons.js +7 -0
- package/lib/widget.d.ts +7 -0
- package/lib/widget.js +37 -1
- package/package.json +1 -1
- package/src/icons.ts +9 -0
- package/src/widget.ts +38 -0
- package/style/base.css +5 -0
package/lib/icons.d.ts
CHANGED
package/lib/icons.js
CHANGED
|
@@ -49,3 +49,10 @@ export const shieldIcon = new LabIcon({
|
|
|
49
49
|
name: 'jupyterlab_claude_code_extension:shield',
|
|
50
50
|
svgstr: shieldSvgStr
|
|
51
51
|
});
|
|
52
|
+
const filterSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
|
|
53
|
+
<path class="jp-icon3" fill="#616161" d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
|
|
54
|
+
</svg>`;
|
|
55
|
+
export const filterIcon = new LabIcon({
|
|
56
|
+
name: 'jupyterlab_claude_code_extension:filter',
|
|
57
|
+
svgstr: filterSvgStr
|
|
58
|
+
});
|
package/lib/widget.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
|
|
|
16
16
|
protected onBeforeHide(_msg: Message): void;
|
|
17
17
|
protected onCloseRequest(msg: Message): void;
|
|
18
18
|
private _buildShell;
|
|
19
|
+
/** Show / hide the filter input. Hiding also clears the active filter
|
|
20
|
+
* so the user does not end up with an "invisible" filter narrowing
|
|
21
|
+
* the rows the next time they open the panel.
|
|
22
|
+
*/
|
|
23
|
+
private _toggleFilterBar;
|
|
19
24
|
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
20
25
|
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
21
26
|
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
|
@@ -85,6 +90,8 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
|
|
|
85
90
|
private readonly _serverSettings;
|
|
86
91
|
private _bodyEl;
|
|
87
92
|
private _refreshBtn;
|
|
93
|
+
private _filterBtn;
|
|
94
|
+
private _searchEl;
|
|
88
95
|
private _sessions;
|
|
89
96
|
private _expanded;
|
|
90
97
|
private _commands;
|
package/lib/widget.js
CHANGED
|
@@ -3,7 +3,7 @@ import { folderIcon, terminalIcon } from '@jupyterlab/ui-components';
|
|
|
3
3
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
4
|
import { Menu, Widget } from '@lumino/widgets';
|
|
5
5
|
import { requestAPI } from './request';
|
|
6
|
-
import { claudeIcon, refreshIcon, removeIcon, shieldIcon, starFilledIcon } from './icons';
|
|
6
|
+
import { claudeIcon, filterIcon, refreshIcon, removeIcon, shieldIcon, starFilledIcon } from './icons';
|
|
7
7
|
const POLL_INTERVAL_MS = 30000;
|
|
8
8
|
const DEFAULT_RECENT_LIMIT = 10;
|
|
9
9
|
const EXPANDED_STORAGE_KEY = 'jupyterlab_claude_code_extension:expanded';
|
|
@@ -59,6 +59,8 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
59
59
|
constructor(app, rootDir, terminalTracker = null) {
|
|
60
60
|
super();
|
|
61
61
|
this._refreshBtn = null;
|
|
62
|
+
this._filterBtn = null;
|
|
63
|
+
this._searchEl = null;
|
|
62
64
|
this._sessions = null;
|
|
63
65
|
this._expanded = loadExpanded();
|
|
64
66
|
this._activeSession = null;
|
|
@@ -137,6 +139,13 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
137
139
|
title.className = 'jp-ClaudeSessionsPanel-title';
|
|
138
140
|
title.textContent = 'Claude Code Sessions';
|
|
139
141
|
header.appendChild(title);
|
|
142
|
+
const filterBtn = document.createElement('button');
|
|
143
|
+
filterBtn.className = 'jp-ClaudeSessionsPanel-iconButton';
|
|
144
|
+
filterBtn.title = 'Filter sessions';
|
|
145
|
+
filterIcon.element({ container: filterBtn });
|
|
146
|
+
filterBtn.addEventListener('click', () => this._toggleFilterBar());
|
|
147
|
+
header.appendChild(filterBtn);
|
|
148
|
+
this._filterBtn = filterBtn;
|
|
140
149
|
const refreshBtn = document.createElement('button');
|
|
141
150
|
refreshBtn.className = 'jp-ClaudeSessionsPanel-iconButton';
|
|
142
151
|
refreshBtn.title = 'Refresh';
|
|
@@ -149,10 +158,15 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
149
158
|
search.className = 'jp-ClaudeSessionsPanel-search';
|
|
150
159
|
search.placeholder = 'Filter sessions...';
|
|
151
160
|
search.spellcheck = false;
|
|
161
|
+
// Hidden by default; the filter-icon button reveals it. Lumino's
|
|
162
|
+
// ``hidden`` attribute toggles ``display: none`` via the user-agent
|
|
163
|
+
// stylesheet so no extra CSS rule is needed.
|
|
164
|
+
search.hidden = true;
|
|
152
165
|
search.addEventListener('input', () => {
|
|
153
166
|
this._filter = search.value;
|
|
154
167
|
this._render();
|
|
155
168
|
});
|
|
169
|
+
this._searchEl = search;
|
|
156
170
|
const body = document.createElement('div');
|
|
157
171
|
body.className = 'jp-ClaudeSessionsPanel-body';
|
|
158
172
|
root.appendChild(header);
|
|
@@ -160,6 +174,28 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
160
174
|
root.appendChild(body);
|
|
161
175
|
this._bodyEl = body;
|
|
162
176
|
}
|
|
177
|
+
/** Show / hide the filter input. Hiding also clears the active filter
|
|
178
|
+
* so the user does not end up with an "invisible" filter narrowing
|
|
179
|
+
* the rows the next time they open the panel.
|
|
180
|
+
*/
|
|
181
|
+
_toggleFilterBar() {
|
|
182
|
+
if (!this._searchEl) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const show = this._searchEl.hidden;
|
|
186
|
+
this._searchEl.hidden = !show;
|
|
187
|
+
if (this._filterBtn) {
|
|
188
|
+
this._filterBtn.classList.toggle('jp-mod-active', show);
|
|
189
|
+
}
|
|
190
|
+
if (show) {
|
|
191
|
+
this._searchEl.focus();
|
|
192
|
+
}
|
|
193
|
+
else if (this._filter) {
|
|
194
|
+
this._filter = '';
|
|
195
|
+
this._searchEl.value = '';
|
|
196
|
+
this._render();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
163
199
|
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
164
200
|
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
165
201
|
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_claude_code_extension",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "Browse, resume, and manage your Claude Code CLI sessions from a JupyterLab side panel. One click reactivates the right terminal - no duplicate tabs, live remote-control indicator, and favourites for the projects you keep coming back to.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
package/src/icons.ts
CHANGED
|
@@ -59,3 +59,12 @@ export const shieldIcon = new LabIcon({
|
|
|
59
59
|
name: 'jupyterlab_claude_code_extension:shield',
|
|
60
60
|
svgstr: shieldSvgStr
|
|
61
61
|
});
|
|
62
|
+
|
|
63
|
+
const filterSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
|
|
64
|
+
<path class="jp-icon3" fill="#616161" d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
|
|
65
|
+
</svg>`;
|
|
66
|
+
|
|
67
|
+
export const filterIcon = new LabIcon({
|
|
68
|
+
name: 'jupyterlab_claude_code_extension:filter',
|
|
69
|
+
svgstr: filterSvgStr
|
|
70
|
+
});
|
package/src/widget.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { Message } from '@lumino/messaging';
|
|
|
15
15
|
import { requestAPI } from './request';
|
|
16
16
|
import {
|
|
17
17
|
claudeIcon,
|
|
18
|
+
filterIcon,
|
|
18
19
|
refreshIcon,
|
|
19
20
|
removeIcon,
|
|
20
21
|
shieldIcon,
|
|
@@ -183,6 +184,14 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
183
184
|
title.textContent = 'Claude Code Sessions';
|
|
184
185
|
header.appendChild(title);
|
|
185
186
|
|
|
187
|
+
const filterBtn = document.createElement('button');
|
|
188
|
+
filterBtn.className = 'jp-ClaudeSessionsPanel-iconButton';
|
|
189
|
+
filterBtn.title = 'Filter sessions';
|
|
190
|
+
filterIcon.element({ container: filterBtn });
|
|
191
|
+
filterBtn.addEventListener('click', () => this._toggleFilterBar());
|
|
192
|
+
header.appendChild(filterBtn);
|
|
193
|
+
this._filterBtn = filterBtn;
|
|
194
|
+
|
|
186
195
|
const refreshBtn = document.createElement('button');
|
|
187
196
|
refreshBtn.className = 'jp-ClaudeSessionsPanel-iconButton';
|
|
188
197
|
refreshBtn.title = 'Refresh';
|
|
@@ -196,10 +205,15 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
196
205
|
search.className = 'jp-ClaudeSessionsPanel-search';
|
|
197
206
|
search.placeholder = 'Filter sessions...';
|
|
198
207
|
search.spellcheck = false;
|
|
208
|
+
// Hidden by default; the filter-icon button reveals it. Lumino's
|
|
209
|
+
// ``hidden`` attribute toggles ``display: none`` via the user-agent
|
|
210
|
+
// stylesheet so no extra CSS rule is needed.
|
|
211
|
+
search.hidden = true;
|
|
199
212
|
search.addEventListener('input', () => {
|
|
200
213
|
this._filter = search.value;
|
|
201
214
|
this._render();
|
|
202
215
|
});
|
|
216
|
+
this._searchEl = search;
|
|
203
217
|
|
|
204
218
|
const body = document.createElement('div');
|
|
205
219
|
body.className = 'jp-ClaudeSessionsPanel-body';
|
|
@@ -211,6 +225,28 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
211
225
|
this._bodyEl = body;
|
|
212
226
|
}
|
|
213
227
|
|
|
228
|
+
/** Show / hide the filter input. Hiding also clears the active filter
|
|
229
|
+
* so the user does not end up with an "invisible" filter narrowing
|
|
230
|
+
* the rows the next time they open the panel.
|
|
231
|
+
*/
|
|
232
|
+
private _toggleFilterBar(): void {
|
|
233
|
+
if (!this._searchEl) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const show = this._searchEl.hidden;
|
|
237
|
+
this._searchEl.hidden = !show;
|
|
238
|
+
if (this._filterBtn) {
|
|
239
|
+
this._filterBtn.classList.toggle('jp-mod-active', show);
|
|
240
|
+
}
|
|
241
|
+
if (show) {
|
|
242
|
+
this._searchEl.focus();
|
|
243
|
+
} else if (this._filter) {
|
|
244
|
+
this._filter = '';
|
|
245
|
+
this._searchEl.value = '';
|
|
246
|
+
this._render();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
214
250
|
/** Normalise strings for filter comparison: NFD-decompose, strip combining
|
|
215
251
|
* diacritic marks, lowercase, and collapse separators (`-`, `_`, `.`, `/`,
|
|
216
252
|
* whitespace) entirely. So "foo-bar", "foo_bar", "foo bar", "Foo Bar" all
|
|
@@ -1062,6 +1098,8 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
1062
1098
|
private readonly _serverSettings: ServerConnection.ISettings;
|
|
1063
1099
|
private _bodyEl!: HTMLDivElement;
|
|
1064
1100
|
private _refreshBtn: HTMLButtonElement | null = null;
|
|
1101
|
+
private _filterBtn: HTMLButtonElement | null = null;
|
|
1102
|
+
private _searchEl: HTMLInputElement | null = null;
|
|
1065
1103
|
private _sessions: ISession[] | null = null;
|
|
1066
1104
|
private _expanded: Record<SectionKey, boolean> = loadExpanded();
|
|
1067
1105
|
private _commands!: CommandRegistry;
|
package/style/base.css
CHANGED
|
@@ -55,6 +55,11 @@
|
|
|
55
55
|
color: var(--jp-ui-font-color1);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
.jp-ClaudeSessionsPanel-iconButton.jp-mod-active {
|
|
59
|
+
background: var(--jp-layout-color3);
|
|
60
|
+
color: var(--jp-brand-color1);
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
.jp-ClaudeSessionsPanel-iconButton svg {
|
|
59
64
|
width: 14px;
|
|
60
65
|
height: 14px;
|