Skip to content

Commit 282cb6d

Browse files
authored
Improve signal lifecycle (#1009)
Use the filebrowser tracker everywhere
1 parent 4bc8099 commit 282cb6d

File tree

7 files changed

+87
-44
lines changed

7 files changed

+87
-44
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@
9191
"@types/jest": "^26.0.0",
9292
"@types/react": "^17.0.0",
9393
"@types/react-dom": "^17.0.0",
94-
"@types/react-textarea-autosize": "^4.3.5",
9594
"@types/react-virtualized-auto-sizer": "^1.0.0",
9695
"@types/react-window": "^1.8.2",
9796
"@typescript-eslint/eslint-plugin": "^4.13.0",

src/commandsAndMenu.tsx

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import {
1010
WidgetTracker
1111
} from '@jupyterlab/apputils';
1212
import { PathExt, URLExt } from '@jupyterlab/coreutils';
13-
import { FileBrowser, FileBrowserModel } from '@jupyterlab/filebrowser';
14-
import { Contents } from '@jupyterlab/services';
13+
import { FileBrowser } from '@jupyterlab/filebrowser';
14+
import { Contents, ContentsManager } from '@jupyterlab/services';
1515
import { ISettingRegistry } from '@jupyterlab/settingregistry';
1616
import { ITerminal } from '@jupyterlab/terminal';
1717
import { TranslationBundle } from '@jupyterlab/translation';
@@ -101,7 +101,7 @@ function pluralizedContextLabel(singular: string, plural: string) {
101101
export function addCommands(
102102
app: JupyterFrontEnd,
103103
gitModel: GitExtension,
104-
fileBrowserModel: FileBrowserModel,
104+
browserTracker: WidgetTracker<FileBrowser>,
105105
settings: ISettingRegistry.ISettings,
106106
trans: TranslationBundle
107107
): void {
@@ -178,7 +178,7 @@ export function addCommands(
178178
'Create an empty Git repository or reinitialize an existing one'
179179
),
180180
execute: async () => {
181-
const currentPath = fileBrowserModel.path;
181+
const currentPath = browserTracker.currentWidget.model.path;
182182
const result = await showDialog({
183183
title: trans.__('Initialize a Repository'),
184184
body: trans.__('Do you really want to make this directory a Git Repo?'),
@@ -311,14 +311,14 @@ export function addCommands(
311311
gitModel,
312312
Operation.Clone,
313313
trans,
314-
{ path: fileBrowserModel.path, url: result.value }
314+
{ path: browserTracker.currentWidget.model.path, url: result.value }
315315
);
316316
logger.log({
317317
message: trans.__('Successfully cloned'),
318318
level: Level.SUCCESS,
319319
details
320320
});
321-
await fileBrowserModel.refresh();
321+
await browserTracker.currentWidget.model.refresh();
322322
} catch (error) {
323323
console.error(
324324
'Encountered an error when cloning the repository. Error: ',
@@ -483,8 +483,13 @@ export function addCommands(
483483
refreshButton.hide();
484484
diffWidget.toolbar.addItem('refresh', refreshButton);
485485

486-
model.changed.connect(() => {
486+
const refresh = () => {
487487
refreshButton.show();
488+
};
489+
490+
model.changed.connect(refresh);
491+
widget.disposed.connect(() => {
492+
model.changed.disconnect(refresh);
488493
});
489494

490495
// Load the diff widget
@@ -629,17 +634,26 @@ export function addCommands(
629634
if (widget) {
630635
// Trigger diff model update
631636
if (diffContext.previousRef === 'HEAD') {
632-
gitModel.headChanged.connect(() => {
637+
const updateHead = () => {
633638
model.reference = {
634639
...model.reference,
635640
updateAt: Date.now()
636641
};
642+
};
643+
644+
gitModel.headChanged.connect(updateHead);
645+
646+
widget.disposed.connect(() => {
647+
gitModel.headChanged.disconnect(updateHead);
637648
});
638649
}
650+
639651
// If the diff is on the current file and it is updated => diff model changed
640652
if (diffContext.currentRef === Git.Diff.SpecialRef.WORKING) {
641-
// More robust than fileBrowser.model.fileChanged
642-
app.serviceManager.contents.fileChanged.connect((_, change) => {
653+
const updateCurrent = (
654+
m: ContentsManager,
655+
change: Contents.IChangedArgs
656+
) => {
643657
const updateAt = new Date(
644658
change.newValue.last_modified
645659
).valueOf();
@@ -652,6 +666,13 @@ export function addCommands(
652666
updateAt
653667
};
654668
}
669+
};
670+
671+
// More robust than fileBrowser.model.fileChanged
672+
app.serviceManager.contents.fileChanged.connect(updateCurrent);
673+
674+
widget.disposed.connect(() => {
675+
app.serviceManager.contents.fileChanged.disconnect(updateCurrent);
655676
});
656677
}
657678
}

src/components/StatusWidget.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ export function addStatusBarWidget(
8989
isActive: Private.isStatusWidgetActive(settings),
9090
activeStateChanged: settings && settings.changed
9191
});
92-
model.taskChanged.connect(Private.createEventCallback(statusWidget));
92+
93+
const callback = Private.createEventCallback(statusWidget);
94+
model.taskChanged.connect(callback);
95+
statusWidget.disposed.connect(() => {
96+
model.taskChanged.disconnect(callback);
97+
});
9398
}
9499
/* eslint-disable no-inner-declarations */
95100
namespace Private {

src/index.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ async function activate(
7474
let settings: ISettingRegistry.ISettings;
7575
let serverSettings: Git.IServerSettings;
7676
// Get a reference to the default file browser extension
77-
const filebrowser = factory.tracker.currentWidget;
77+
let filebrowser = factory.tracker.currentWidget;
7878
translator = translator || nullTranslator;
7979
const trans = translator.load('jupyterlab_git');
8080

@@ -137,16 +137,34 @@ async function activate(
137137
gitExtension.pathRepository = filebrowser.model.path;
138138
});
139139

140+
const onPathChanged = (
141+
model: FileBrowserModel,
142+
change: IChangedArgs<string>
143+
) => {
144+
gitExtension.pathRepository = change.newValue;
145+
};
146+
140147
// Whenever the file browser path changes, sync the Git extension path
141-
filebrowser.model.pathChanged.connect(
142-
(model: FileBrowserModel, change: IChangedArgs<string>) => {
143-
gitExtension.pathRepository = change.newValue;
144-
}
145-
);
148+
filebrowser.model.pathChanged.connect(onPathChanged);
146149

147-
// Whenever the `HEAD` of the Git repository changes, refresh the file browser
148-
gitExtension.headChanged.connect(() => {
150+
const refreshBrowser = () => {
149151
filebrowser.model.refresh();
152+
};
153+
154+
// Whenever the `HEAD` of the Git repository changes, refresh the file browser
155+
gitExtension.headChanged.connect(refreshBrowser);
156+
157+
// Handle file browser changes
158+
factory.tracker.currentChanged.connect((_, browser) => {
159+
filebrowser.model.pathChanged.disconnect(onPathChanged);
160+
161+
filebrowser = browser;
162+
gitExtension.pathRepository = filebrowser.model.path;
163+
filebrowser.model.pathChanged.connect(onPathChanged);
164+
165+
if (settings) {
166+
addCloneButton(gitExtension, filebrowser, app.commands);
167+
}
150168
});
151169

152170
// Whenever a user adds/renames/saves/deletes/modifies a file within the lab environment, refresh the Git status
@@ -157,14 +175,14 @@ async function activate(
157175
// Provided we were able to load application settings, create the extension widgets
158176
if (settings) {
159177
// Add JupyterLab commands
160-
addCommands(app, gitExtension, filebrowser.model, settings, trans);
178+
addCommands(app, gitExtension, factory.tracker, settings, trans);
161179

162180
// Create the Git widget sidebar
163181
const gitPlugin = new GitWidget(
164182
gitExtension,
165183
settings,
166184
app.commands,
167-
filebrowser.model,
185+
factory.tracker,
168186
trans
169187
);
170188
gitPlugin.id = 'jp-git-sessions';

src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,7 @@ export class GitExtension implements IGitExtension {
633633
this._fetchPoll.dispose();
634634
this._statusPoll.dispose();
635635
this._taskHandler.dispose();
636+
this._settings.changed.disconnect(this._onSettingsChange, this);
636637
Signal.clearData(this);
637638
}
638639

src/widgets/GitWidget.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { ReactWidget, UseSignal } from '@jupyterlab/apputils';
2-
import { FileBrowserModel } from '@jupyterlab/filebrowser';
1+
import { ReactWidget, UseSignal, WidgetTracker } from '@jupyterlab/apputils';
2+
import { FileBrowser } from '@jupyterlab/filebrowser';
33
import { ISettingRegistry } from '@jupyterlab/settingregistry';
44
import { TranslationBundle } from '@jupyterlab/translation';
55
import { CommandRegistry } from '@lumino/commands';
@@ -22,7 +22,7 @@ export class GitWidget extends ReactWidget {
2222
model: GitExtension,
2323
settings: ISettingRegistry.ISettings,
2424
commands: CommandRegistry,
25-
filebrowser: FileBrowserModel,
25+
browserTracker: WidgetTracker<FileBrowser>,
2626
trans: TranslationBundle,
2727
options?: Widget.IOptions
2828
) {
@@ -32,7 +32,7 @@ export class GitWidget extends ReactWidget {
3232

3333
this._trans = trans;
3434
this._commands = commands;
35-
this._filebrowser = filebrowser;
35+
this._browserTracker = browserTracker;
3636
this._model = model;
3737
this._settings = settings;
3838

@@ -67,14 +67,21 @@ export class GitWidget extends ReactWidget {
6767
<LoggerContext.Consumer>
6868
{logger => (
6969
<React.Fragment>
70-
<GitPanel
71-
commands={this._commands}
72-
filebrowser={this._filebrowser}
73-
logger={logger}
74-
model={this._model}
75-
settings={this._settings}
76-
trans={this._trans}
77-
/>
70+
<UseSignal
71+
signal={this._browserTracker.currentChanged}
72+
initialArgs={this._browserTracker.currentWidget}
73+
>
74+
{(tracker, filebrowser) => (
75+
<GitPanel
76+
commands={this._commands}
77+
filebrowser={filebrowser.model}
78+
logger={logger}
79+
model={this._model}
80+
settings={this._settings}
81+
trans={this._trans}
82+
/>
83+
)}
84+
</UseSignal>
7885
<UseSignal
7986
signal={logger.signal}
8087
initialArgs={{ message: '', level: Level.INFO } as ILogMessage}
@@ -97,7 +104,7 @@ export class GitWidget extends ReactWidget {
97104
}
98105

99106
private _commands: CommandRegistry;
100-
private _filebrowser: FileBrowserModel;
107+
private _browserTracker: WidgetTracker<FileBrowser>;
101108
private _model: GitExtension;
102109
private _settings: ISettingRegistry.ISettings;
103110
private _trans: TranslationBundle;

yarn.lock

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7047,7 +7047,7 @@ prop-types-exact@^1.2.0:
70477047
object.assign "^4.1.0"
70487048
reflect.ownkeys "^0.2.0"
70497049

7050-
prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
7050+
prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
70517051
version "15.7.2"
70527052
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
70537053
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -7213,14 +7213,6 @@ react-test-renderer@^17.0.0:
72137213
react-shallow-renderer "^16.13.1"
72147214
scheduler "^0.20.2"
72157215

7216-
react-textarea-autosize@^7.1.2:
7217-
version "7.1.2"
7218-
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda"
7219-
integrity sha512-uH3ORCsCa3C6LHxExExhF4jHoXYCQwE5oECmrRsunlspaDAbS4mGKNlWZqjLfInWtFQcf0o1n1jC/NGXFdUBCg==
7220-
dependencies:
7221-
"@babel/runtime" "^7.1.2"
7222-
prop-types "^15.6.0"
7223-
72247216
react-transition-group@^2.9.0:
72257217
version "2.9.0"
72267218
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"

0 commit comments

Comments
 (0)