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
URL-based navigation system with pattern matching, command mapping, and programmatic route handling for single-page application behavior.
Main router implementation providing URL routing with pattern matching and command execution for navigation within the application.
/**
* URL routing implementation for applications
*/
class Router implements IRouter {
constructor(options: Router.IOptions);
/** The base URL for the router */
readonly base: string;
/** The command registry used by the router */
readonly commands: CommandRegistry;
/** The parsed current URL of the application */
readonly current: IRouter.ILocation;
/** A signal emitted when the router routes a route */
readonly routed: ISignal<this, IRouter.ILocation>;
/** Stop token for halting route matching chain */
readonly stop: Token<void>;
/**
* Navigate to a new path within the application
* @param path - The new path or empty string if redirecting to root
* @param options - The navigation options
*/
navigate(path: string, options?: IRouter.INavOptions): void;
/**
* Register a rule that maps a path pattern to a command
* @param options - The route registration options
* @returns A disposable that removes the registered rule from the router
*/
register(options: IRouter.IRegisterOptions): IDisposable;
/** Cause a hard reload of the document */
reload(): void;
/**
* Route the current URL
* @returns Promise that resolves when routing is complete
*/
route(): Promise<void>;
}Usage Examples:
import { Router, IRouter } from "@jupyterlab/application";
import { CommandRegistry } from "@lumino/commands";
// Create router
const commands = new CommandRegistry();
const router = new Router({
base: '/lab',
commands: commands
});
// Register commands first
commands.addCommand('app:open-file', {
execute: (args) => {
console.log('Opening file:', args.path);
}
});
commands.addCommand('app:show-help', {
execute: () => {
console.log('Showing help');
}
});
// Register route patterns
router.register({
command: 'app:open-file',
pattern: /^\/file\/(.+)$/,
rank: 10
});
router.register({
command: 'app:show-help',
pattern: /^\/help$/,
rank: 20
});
// Navigate programmatically
router.navigate('/file/notebook.ipynb');
router.navigate('/help');
// Listen to route changes
router.routed.connect((sender, location) => {
console.log('Routed to:', location.path);
});
// Current location info
console.log('Current path:', router.current.path);
console.log('Current hash:', router.current.hash);Service interface for URL routing functionality with dependency injection support.
/**
* URL routing service interface
*/
interface IRouter {
/** The base URL for the router */
readonly base: string;
/** The command registry used by the router */
readonly commands: CommandRegistry;
/** The parsed current URL of the application */
readonly current: IRouter.ILocation;
/** A signal emitted when the router routes a route */
readonly routed: ISignal<IRouter, IRouter.ILocation>;
/** Stop token for halting route matching if returned from command */
readonly stop: Token<void>;
/**
* Navigate to a new path within the application
* @param path - The new path or empty string if redirecting to root
* @param options - The navigation options
*/
navigate(path: string, options?: IRouter.INavOptions): void;
/**
* Register a rule that maps a path pattern to a command
* @param options - The route registration options
* @returns A disposable that removes the registered rule from the router
*/
register(options: IRouter.IRegisterOptions): IDisposable;
/** Cause a hard reload of the document */
reload(): void;
/**
* Route the current URL
* @returns Promise that resolves when routing is complete
*
* #### Notes
* If a pattern is matched, its command will be invoked with arguments that
* match the `IRouter.ILocation` interface.
*/
route(): Promise<void>;
}
/**
* Service token for URL router
*/
const IRouter: Token<IRouter>;Usage in Plugins:
import { IRouter } from "@jupyterlab/application";
import { JupyterFrontEndPlugin } from "@jupyterlab/application";
const routingPlugin: JupyterFrontEndPlugin<void> = {
id: 'my-routing-plugin',
autoStart: true,
requires: [IRouter],
activate: (app, router: IRouter) => {
// Register routes for this plugin
const disposable = router.register({
command: 'myapp:handle-route',
pattern: /^\/myapp\/(.+)$/,
rank: 100
});
// Listen to route changes
router.routed.connect((sender, location) => {
if (location.path.startsWith('/myapp/')) {
console.log('My app route activated');
}
});
// Clean up on plugin disposal
return disposable;
}
};Information about the current URL location including parsed components.
/**
* The parsed location currently being routed
*/
interface IRouter.ILocation extends ReadonlyPartialJSONObject {
/** The location hash */
hash: string;
/** The path that matched a routing pattern */
path: string;
/**
* The request being routed with the router `base` omitted
*
* #### Notes
* This field includes the query string and hash, if they exist.
*/
request: string;
/**
* The search element, including leading question mark (`'?'`), if any,
* of the path.
*/
search?: string;
}Usage Examples:
// Accessing location information
const currentLocation = router.current;
console.log('Full request:', currentLocation.request);
console.log('Path only:', currentLocation.path);
console.log('Hash:', currentLocation.hash);
console.log('Query string:', currentLocation.search);
// Example values for URL: /lab/tree/notebooks?filter=python#section1
// base: '/lab'
// request: '/tree/notebooks?filter=python#section1'
// path: '/tree/notebooks'
// search: '?filter=python'
// hash: '#section1'Options for controlling navigation behavior and routing.
/**
* The options passed into a navigation request
*/
interface IRouter.INavOptions {
/**
* Whether the navigation should be hard URL change instead of an HTML
* history API change.
*/
hard?: boolean;
/**
* Should the routing stage be skipped when navigating? This will simply rewrite the URL
* and push the new state to the history API, no routing commands will be triggered.
*/
skipRouting?: boolean;
}Usage Examples:
// Soft navigation (default) - uses HTML5 history API
router.navigate('/new-path');
// Hard navigation - causes full page reload
router.navigate('/new-path', { hard: true });
// Skip routing - just update URL without triggering commands
router.navigate('/new-path', { skipRouting: true });
// Combined options
router.navigate('/external-link', {
hard: true,
skipRouting: false
});System for mapping URL patterns to commands with configurable priority.
/**
* The specification for registering a route with the router
*/
interface IRouter.IRegisterOptions {
/** The command string that will be invoked upon matching */
command: string;
/** The regular expression that will be matched against URLs */
pattern: RegExp;
/**
* The rank order of the registered rule. A lower rank denotes a higher
* priority. The default rank is `100`.
*/
rank?: number;
}Usage Examples:
// High priority route (lower rank = higher priority)
router.register({
command: 'app:admin-panel',
pattern: /^\/admin\/(.*)$/,
rank: 1
});
// Medium priority route
router.register({
command: 'app:open-notebook',
pattern: /^\/notebooks\/(.+\.ipynb)$/,
rank: 50
});
// Default priority route (rank defaults to 100)
router.register({
command: 'app:catch-all',
pattern: /^\/(.*)$/
});
// Route with capture groups
router.register({
command: 'app:user-profile',
pattern: /^\/users\/([^\/]+)(?:\/(.+))?$/,
rank: 25
});
// Command handler receives location as arguments
commands.addCommand('app:user-profile', {
execute: (args: IRouter.ILocation) => {
// Access path parts via regex match
const match = args.path.match(/^\/users\/([^\/]+)(?:\/(.+))?$/);
if (match) {
const [, username, subpath] = match;
console.log('User:', username, 'Subpath:', subpath);
}
}
});Configuration for creating Router instances.
namespace Router {
/**
* Constructor options for Router
*/
interface IOptions {
/** Base URL path for the router */
base: string;
/** Command registry to use for route commands */
commands: CommandRegistry;
}
}Usage Examples:
import { Router } from "@jupyterlab/application";
import { CommandRegistry } from "@lumino/commands";
// Basic router setup
const commands = new CommandRegistry();
const router = new Router({
base: window.location.pathname,
commands: commands
});
// Router with custom base
const labRouter = new Router({
base: '/lab',
commands: commands
});
// Router for development
const devRouter = new Router({
base: process.env.NODE_ENV === 'development' ? '/dev' : '/app',
commands: commands
});Complex routing scenarios and patterns for real-world applications.
// Advanced routing patterns
interface AdvancedRoutingPatterns {
/** File path routing with extension matching */
fileRouting: RegExp; // /^\/files\/(.+\.(py|js|ts|md))$/
/** Nested resource routing */
nestedRouting: RegExp; // /^\/workspaces\/([^\/]+)\/files\/(.+)$/
/** Optional parameters */
optionalParams: RegExp; // /^\/search(?:\/(.+))?$/
/** Query parameter handling */
queryParams: RegExp; // /^\/results/
}Complete Routing Example:
import { Router, IRouter } from "@jupyterlab/application";
import { CommandRegistry } from "@lumino/commands";
// Complete routing setup
function setupRouting(commands: CommandRegistry): Router {
const router = new Router({
base: '/app',
commands: commands
});
// Define commands
commands.addCommand('app:home', {
execute: () => console.log('Home page')
});
commands.addCommand('app:open-file', {
execute: (args: IRouter.ILocation) => {
const match = args.path.match(/^\/files\/(.+)$/);
if (match) {
const filePath = decodeURIComponent(match[1]);
console.log('Opening file:', filePath);
}
}
});
commands.addCommand('app:search', {
execute: (args: IRouter.ILocation) => {
const searchParams = new URLSearchParams(args.search || '');
const query = searchParams.get('q') || '';
console.log('Searching for:', query);
}
});
// Register routes with priorities
const disposables = [
// High priority exact matches
router.register({
command: 'app:home',
pattern: /^\/$/,
rank: 1
}),
// Medium priority with parameters
router.register({
command: 'app:open-file',
pattern: /^\/files\/(.+)$/,
rank: 50
}),
router.register({
command: 'app:search',
pattern: /^\/search$/,
rank: 50
})
];
// Navigation helpers
const navigateToFile = (path: string) => {
router.navigate(`/files/${encodeURIComponent(path)}`);
};
const navigateToSearch = (query: string) => {
router.navigate(`/search?q=${encodeURIComponent(query)}`);
};
// Route change logging
router.routed.connect((sender, location) => {
console.log(`Routed to: ${location.path}`, location);
});
return router;
}Handling routing errors and edge cases.
// Error handling in route commands
commands.addCommand('app:error-prone-route', {
execute: async (args: IRouter.ILocation) => {
try {
// Route handling that might fail
await handleRoute(args);
} catch (error) {
console.error('Route handling failed:', error);
// Navigate to error page or show notification
router.navigate('/error');
}
}
});
// Graceful fallback routing
router.register({
command: 'app:not-found',
pattern: /.*/, // Matches everything
rank: 1000 // Lowest priority (highest rank)
});