or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-framework.mdindex.mdlayout-restoration.mdmime-rendering.mdservice-tokens.mdshell-management.mdstatus-management.mdurl-routing.mdutility-functions.md
tile.json

utility-functions.mddocs/

0

# Utility Functions

1

2

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

3

4

## Capabilities

5

6

### addSemanticCommand Function

7

8

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

9

10

```typescript { .api }

11

/**

12

* Add semantic commands to the application and set up command changed signal handling

13

* @param options - Semantic command configuration options

14

*/

15

function addSemanticCommand(options: ISemanticCommandOptions): void;

16

17

/**

18

* Semantic command configuration options

19

*/

20

interface ISemanticCommandOptions {

21

/** Unique identifier for the semantic command */

22

id: string;

23

24

/** Application command registry */

25

commands: CommandRegistry;

26

27

/** Application shell for widget context */

28

shell: JupyterFrontEnd.IShell;

29

30

/** Single semantic command or array of semantic commands */

31

semanticCommands: SemanticCommand | SemanticCommand[];

32

33

/** Default command options when no semantic command is enabled */

34

default?: ISemanticCommandDefault;

35

36

/** Override options for the command (excluding execute function) */

37

overrides?: Omit<CommandRegistry.ICommandOptions, 'execute'>;

38

39

/** Translation bundle for internationalization */

40

trans?: TranslationBundle;

41

}

42

43

/**

44

* Default command options for semantic commands

45

*/

46

interface ISemanticCommandDefault {

47

/** Default command ID to execute if no command is enabled */

48

execute?: string;

49

50

/** Default command label */

51

label?: string;

52

53

/** Default command caption */

54

caption?: string;

55

56

/** Whether the default command is enabled */

57

isEnabled?: boolean;

58

59

/** Whether the default command is toggled */

60

isToggled?: boolean;

61

62

/** Whether the default command is visible */

63

isVisible?: boolean;

64

}

65

```

66

67

**Usage Examples:**

68

69

```typescript

70

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

71

import { SemanticCommand } from "@jupyterlab/apputils";

72

import { CommandRegistry } from "@lumino/commands";

73

74

// Create semantic commands for file operations

75

const fileCommands = [

76

new SemanticCommand({

77

id: 'file:save',

78

selector: '.jp-Notebook',

79

rank: 100

80

}),

81

new SemanticCommand({

82

id: 'file:save-as',

83

selector: '.jp-Notebook',

84

rank: 200

85

})

86

];

87

88

// Add semantic command with comprehensive options

89

addSemanticCommand({

90

id: 'semantic:save',

91

commands: app.commands,

92

shell: app.shell,

93

semanticCommands: fileCommands,

94

default: {

95

execute: 'file:new',

96

label: 'Save',

97

caption: 'Save the current document',

98

isEnabled: true,

99

isVisible: true

100

},

101

overrides: {

102

icon: 'ui-components:save',

103

mnemonic: 0 // Underline first character

104

},

105

trans: translator.load('myapp')

106

});

107

108

// Single semantic command example

109

const copyCommand = new SemanticCommand({

110

id: 'edit:copy',

111

selector: '.jp-CodeCell',

112

rank: 50

113

});

114

115

addSemanticCommand({

116

id: 'semantic:copy',

117

commands: app.commands,

118

shell: app.shell,

119

semanticCommands: copyCommand,

120

default: {

121

label: 'Copy',

122

isEnabled: false

123

}

124

});

125

126

// Using the semantic command

127

app.commands.execute('semantic:save');

128

app.commands.execute('semantic:copy');

129

```

130

131

### createSemanticCommand Function (Deprecated)

132

133

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

134

135

```typescript { .api }

136

/**

137

* Create command options from semantic commands list and default values

138

* @param app - Jupyter Application or object with commands and shell

139

* @param semanticCommands - Single semantic command or array of commands

140

* @param defaultValues - Default values for command options

141

* @param trans - Translation bundle

142

* @returns Command options for registering with CommandRegistry

143

*

144

* @deprecated Please use addSemanticCommand. This function will be removed from the public API in JupyterLab 5.

145

*/

146

function createSemanticCommand(

147

app: JupyterFrontEnd | { commands: CommandRegistry; shell: JupyterFrontEnd.IShell },

148

semanticCommands: SemanticCommand | SemanticCommand[],

149

defaultValues: ISemanticCommandDefault,

150

trans: TranslationBundle

151

): CommandRegistry.ICommandOptions;

152

```

153

154

**Migration Example:**

155

156

```typescript

157

// Old approach (deprecated)

158

const commandOptions = createSemanticCommand(

159

app,

160

semanticCommands,

161

defaultValues,

162

trans

163

);

164

app.commands.addCommand('my-command', commandOptions);

165

166

// New approach (recommended)

167

addSemanticCommand({

168

id: 'my-command',

169

commands: app.commands,

170

shell: app.shell,

171

semanticCommands: semanticCommands,

172

default: defaultValues,

173

trans: trans

174

});

175

```

176

177

### ConnectionLost Function

178

179

Default connection lost dialog handler for server connection failures.

180

181

```typescript { .api }

182

/**

183

* Default connection lost handler function that shows a dialog when server connection is lost

184

* @param manager - Service manager instance

185

* @param err - Network error that occurred

186

* @param translator - Optional translator for internationalization

187

* @returns Promise resolving when handling is complete

188

*/

189

function ConnectionLost(

190

manager: ServiceManager.IManager,

191

err: ServerConnection.NetworkError,

192

translator?: ITranslator

193

): Promise<void>;

194

```

195

196

**Usage Examples:**

197

198

```typescript

199

import { ConnectionLost } from "@jupyterlab/application";

200

import { ServiceManager, ServerConnection } from "@jupyterlab/services";

201

import { ITranslator } from "@jupyterlab/translation";

202

203

// Basic usage with service manager

204

const serviceManager = new ServiceManager();

205

const translator = app.serviceManager.translator;

206

207

// Handle connection failure

208

serviceManager.connectionFailure.connect(async (sender, error) => {

209

await ConnectionLost(serviceManager, error, translator);

210

});

211

212

// Custom connection lost handling

213

async function handleConnectionLost(

214

manager: ServiceManager.IManager,

215

error: ServerConnection.NetworkError

216

) {

217

console.log('Connection lost:', error.message);

218

219

// Use default handler

220

await ConnectionLost(manager, error);

221

222

// Additional custom handling

223

console.log('Connection lost dialog completed');

224

}

225

226

// Providing as a service

227

const connectionLostPlugin: JupyterFrontEndPlugin<IConnectionLost> = {

228

id: 'default-connection-lost',

229

provides: IConnectionLost,

230

activate: (): IConnectionLost => {

231

return ConnectionLost;

232

}

233

};

234

```

235

236

### ITreePathUpdater Type

237

238

Function interface for updating tree path in the application.

239

240

```typescript { .api }

241

/**

242

* Function interface for updating the current tree path

243

* @param treePath - New tree path to set

244

*/

245

type ITreePathUpdater = (treePath: string) => void;

246

247

/**

248

* Service token for tree path updater

249

*/

250

const ITreePathUpdater: Token<ITreePathUpdater>;

251

```

252

253

**Usage Examples:**

254

255

```typescript

256

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

257

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

258

259

// Using tree path updater in a plugin

260

const pathUpdaterPlugin: JupyterFrontEndPlugin<void> = {

261

id: 'path-updater-example',

262

autoStart: true,

263

requires: [ITreePathUpdater],

264

activate: (app, updatePath: ITreePathUpdater) => {

265

// Update path when files are opened

266

app.shell.currentChanged.connect((sender, args) => {

267

const widget = args.newValue;

268

if (widget && widget.title.caption) {

269

// Extract path from widget caption

270

const path = widget.title.caption;

271

updatePath(path);

272

console.log('Updated tree path to:', path);

273

}

274

});

275

276

// Update path programmatically

277

const navigateToFile = (filePath: string) => {

278

updatePath(filePath);

279

console.log('Navigated to:', filePath);

280

};

281

282

// Example usage

283

navigateToFile('/notebooks/analysis.ipynb');

284

navigateToFile('/data/dataset.csv');

285

}

286

};

287

288

// Providing a tree path updater implementation

289

const treePathProviderPlugin: JupyterFrontEndPlugin<ITreePathUpdater> = {

290

id: 'tree-path-provider',

291

provides: ITreePathUpdater,

292

activate: (app): ITreePathUpdater => {

293

return (treePath: string) => {

294

// Update application state

295

console.log('Setting tree path:', treePath);

296

297

// Could update URL, breadcrumbs, or internal state

298

if (treePath.startsWith('/')) {

299

document.title = `JupyterLab - ${treePath}`;

300

}

301

302

// Emit custom event for other components

303

const event = new CustomEvent('tree-path-changed', {

304

detail: { path: treePath }

305

});

306

window.dispatchEvent(event);

307

};

308

}

309

};

310

```

311

312

## Advanced Usage Patterns

313

314

### Complex Semantic Command Setup

315

316

Advanced patterns for setting up sophisticated semantic command hierarchies.

317

318

```typescript { .api }

319

// Advanced semantic command patterns

320

interface AdvancedSemanticCommandSetup {

321

/** Hierarchical command organization */

322

commandHierarchy: CommandHierarchy;

323

324

/** Conditional command enabling */

325

conditionalCommands: ConditionalCommandOptions;

326

327

/** Context-sensitive commands */

328

contextSensitiveCommands: ContextSensitiveOptions;

329

}

330

331

interface CommandHierarchy {

332

/** Parent command category */

333

category: string;

334

335

/** Child command definitions */

336

children: SemanticCommandDefinition[];

337

}

338

339

interface ConditionalCommandOptions {

340

/** Conditions for enabling commands */

341

enableConditions: Array<(context: any) => boolean>;

342

343

/** Commands to enable based on conditions */

344

conditionalCommands: SemanticCommandMapping[];

345

}

346

```

347

348

**Complete Advanced Example:**

349

350

```typescript

351

import {

352

addSemanticCommand,

353

ISemanticCommandOptions

354

} from "@jupyterlab/application";

355

import { SemanticCommand } from "@jupyterlab/apputils";

356

357

// Advanced semantic command setup

358

class AdvancedCommandManager {

359

private app: JupyterFrontEnd;

360

private commandCategories: Map<string, SemanticCommand[]> = new Map();

361

362

constructor(app: JupyterFrontEnd) {

363

this.app = app;

364

this.setupCommandHierarchy();

365

}

366

367

private setupCommandHierarchy(): void {

368

// File operations category

369

const fileCommands = [

370

new SemanticCommand({

371

id: 'file:save',

372

selector: '.jp-Document',

373

rank: 100

374

}),

375

new SemanticCommand({

376

id: 'file:save-as',

377

selector: '.jp-Document',

378

rank: 200

379

}),

380

new SemanticCommand({

381

id: 'file:export',

382

selector: '.jp-Notebook',

383

rank: 300

384

})

385

];

386

387

// Edit operations category

388

const editCommands = [

389

new SemanticCommand({

390

id: 'edit:copy',

391

selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',

392

rank: 10

393

}),

394

new SemanticCommand({

395

id: 'edit:paste',

396

selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',

397

rank: 20

398

}),

399

new SemanticCommand({

400

id: 'edit:cut',

401

selector: '.jp-CodeCell.jp-mod-active, .jp-MarkdownCell.jp-mod-active',

402

rank: 30

403

})

404

];

405

406

// View operations category

407

const viewCommands = [

408

new SemanticCommand({

409

id: 'view:toggle-line-numbers',

410

selector: '.jp-CodeCell',

411

rank: 100

412

}),

413

new SemanticCommand({

414

id: 'view:toggle-header',

415

selector: '.jp-Notebook',

416

rank: 200

417

})

418

];

419

420

this.commandCategories.set('file', fileCommands);

421

this.commandCategories.set('edit', editCommands);

422

this.commandCategories.set('view', viewCommands);

423

424

// Register all command categories

425

this.registerCommandCategories();

426

}

427

428

private registerCommandCategories(): void {

429

// File category commands

430

addSemanticCommand({

431

id: 'semantic:file-save',

432

commands: this.app.commands,

433

shell: this.app.shell,

434

semanticCommands: this.commandCategories.get('file')!,

435

default: {

436

execute: 'file:new',

437

label: 'Save Document',

438

caption: 'Save the current document',

439

isEnabled: true

440

},

441

overrides: {

442

icon: 'ui-components:save',

443

iconClass: 'jp-SaveIcon'

444

}

445

});

446

447

// Edit category commands

448

addSemanticCommand({

449

id: 'semantic:edit-clipboard',

450

commands: this.app.commands,

451

shell: this.app.shell,

452

semanticCommands: this.commandCategories.get('edit')!,

453

default: {

454

label: 'Clipboard Operation',

455

caption: 'Perform clipboard operation on selected content',

456

isEnabled: false

457

},

458

overrides: {

459

icon: 'ui-components:edit'

460

}

461

});

462

463

// View category commands with conditional logic

464

addSemanticCommand({

465

id: 'semantic:view-toggle',

466

commands: this.app.commands,

467

shell: this.app.shell,

468

semanticCommands: this.commandCategories.get('view')!,

469

default: {

470

label: 'Toggle View',

471

caption: 'Toggle view settings',

472

isEnabled: true,

473

isVisible: true

474

}

475

});

476

}

477

478

// Method to add new semantic commands dynamically

479

addDynamicCommand(

480

category: string,

481

commandId: string,

482

selector: string,

483

rank: number = 1000

484

): void {

485

const newCommand = new SemanticCommand({

486

id: commandId,

487

selector: selector,

488

rank: rank

489

});

490

491

if (!this.commandCategories.has(category)) {

492

this.commandCategories.set(category, []);

493

}

494

495

this.commandCategories.get(category)!.push(newCommand);

496

497

// Re-register the category

498

addSemanticCommand({

499

id: `semantic:${category}-dynamic`,

500

commands: this.app.commands,

501

shell: this.app.shell,

502

semanticCommands: this.commandCategories.get(category)!,

503

default: {

504

label: `${category} Operations`,

505

isEnabled: true

506

}

507

});

508

}

509

510

// Method to get current command status

511

getCommandStatus(semanticCommandId: string): {

512

isEnabled: boolean;

513

isVisible: boolean;

514

label: string;

515

} {

516

const commands = this.app.commands;

517

return {

518

isEnabled: commands.isEnabled(semanticCommandId),

519

isVisible: commands.isVisible(semanticCommandId),

520

label: commands.label(semanticCommandId)

521

};

522

}

523

}

524

525

// Usage

526

const commandManager = new AdvancedCommandManager(app);

527

528

// Add dynamic commands

529

commandManager.addDynamicCommand(

530

'notebook',

531

'notebook:run-all',

532

'.jp-Notebook',

533

50

534

);

535

536

// Check command status

537

const saveStatus = commandManager.getCommandStatus('semantic:file-save');

538

console.log('Save command status:', saveStatus);

539

```

540

541

### Connection Lost Customization

542

543

Advanced patterns for customizing connection lost behavior.

544

545

```typescript { .api }

546

// Advanced connection lost handling

547

class AdvancedConnectionLostHandler {

548

private retryAttempts: number = 0;

549

private maxRetries: number = 3;

550

private retryDelay: number = 2000;

551

552

async handleConnectionLost(

553

manager: ServiceManager.IManager,

554

error: ServerConnection.NetworkError,

555

translator?: ITranslator

556

): Promise<void> {

557

console.log(`Connection lost (attempt ${this.retryAttempts + 1}):`, error.message);

558

559

// Try automatic reconnection first

560

if (this.retryAttempts < this.maxRetries) {

561

await this.attemptReconnection(manager, error, translator);

562

} else {

563

// Fall back to default dialog

564

await ConnectionLost(manager, error, translator);

565

this.retryAttempts = 0; // Reset for next time

566

}

567

}

568

569

private async attemptReconnection(

570

manager: ServiceManager.IManager,

571

error: ServerConnection.NetworkError,

572

translator?: ITranslator

573

): Promise<void> {

574

this.retryAttempts++;

575

576

// Show subtle notification instead of modal dialog

577

this.showReconnectionNotification(this.retryAttempts, this.maxRetries);

578

579

try {

580

// Wait before retry

581

await new Promise(resolve => setTimeout(resolve, this.retryDelay));

582

583

// Test connection

584

await manager.ready;

585

586

// Success - show success notification

587

this.showReconnectionSuccess();

588

this.retryAttempts = 0;

589

590

} catch (retryError) {

591

// Retry failed

592

if (this.retryAttempts >= this.maxRetries) {

593

// Show final failure dialog

594

await ConnectionLost(manager, error, translator);

595

this.retryAttempts = 0;

596

} else {

597

// Try again

598

await this.attemptReconnection(manager, error, translator);

599

}

600

}

601

}

602

603

private showReconnectionNotification(attempt: number, maxAttempts: number): void {

604

const notification = document.createElement('div');

605

notification.className = 'reconnection-notification';

606

notification.innerHTML = `

607

<div class="reconnection-content">

608

<span class="reconnection-icon">πŸ”„</span>

609

<span class="reconnection-text">

610

Reconnecting... (${attempt}/${maxAttempts})

611

</span>

612

</div>

613

`;

614

615

document.body.appendChild(notification);

616

617

// Auto-remove after delay

618

setTimeout(() => {

619

if (notification.parentNode) {

620

notification.parentNode.removeChild(notification);

621

}

622

}, this.retryDelay);

623

}

624

625

private showReconnectionSuccess(): void {

626

const notification = document.createElement('div');

627

notification.className = 'success-notification';

628

notification.innerHTML = `

629

<div class="success-content">

630

<span class="success-icon">βœ…</span>

631

<span class="success-text">Reconnected successfully</span>

632

</div>

633

`;

634

635

document.body.appendChild(notification);

636

637

setTimeout(() => {

638

if (notification.parentNode) {

639

notification.parentNode.removeChild(notification);

640

}

641

}, 3000);

642

}

643

}

644

645

// Usage

646

const advancedHandler = new AdvancedConnectionLostHandler();

647

648

const connectionLostPlugin: JupyterFrontEndPlugin<IConnectionLost> = {

649

id: 'advanced-connection-lost',

650

provides: IConnectionLost,

651

activate: (app): IConnectionLost => {

652

return advancedHandler.handleConnectionLost.bind(advancedHandler);

653

}

654

};

655

```

656

657

## Integration Examples

658

659

### Complete Utility Integration

660

661

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

662

663

```typescript

664

import {

665

addSemanticCommand,

666

ConnectionLost,

667

ITreePathUpdater

668

} from "@jupyterlab/application";

669

670

// Complete integration example

671

const utilityIntegrationPlugin: JupyterFrontEndPlugin<void> = {

672

id: 'utility-integration',

673

autoStart: true,

674

requires: [ITreePathUpdater],

675

activate: (app, updatePath: ITreePathUpdater) => {

676

// Set up semantic commands for file operations

677

const fileCommands = [

678

new SemanticCommand({

679

id: 'file:save',

680

selector: '.jp-Document',

681

rank: 100

682

})

683

];

684

685

addSemanticCommand({

686

id: 'integrated:save',

687

commands: app.commands,

688

shell: app.shell,

689

semanticCommands: fileCommands,

690

default: {

691

label: 'Save',

692

isEnabled: true

693

}

694

});

695

696

// Set up connection lost handling

697

app.serviceManager.connectionFailure.connect(async (sender, error) => {

698

await ConnectionLost(app.serviceManager, error);

699

});

700

701

// Set up tree path updates

702

app.shell.currentChanged.connect((sender, args) => {

703

const widget = args.newValue;

704

if (widget && widget.title.caption) {

705

updatePath(widget.title.caption);

706

}

707

});

708

709

// Integrate all utilities for file operations

710

app.commands.addCommand('integrated:open-file', {

711

execute: async (args: any) => {

712

const filePath = args.path as string;

713

714

// Update tree path

715

updatePath(filePath);

716

717

// Execute semantic save command

718

await app.commands.execute('integrated:save');

719

720

console.log('File operation completed:', filePath);

721

}

722

});

723

}

724

};

725

```