Skip to content

Commit 6154a5d

Browse files
committed
Add a completion status in the status bar
1 parent b743650 commit 6154a5d

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@jupyterlab/rendermime": "^4.4.6",
7272
"@jupyterlab/services": "^7.4.6",
7373
"@jupyterlab/settingregistry": "^4.0.0",
74+
"@jupyterlab/statusbar": "^4.4.6",
7475
"@jupyterlab/ui-components": "^4.4.6",
7576
"@lumino/commands": "^2.3.2",
7677
"@lumino/coreutils": "^2.2.1",
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { AISettingsModel } from '../models/settings-model';
3+
import { ReactWidget } from '@jupyterlab/ui-components';
4+
import { jupyternautIcon } from '../icons';
5+
6+
const STATUS_DISABLED_CLASS = 'jp-ai-status-completion-disabled';
7+
8+
/**
9+
* The completion status props.
10+
*/
11+
interface ICompletionStatusProps {
12+
/**
13+
* The settings model.
14+
*/
15+
settingsModel: AISettingsModel;
16+
}
17+
18+
/**
19+
* The completion status component.
20+
*/
21+
function CompletionStatus(props: ICompletionStatusProps): JSX.Element {
22+
const [disabled, setDisabled] = useState<boolean>(true);
23+
const [title, setTitle] = useState<string>('');
24+
25+
/**
26+
* Handle changes in the settings.
27+
*/
28+
useEffect(() => {
29+
const stateChanged = (model: AISettingsModel) => {
30+
if (model.config.useSameProviderForChatAndCompleter) {
31+
setDisabled(false);
32+
setTitle(`Completion using ${model.getDefaultProvider()?.model}`);
33+
} else if (model.config.activeCompleterProvider) {
34+
setDisabled(false);
35+
setTitle(
36+
`Completion using ${model.getProvider(model.config.activeCompleterProvider)?.model}`
37+
);
38+
} else {
39+
setDisabled(true);
40+
setTitle('No completion');
41+
}
42+
};
43+
44+
props.settingsModel.stateChanged.connect(stateChanged);
45+
46+
stateChanged(props.settingsModel);
47+
return () => {
48+
props.settingsModel.stateChanged.disconnect(stateChanged);
49+
};
50+
}, [props.settingsModel]);
51+
52+
return (
53+
<jupyternautIcon.react
54+
className={disabled ? STATUS_DISABLED_CLASS : ''}
55+
top={'2px'}
56+
width={'16px'}
57+
stylesheet={'statusBar'}
58+
title={title}
59+
/>
60+
);
61+
}
62+
63+
/**
64+
* The completion status widget that will be added to the status bar.
65+
*/
66+
export class CompletionStatusWidget extends ReactWidget {
67+
constructor(options: ICompletionStatusProps) {
68+
super();
69+
this._props = options;
70+
}
71+
72+
render(): JSX.Element {
73+
return <CompletionStatus {...this._props} />;
74+
}
75+
76+
private _props: ICompletionStatusProps;
77+
}

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './clear-button';
2+
export * from './completion-status';
23
export * from './model-select';
34
export * from './stop-button';
45
export * from './token-usage-display';

src/index.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import { IKernelSpecManager, KernelSpec } from '@jupyterlab/services';
3636

3737
import { ISettingRegistry } from '@jupyterlab/settingregistry';
3838

39+
import { IStatusBar } from '@jupyterlab/statusbar';
40+
3941
import {
4042
settingsIcon,
4143
Toolbar,
@@ -83,6 +85,7 @@ import {
8385
createModelSelectItem,
8486
createToolSelectItem,
8587
stopItem,
88+
CompletionStatusWidget,
8689
TokenUsageWidget
8790
} from './components';
8891

@@ -930,6 +933,25 @@ const inputToolbarFactory: JupyterFrontEndPlugin<IInputToolbarRegistryFactory> =
930933
}
931934
};
932935

936+
const completionStatus: JupyterFrontEndPlugin<void> = {
937+
id: '@jupyterlite/ai:completion status',
938+
description: 'The completion status displayed in the status bar',
939+
autoStart: true,
940+
requires: [IAISettingsModel, IStatusBar],
941+
activate: (
942+
app: JupyterFrontEnd,
943+
settingsModel: AISettingsModel,
944+
statusBar: IStatusBar,
945+
) => {
946+
const div = document.createElement('div');
947+
div.style.width = '50px';
948+
div.style.height = '100%';
949+
div.style.backgroundColor = 'red';
950+
const item = new CompletionStatusWidget({ settingsModel });
951+
statusBar.registerStatusItem('completionState', { item , align: 'right', rank: 10 });
952+
}
953+
};
954+
933955
export default [
934956
providerRegistryPlugin,
935957
anthropicProviderPlugin,
@@ -944,7 +966,8 @@ export default [
944966
plugin,
945967
toolRegistry,
946968
agentManagerFactory,
947-
inputToolbarFactory
969+
inputToolbarFactory,
970+
completionStatus
948971
];
949972

950973
// Export extension points for other extensions to use

style/base.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,12 @@
379379
stroke: var(--jp-inverse-layout-color3);
380380
stroke-width: 2;
381381
}
382+
383+
/* Disabled color for the completion status */
384+
.jp-ai-status-completion-disabled circle {
385+
fill: var(--jp-layout-color3);
386+
}
387+
388+
.jp-ai-status-completion-disabled path {
389+
fill: var(--jp-layout-color2);
390+
}

yarn.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2905,7 +2905,7 @@ __metadata:
29052905
languageName: node
29062906
linkType: hard
29072907

2908-
"@jupyterlab/statusbar@npm:^4.4.7":
2908+
"@jupyterlab/statusbar@npm:^4.4.6, @jupyterlab/statusbar@npm:^4.4.7":
29092909
version: 4.4.7
29102910
resolution: "@jupyterlab/statusbar@npm:4.4.7"
29112911
dependencies:
@@ -3046,6 +3046,7 @@ __metadata:
30463046
"@jupyterlab/rendermime": ^4.4.6
30473047
"@jupyterlab/services": ^7.4.6
30483048
"@jupyterlab/settingregistry": ^4.0.0
3049+
"@jupyterlab/statusbar": ^4.4.6
30493050
"@jupyterlab/testutils": ^4.0.0
30503051
"@jupyterlab/ui-components": ^4.4.6
30513052
"@lumino/commands": ^2.3.2

0 commit comments

Comments
 (0)