JupyterLab application framework providing the core application class, shell management, plugin system, layout restoration, and routing capabilities.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Persistent layout state management for saving and restoring widget arrangements, positions, and application state across sessions.
Main implementation for layout restoration providing persistent state management across application sessions.
/**
* Layout restoration implementation for persistent widget state management
*/
class LayoutRestorer implements ILayoutRestorer {
constructor(options: LayoutRestorer.IOptions);
/** Whether restoration is deferred until later */
readonly isDeferred: boolean;
/** Promise that resolves when restoration is complete */
readonly restored: Promise<void>;
/**
* Add a widget to be tracked for restoration
* @param widget - Widget to track
* @param name - Unique name for the widget
*/
add(widget: Widget, name: string): void;
/**
* Fetch the saved layout from storage
* @returns Promise resolving to saved layout or null
*/
fetch(): Promise<ILabShell.ILayout>;
/**
* Restore a widget tracker with saved state
* @param tracker - Widget tracker to restore
* @param options - Restoration options
* @returns Promise resolving when restoration is complete
*/
restore(
tracker: WidgetTracker,
options: IRestorer.IOptions<Widget>
): Promise<any>;
/**
* Restore deferred widgets
* @returns Promise resolving to main area layout or null
*/
restoreDeferred(): Promise<ILabShell.IMainArea | null>;
/**
* Save the current layout to storage
* @param layout - Layout to save
* @returns Promise resolving when save is complete
*/
save(layout: ILabShell.ILayout): Promise<void>;
}Usage Examples:
import { LayoutRestorer, ILayoutRestorer } from "@jupyterlab/application";
import { StateDB } from "@jupyterlab/statedb";
import { Widget } from "@lumino/widgets";
// Create layout restorer
const restorer = new LayoutRestorer({
connector: new StateDB(),
first: Promise.resolve(),
registry: commandRegistry
});
// Add widgets for tracking
const myWidget = new Widget();
myWidget.id = 'my-important-widget';
restorer.add(myWidget, 'my-important-widget');
// Wait for restoration to complete
await restorer.restored;
console.log('Layout restoration completed');
// Save current layout
const currentLayout = shell.saveLayout();
await restorer.save(currentLayout);
// Restore a widget tracker
await restorer.restore(widgetTracker, {
command: 'myapp:open-widget',
args: (widget) => ({ id: widget.id }),
name: (widget) => widget.id
});Service interface for layout restoration functionality with dependency injection support.
/**
* Layout restoration service interface
*/
interface ILayoutRestorer extends IRestorer {
/** Promise that resolves when restoration is complete */
readonly restored: Promise<void>;
/**
* Add a widget to be tracked for restoration
* @param widget - Widget to track
* @param name - Unique name for the widget
*/
add(widget: Widget, name: string): void;
/**
* Restore a widget tracker with saved state
* @param tracker - Widget tracker to restore
* @param options - Restoration options
* @returns Promise resolving when restoration is complete
*/
restore<T extends Widget>(
tracker: WidgetTracker<T>,
options: IRestorer.IOptions<T>
): Promise<any>;
}
/**
* Service token for layout restoration
*/
const ILayoutRestorer: Token<ILayoutRestorer>;Usage in Plugins:
import { ILayoutRestorer } from "@jupyterlab/application";
import { JupyterFrontEndPlugin } from "@jupyterlab/application";
import { WidgetTracker } from "@jupyterlab/apputils";
const plugin: JupyterFrontEndPlugin<void> = {
id: 'my-restoration-plugin',
autoStart: true,
requires: [ILayoutRestorer],
activate: (app, restorer: ILayoutRestorer) => {
const tracker = new WidgetTracker<MyWidget>({
namespace: 'my-widgets'
});
// Restore widgets from previous session
restorer.restore(tracker, {
command: 'myapp:create-widget',
args: (widget) => ({
id: widget.id,
config: widget.config
}),
name: (widget) => widget.id,
when: app.serviceManager.ready
});
// Add new widgets to restoration
tracker.widgetAdded.connect((sender, widget) => {
restorer.add(widget, widget.id);
});
}
};Configuration options for controlling how widgets and trackers are restored.
/**
* Options for restoring widget trackers (from @jupyterlab/apputils)
*/
interface IRestorer.IOptions<T extends Widget> {
/**
* Command to execute when restoring a widget
*/
command: string;
/**
* Function to extract command arguments from widget
* @param widget - Widget to extract args from
* @returns Command arguments
*/
args?: (widget: T) => ReadonlyPartialJSONObject;
/**
* Function to generate unique name for widget
* @param widget - Widget to name
* @returns Unique name string
*/
name: (widget: T) => string;
/**
* Promise to wait for before restoration
*/
when?: Promise<any>;
}Configuration for creating LayoutRestorer instances.
namespace LayoutRestorer {
/**
* Constructor options for LayoutRestorer
*/
interface IOptions {
/**
* State storage connector
*/
connector: IDataConnector<ReadonlyPartialJSONObject>;
/**
* Promise to resolve before restoration begins
*/
first: Promise<any>;
/**
* Command registry for executing restoration commands
*/
registry: CommandRegistry;
}
}Usage Examples:
import { LayoutRestorer } from "@jupyterlab/application";
import { StateDB } from "@jupyterlab/statedb";
import { CommandRegistry } from "@lumino/commands";
// Custom state connector
class CustomStateConnector implements IDataConnector<ReadonlyPartialJSONObject> {
async fetch(id: string): Promise<ReadonlyPartialJSONObject | undefined> {
// Custom fetch implementation
return JSON.parse(localStorage.getItem(id) || '{}');
}
async save(id: string, value: ReadonlyPartialJSONObject): Promise<void> {
// Custom save implementation
localStorage.setItem(id, JSON.stringify(value));
}
async remove(id: string): Promise<void> {
localStorage.removeItem(id);
}
async list(query?: string): Promise<any> {
// List implementation
return {};
}
}
// Create restorer with custom options
const commands = new CommandRegistry();
const restorer = new LayoutRestorer({
connector: new CustomStateConnector(),
first: Promise.resolve(), // Or wait for some initialization
registry: commands
});
// Check if restoration is deferred
if (restorer.isDeferred) {
console.log('Restoration will happen later');
// Manually trigger deferred restoration
const deferredLayout = await restorer.restoreDeferred();
if (deferredLayout) {
console.log('Deferred widgets restored');
}
}How layout restoration integrates with the shell system for complete state management.
// Integration example showing how restoration works with shell
interface ShellRestorationWorkflow {
/**
* 1. Shell saves its layout periodically or on shutdown
*/
saveShellLayout(): Promise<void>;
/**
* 2. Layout restorer fetches saved layout on startup
*/
fetchSavedLayout(): Promise<ILabShell.ILayout | null>;
/**
* 3. Shell restores layout with layout restorer
*/
restoreShellLayout(layout: ILabShell.ILayout): Promise<void>;
/**
* 4. Individual widgets are restored via trackers
*/
restoreWidgetTrackers(): Promise<void>;
}Complete Restoration Example:
import {
LayoutRestorer,
ILayoutRestorer,
LabShell,
ILabShell
} from "@jupyterlab/application";
import { StateDB } from "@jupyterlab/statedb";
import { DockPanel } from "@lumino/widgets";
// Complete restoration workflow
async function setupLayoutRestoration(
shell: LabShell,
commands: CommandRegistry
) {
// 1. Create layout restorer
const restorer = new LayoutRestorer({
connector: new StateDB(),
first: Promise.resolve(),
registry: commands
});
// 2. Wait for restoration to complete
await restorer.restored;
// 3. Restore shell layout from saved state
const savedLayout = await restorer.fetch();
if (savedLayout) {
await shell.restoreLayout(
DockPanel.Mode.Multiple,
restorer,
savedLayout
);
}
// 4. Set up periodic saving
let saveTimer: any;
const scheduleSave = () => {
clearTimeout(saveTimer);
saveTimer = setTimeout(async () => {
const currentLayout = shell.saveLayout();
await restorer.save(currentLayout);
}, 1000); // Save after 1 second of inactivity
};
// Save when layout changes
shell.layoutModified.connect(scheduleSave);
// Save when widgets are added/removed
shell.currentChanged.connect(scheduleSave);
return restorer;
}Common error scenarios and how to handle them in layout restoration.
// Error handling patterns
try {
await restorer.restore(tracker, options);
} catch (error) {
if (error instanceof Error) {
console.warn('Failed to restore widgets:', error.message);
// Fallback to default layout or create new widgets
}
}
// Graceful degradation
const layout = await restorer.fetch().catch(() => null);
if (!layout) {
console.log('No saved layout found, using defaults');
// Set up default layout
}