CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jupyterlab--application

JupyterLab application framework providing the core application class, shell management, plugin system, layout restoration, and routing capabilities.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utility-functions.mddocs/

Utility Functions

Helper functions for semantic command management, connection lost handling, and tree path updates for enhanced application functionality.

Capabilities

addSemanticCommand Function

Adds semantic commands to the application with automatic signal setup and command lifecycle management.

/**
 * Add semantic commands to the application and set up command changed signal handling
 * @param options - Semantic command configuration options
 */
function addSemanticCommand(options: ISemanticCommandOptions): void;

/**
 * Semantic command configuration options
 */
interface ISemanticCommandOptions {
  /** Unique identifier for the semantic command */
  id: string;
  
  /** Application command registry */
  commands: CommandRegistry;
  
  /** Application shell for widget context */
  shell: JupyterFrontEnd.IShell;
  
  /** Single semantic command or array of semantic commands */
  semanticCommands: SemanticCommand | SemanticCommand[];
  
  /** Default command options when no semantic command is enabled */
  default?: ISemanticCommandDefault;
  
  /** Override options for the command (excluding execute function) */
  overrides?: Omit<CommandRegistry.ICommandOptions, 'execute'>;
  
  /** Translation bundle for internationalization */
  trans?: TranslationBundle;
}

/**
 * Default command options for semantic commands
 */
interface ISemanticCommandDefault {
  /** Default command ID to execute if no command is enabled */
  execute?: string;
  
  /** Default command label */
  label?: string;
  
  /** Default command caption */
  caption?: string;
  
  /** Whether the default command is enabled */
  isEnabled?: boolean;
  
  /** Whether the default command is toggled */
  isToggled?: boolean;
  
  /** Whether the default command is visible */
  isVisible?: boolean;
}

Usage Examples:

import { addSemanticCommand, ISemanticCommandOptions } from "@jupyterlab/application";
import { SemanticCommand } from "@jupyterlab/apputils";
import { CommandRegistry } from "@lumino/commands";

// Create semantic commands for file operations
const fileCommands = [
  new SemanticCommand({
    id: 'file:save',
    selector: '.jp-Notebook',
    rank: 100
  }),
  new SemanticCommand({
    id: 'file:save-as',
    selector: '.jp-Notebook',
    rank: 200
  })
];

// Add semantic command with comprehensive options
addSemanticCommand({
  id: 'semantic:save',
  commands: app.commands,
  shell: app.shell,
  semanticCommands: fileCommands,
  default: {
    execute: 'file:new',
    label: 'Save',
    caption: 'Save the current document',
    isEnabled: true,
    isVisible: true
  },
  overrides: {
    icon: 'ui-components:save',
    mnemonic: 0 // Underline first character
  },
  trans: translator.load('myapp')
});

// Single semantic command example
const copyCommand = new SemanticCommand({
  id: 'edit:copy',
  selector: '.jp-CodeCell',
  rank: 50
});

addSemanticCommand({
  id: 'semantic:copy',
  commands: app.commands,
  shell: app.shell,
  semanticCommands: copyCommand,
  default: {
    label: 'Copy',
    isEnabled: false
  }
});

// Using the semantic command
app.commands.execute('semantic:save');
app.commands.execute('semantic:copy');

createSemanticCommand Function (Deprecated)

Legacy function for creating semantic command options (use addSemanticCommand instead).

/**
 * Create command options from semantic commands list and default values
 * @param app - Jupyter Application or object with commands and shell
 * @param semanticCommands - Single semantic command or array of commands
 * @param defaultValues - Default values for command options
 * @param trans - Translation bundle
 * @returns Command options for registering with CommandRegistry
 * 
 * @deprecated Please use addSemanticCommand. This function will be removed from the public API in JupyterLab 5.
 */
function createSemanticCommand(
  app: JupyterFrontEnd | { commands: CommandRegistry; shell: JupyterFrontEnd.IShell },
  semanticCommands: SemanticCommand | SemanticCommand[],
  defaultValues: ISemanticCommandDefault,
  trans: TranslationBundle
): CommandRegistry.ICommandOptions;

Migration Example:

// Old approach (deprecated)
const commandOptions = createSemanticCommand(
  app,
  semanticCommands,
  defaultValues,
  trans
);
app.commands.addCommand('my-command', commandOptions);

// New approach (recommended)
addSemanticCommand({
  id: 'my-command',
  commands: app.commands,
  shell: app.shell,
  semanticCommands: semanticCommands,
  default: defaultValues,
  trans: trans
});

ConnectionLost Function

Default connection lost dialog handler for server connection failures.

/**
 * Default connection lost handler function that shows a dialog when server connection is lost
 * @param manager - Service manager instance
 * @param err - Network error that occurred
 * @param translator - Optional translator for internationalization
 * @returns Promise resolving when handling is complete
 */
function ConnectionLost(
  manager: ServiceManager.IManager,
  err: ServerConnection.NetworkError,
  translator?: ITranslator
): Promise<void>;

Usage Examples:

import { ConnectionLost } from "@jupyterlab/application";
import { ServiceManager, ServerConnection } from "@jupyterlab/services";
import { ITranslator } from "@jupyterlab/translation";

// Basic usage with service manager
const serviceManager = new ServiceManager();
const translator = app.serviceManager.translator;

// Handle connection failure
serviceManager.connectionFailure.connect(async (sender, error) => {
  await ConnectionLost(serviceManager, error, translator);
});

// Custom connection lost handling
async function handleConnectionLost(
  manager: ServiceManager.IManager,
  error: ServerConnection.NetworkError
) {
  console.log('Connection lost:', error.message);
  
  // Use default handler
  await ConnectionLost(manager, error);
  
  // Additional custom handling
  console.log('Connection lost dialog completed');
}

// Providing as a service
const connectionLostPlugin: JupyterFrontEndPlugin<IConnectionLost> = {
  id: 'default-connection-lost',
  provides: IConnectionLost,
  activate: (): IConnectionLost => {
    return ConnectionLost;
  }
};

ITreePathUpdater Type

Function interface for updating tree path in the application.

/**
 * Function interface for updating the current tree path
 * @param treePath - New tree path to set
 */
type ITreePathUpdater = (treePath: string) => void;

/**
 * Service token for tree path updater
 */
const ITreePathUpdater: Token<ITreePathUpdater>;

Usage Examples:

import { ITreePathUpdater } from "@jupyterlab/application";
import { JupyterFrontEndPlugin } from "@jupyterlab/application";

// Using tree path updater in a plugin
const pathUpdaterPlugin: JupyterFrontEndPlugin<void> = {
  id: 'path-updater-example',
  autoStart: true,
  requires: [ITreePathUpdater],
  activate: (app, updatePath: ITreePathUpdater) => {
    // Update path when files are opened
    app.shell.currentChanged.connect((sender, args) => {
      const widget = args.newValue;
      if (widget && widget.title.caption) {
        // Extract path from widget caption
        const path = widget.title.caption;
        updatePath(path);
        console.log('Updated tree path to:', path);
      }
    });
    
    // Update path programmatically
    const navigateToFile = (filePath: string) => {
      updatePath(filePath);
      console.log('Navigated to:', filePath);
    };
    
    // Example usage
    navigateToFile('/notebooks/analysis.ipynb');
    navigateToFile('/data/dataset.csv');
  }
};

// Providing a tree path updater implementation
const treePathProviderPlugin: JupyterFrontEndPlugin<ITreePathUpdater> = {
  id: 'tree-path-provider',
  provides: ITreePathUpdater,
  activate: (app): ITreePathUpdater => {
    return (treePath: string) => {
      // Update application state
      console.log('Setting tree path:', treePath);
      
      // Could update URL, breadcrumbs, or internal state
      if (treePath.startsWith('/')) {
        document.title = `JupyterLab - ${treePath}`;
      }
      
      // Emit custom event for other components
      const event = new CustomEvent('tree-path-changed', {
        detail: { path: treePath }
      });
      window.dispatchEvent(event);
    };
  }
};

Advanced Usage Patterns

Complex Semantic Command Setup

Advanced patterns for setting up sophisticated semantic command hierarchies.

// Advanced semantic command patterns
interface AdvancedSemanticCommandSetup {
  /** Hierarchical command organization */
  commandHierarchy: CommandHierarchy;
  
  /** Conditional command enabling */
  conditionalCommands: ConditionalCommandOptions;
  
  /** Context-sensitive commands */
  contextSensitiveCommands: ContextSensitiveOptions;
}

interface CommandHierarchy {
  /** Parent command category */
  category: string;
  
  /** Child command definitions */
  children: SemanticCommandDefinition[];
}

interface ConditionalCommandOptions {
  /** Conditions for enabling commands */
  enableConditions: Array<(context: any) => boolean>;
  
  /** Commands to enable based on conditions */
  conditionalCommands: SemanticCommandMapping[];
}

Complete Advanced Example:

import { 
  addSemanticCommand, 
  ISemanticCommandOptions 
} from "@jupyterlab/application";
import { SemanticCommand } from "@jupyterlab/apputils";

// Advanced semantic command setup
class AdvancedCommandManager {
  private app: JupyterFrontEnd;
  private commandCategories: Map<string, SemanticCommand[]> = new Map();
  
  constructor(app: JupyterFrontEnd) {
    this.app = app;
    this.setupCommandHierarchy();
  }
  
  private setupCommandHierarchy(): void {
    // File operations category
    const fileCommands = [
      new SemanticCommand({
        id: 'file:save',
        selector: '.jp-Document',
        rank: 100
      }),
      new SemanticCommand({
        id: 'file:save-as',
        selector: '.jp-Document',
        rank: 200
      }),
      new SemanticCommand({
        id: 'file:export',
        selector: '.jp-Notebook',
        rank: 300
      })
    ];
    
    // Edit operations category
    const editCommands = [
      new SemanticCommand({
        id: 'edit:copy',
        selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',
        rank: 10
      }),
      new SemanticCommand({
        id: 'edit:paste',
        selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',
        rank: 20
      }),
      new SemanticCommand({
        id: 'edit:cut',
        selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',
        rank: 30
      })
    ];
    
    // View operations category
    const viewCommands = [
      new SemanticCommand({
        id: 'view:toggle-line-numbers',
        selector: '.jp-CodeCell',
        rank: 100
      }),
      new SemanticCommand({
        id: 'view:toggle-header',
        selector: '.jp-Notebook',
        rank: 200
      })
    ];
    
    this.commandCategories.set('file', fileCommands);
    this.commandCategories.set('edit', editCommands);
    this.commandCategories.set('view', viewCommands);
    
    // Register all command categories
    this.registerCommandCategories();
  }
  
  private registerCommandCategories(): void {
    // File category commands
    addSemanticCommand({
      id: 'semantic:file-save',
      commands: this.app.commands,
      shell: this.app.shell,
      semanticCommands: this.commandCategories.get('file')!,
      default: {
        execute: 'file:new',
        label: 'Save Document',
        caption: 'Save the current document',
        isEnabled: true
      },
      overrides: {
        icon: 'ui-components:save',
        iconClass: 'jp-SaveIcon'
      }
    });
    
    // Edit category commands
    addSemanticCommand({
      id: 'semantic:edit-clipboard',
      commands: this.app.commands,
      shell: this.app.shell,
      semanticCommands: this.commandCategories.get('edit')!,
      default: {
        label: 'Clipboard Operation',
        caption: 'Perform clipboard operation on selected content',
        isEnabled: false
      },
      overrides: {
        icon: 'ui-components:edit'
      }
    });
    
    // View category commands with conditional logic
    addSemanticCommand({
      id: 'semantic:view-toggle',
      commands: this.app.commands,
      shell: this.app.shell,
      semanticCommands: this.commandCategories.get('view')!,
      default: {
        label: 'Toggle View',
        caption: 'Toggle view settings',
        isEnabled: true,
        isVisible: true
      }
    });
  }
  
  // Method to add new semantic commands dynamically
  addDynamicCommand(
    category: string,
    commandId: string,
    selector: string,
    rank: number = 1000
  ): void {
    const newCommand = new SemanticCommand({
      id: commandId,
      selector: selector,
      rank: rank
    });
    
    if (!this.commandCategories.has(category)) {
      this.commandCategories.set(category, []);
    }
    
    this.commandCategories.get(category)!.push(newCommand);
    
    // Re-register the category
    addSemanticCommand({
      id: `semantic:${category}-dynamic`,
      commands: this.app.commands,
      shell: this.app.shell,
      semanticCommands: this.commandCategories.get(category)!,
      default: {
        label: `${category} Operations`,
        isEnabled: true
      }
    });
  }
  
  // Method to get current command status
  getCommandStatus(semanticCommandId: string): {
    isEnabled: boolean;
    isVisible: boolean;
    label: string;
  } {
    const commands = this.app.commands;
    return {
      isEnabled: commands.isEnabled(semanticCommandId),
      isVisible: commands.isVisible(semanticCommandId),
      label: commands.label(semanticCommandId)
    };
  }
}

// Usage
const commandManager = new AdvancedCommandManager(app);

// Add dynamic commands
commandManager.addDynamicCommand(
  'notebook',
  'notebook:run-all',
  '.jp-Notebook',
  50
);

// Check command status
const saveStatus = commandManager.getCommandStatus('semantic:file-save');
console.log('Save command status:', saveStatus);

Connection Lost Customization

Advanced patterns for customizing connection lost behavior.

// Advanced connection lost handling
class AdvancedConnectionLostHandler {
  private retryAttempts: number = 0;
  private maxRetries: number = 3;
  private retryDelay: number = 2000;
  
  async handleConnectionLost(
    manager: ServiceManager.IManager,
    error: ServerConnection.NetworkError,
    translator?: ITranslator
  ): Promise<void> {
    console.log(`Connection lost (attempt ${this.retryAttempts + 1}):`, error.message);
    
    // Try automatic reconnection first
    if (this.retryAttempts < this.maxRetries) {
      await this.attemptReconnection(manager, error, translator);
    } else {
      // Fall back to default dialog
      await ConnectionLost(manager, error, translator);
      this.retryAttempts = 0; // Reset for next time
    }
  }
  
  private async attemptReconnection(
    manager: ServiceManager.IManager,
    error: ServerConnection.NetworkError,
    translator?: ITranslator
  ): Promise<void> {
    this.retryAttempts++;
    
    // Show subtle notification instead of modal dialog
    this.showReconnectionNotification(this.retryAttempts, this.maxRetries);
    
    try {
      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, this.retryDelay));
      
      // Test connection
      await manager.ready;
      
      // Success - show success notification
      this.showReconnectionSuccess();
      this.retryAttempts = 0;
      
    } catch (retryError) {
      // Retry failed
      if (this.retryAttempts >= this.maxRetries) {
        // Show final failure dialog
        await ConnectionLost(manager, error, translator);
        this.retryAttempts = 0;
      } else {
        // Try again
        await this.attemptReconnection(manager, error, translator);
      }
    }
  }
  
  private showReconnectionNotification(attempt: number, maxAttempts: number): void {
    const notification = document.createElement('div');
    notification.className = 'reconnection-notification';
    notification.innerHTML = `
      <div class="reconnection-content">
        <span class="reconnection-icon">🔄</span>
        <span class="reconnection-text">
          Reconnecting... (${attempt}/${maxAttempts})
        </span>
      </div>
    `;
    
    document.body.appendChild(notification);
    
    // Auto-remove after delay
    setTimeout(() => {
      if (notification.parentNode) {
        notification.parentNode.removeChild(notification);
      }
    }, this.retryDelay);
  }
  
  private showReconnectionSuccess(): void {
    const notification = document.createElement('div');
    notification.className = 'success-notification';
    notification.innerHTML = `
      <div class="success-content">
        <span class="success-icon">✅</span>
        <span class="success-text">Reconnected successfully</span>
      </div>
    `;
    
    document.body.appendChild(notification);
    
    setTimeout(() => {
      if (notification.parentNode) {
        notification.parentNode.removeChild(notification);
      }
    }, 3000);
  }
}

// Usage
const advancedHandler = new AdvancedConnectionLostHandler();

const connectionLostPlugin: JupyterFrontEndPlugin<IConnectionLost> = {
  id: 'advanced-connection-lost',
  provides: IConnectionLost,
  activate: (app): IConnectionLost => {
    return advancedHandler.handleConnectionLost.bind(advancedHandler);
  }
};

Integration Examples

Complete Utility Integration

Example showing how all utility functions work together in a real application.

import { 
  addSemanticCommand,
  ConnectionLost,
  ITreePathUpdater
} from "@jupyterlab/application";

// Complete integration example
const utilityIntegrationPlugin: JupyterFrontEndPlugin<void> = {
  id: 'utility-integration',
  autoStart: true,
  requires: [ITreePathUpdater],
  activate: (app, updatePath: ITreePathUpdater) => {
    // Set up semantic commands for file operations
    const fileCommands = [
      new SemanticCommand({
        id: 'file:save',
        selector: '.jp-Document',
        rank: 100
      })
    ];
    
    addSemanticCommand({
      id: 'integrated:save',
      commands: app.commands,
      shell: app.shell,
      semanticCommands: fileCommands,
      default: {
        label: 'Save',
        isEnabled: true
      }
    });
    
    // Set up connection lost handling
    app.serviceManager.connectionFailure.connect(async (sender, error) => {
      await ConnectionLost(app.serviceManager, error);
    });
    
    // Set up tree path updates
    app.shell.currentChanged.connect((sender, args) => {
      const widget = args.newValue;
      if (widget && widget.title.caption) {
        updatePath(widget.title.caption);
      }
    });
    
    // Integrate all utilities for file operations
    app.commands.addCommand('integrated:open-file', {
      execute: async (args: any) => {
        const filePath = args.path as string;
        
        // Update tree path
        updatePath(filePath);
        
        // Execute semantic save command
        await app.commands.execute('integrated:save');
        
        console.log('File operation completed:', filePath);
      }
    });
  }
};

docs

application-framework.md

index.md

layout-restoration.md

mime-rendering.md

service-tokens.md

shell-management.md

status-management.md

url-routing.md

utility-functions.md

tile.json