@jupyterlab/git
Version:
A JupyterLab extension for version control using git
171 lines (170 loc) • 8.32 kB
JavaScript
import { ILayoutRestorer } from '@jupyterlab/application';
import { Dialog, ICommandPalette, showErrorMessage } from '@jupyterlab/apputils';
import { IEditorServices } from '@jupyterlab/codeeditor';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
import { IMainMenu } from '@jupyterlab/mainmenu';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { IStatusBar } from '@jupyterlab/statusbar';
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
import { gitCloneCommandPlugin } from './cloneCommand';
import { addCommands, addFileBrowserContextMenu, createGitMenu } from './commandsAndMenu';
import { createImageDiff } from './components/diff/ImageDiff';
import { createNotebookDiff } from './components/diff/NotebookDiff';
import { addStatusBarWidget } from './components/StatusWidget';
import { GitExtension } from './model';
import { getServerSettings } from './server';
import { gitIcon } from './style/icons';
import { CommandIDs, IGitExtension } from './tokens';
import { GitWidget } from './widgets/GitWidget';
import { IEditorLanguageRegistry } from '@jupyterlab/codemirror';
export { DiffModel } from './components/diff/model';
export { NotebookDiff } from './components/diff/NotebookDiff';
export { PlainTextDiff } from './components/diff/PlainTextDiff';
export { Git, IGitExtension } from './tokens';
/**
* The default running sessions extension.
*/
const plugin = {
id: '@jupyterlab/git:plugin',
requires: [
ILayoutRestorer,
IEditorLanguageRegistry,
IEditorServices,
IDefaultFileBrowser,
IRenderMimeRegistry,
ISettingRegistry,
IDocumentManager
],
optional: [IMainMenu, IStatusBar, ICommandPalette, ITranslator],
provides: IGitExtension,
activate,
autoStart: true
};
/**
* Export the plugin as default.
*/
export default [plugin, gitCloneCommandPlugin];
/**
* Activate the running plugin.
*/
async function activate(app, restorer, languageRegistry, editorServices,
// Get a reference to the default file browser extension
// We don't use the current tracked browser because extension like jupyterlab-github
// or jupyterlab-gitlab are defining new filebrowsers that we don't support.
// And it is unlikely that another browser than the default will be used.
// Ref: https://github.com/jupyterlab/jupyterlab-git/issues/1014
fileBrowser, renderMime, settingRegistry, docmanager, mainMenu, statusBar, palette, translator) {
let settings = undefined;
let serverSettings;
translator = translator !== null && translator !== void 0 ? translator : nullTranslator;
const trans = translator.load('jupyterlab_git');
// Attempt to load application settings
try {
settings = await settingRegistry.load(plugin.id);
}
catch (error) {
console.error(trans.__('Failed to load settings for the Git Extension.\n%1', error));
}
try {
serverSettings = await getServerSettings(trans);
const { frontendVersion, gitVersion, serverVersion } = serverSettings;
// Version validation
if (!gitVersion) {
throw new Error(trans.__('git command not found - please ensure you have Git > 2 installed'));
}
else {
const gitVersion_ = gitVersion.split('.');
if (Number.parseInt(gitVersion_[0]) < 2) {
throw new Error(trans.__('git command version must be > 2; got %1.', gitVersion));
}
}
if (frontendVersion && frontendVersion !== serverVersion) {
throw new Error(trans.__('The versions of the JupyterLab Git server frontend and backend do not match. ' +
'The @jupyterlab/git frontend extension has version: %1 ' +
'while the python package has version %2. ' +
'Please install identical version of jupyterlab-git Python package and the @jupyterlab/git extension. Try running: pip install --upgrade jupyterlab-git', frontendVersion, serverVersion));
}
}
catch (error) {
// If we fall here, nothing will be loaded in the frontend.
console.error(trans.__('Failed to load the jupyterlab-git server extension settings'), error);
showErrorMessage(trans.__('Failed to load the jupyterlab-git server extension'), error.message, [Dialog.warnButton({ label: trans.__('Dismiss') })]);
// @ts-expect-error unable to initialize the extension token.
return null;
}
// Create the Git model
const gitExtension = new GitExtension(docmanager, app.docRegistry, settings);
const onPathChanged = (model, change) => {
gitExtension.pathRepository = app.serviceManager.contents.localPath(change.newValue);
gitExtension.refreshBranch();
};
// Whenever we restore the application, sync the Git extension path
Promise.all([app.restored, fileBrowser.model.restored]).then(() => {
onPathChanged(fileBrowser.model, {
name: 'path',
newValue: fileBrowser.model.path,
oldValue: ''
});
});
// Whenever the file browser path changes, sync the Git extension path
fileBrowser.model.pathChanged.connect(onPathChanged);
const refreshBrowser = () => {
fileBrowser.model.refresh();
};
// Whenever the `HEAD` of the Git repository changes, refresh the file browser
gitExtension.headChanged.connect(refreshBrowser);
// Whenever a user adds/renames/saves/deletes/modifies a file within the lab environment, refresh the Git status
app.serviceManager.contents.fileChanged.connect(() => gitExtension.refreshStatus());
// Provided we were able to load application settings, create the extension widgets
if (settings) {
// Add JupyterLab commands
addCommands(app, gitExtension, editorServices.factoryService, languageRegistry, fileBrowser.model, settings, translator);
// Create the Git widget sidebar
const gitPlugin = new GitWidget(gitExtension, settings, app.commands, fileBrowser.model, trans);
gitPlugin.id = 'jp-git-sessions';
gitPlugin.title.icon = gitIcon;
gitPlugin.title.caption = 'Git';
if (palette) {
// Add the commands to the command palette
const category = 'Git Operations';
[
CommandIDs.gitToggleSimpleStaging,
CommandIDs.gitToggleDoubleClickDiff,
CommandIDs.gitOpenGitignore,
CommandIDs.gitInit,
CommandIDs.gitMerge,
CommandIDs.gitRebase,
CommandIDs.gitPush,
CommandIDs.gitPull,
CommandIDs.gitResetToRemote,
CommandIDs.gitManageRemote,
CommandIDs.gitTerminalCommand
].forEach(command => palette.addItem({ command, category }));
}
// Let the application restorer track the running panel for restoration of
// application state (e.g. setting the running panel as the current side bar
// widget).
restorer.add(gitPlugin, 'git-sessions');
// Rank has been chosen somewhat arbitrarily to give priority to the running
// sessions widget in the sidebar.
app.shell.add(gitPlugin, 'left', { rank: 200 });
// Add a menu for the plugin
if (mainMenu && app.version.split('.').slice(0, 2).join('.') < '3.1') {
// Support JLab 3.0
/*mainMenu.addMenu(createGitMenu(app.commands, trans), { rank: 60 });*/
mainMenu.addMenu(createGitMenu(app.commands, trans));
}
// Add the status bar widget
if (statusBar) {
addStatusBarWidget(statusBar, gitExtension, settings, trans);
}
// Add the context menu items for the default file browser
addFileBrowserContextMenu(gitExtension, fileBrowser, app.serviceManager.contents, app.contextMenu, trans);
}
// Register diff providers
gitExtension.registerDiffProvider('Nbdime', ['.ipynb'], (options) => createNotebookDiff({ ...options, renderMime }));
gitExtension.registerDiffProvider('ImageDiff', ['.jpeg', '.jpg', '.png'], createImageDiff);
return gitExtension;
}