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

service-tokens.mddocs/

0

# Service Tokens

1

2

Dependency injection tokens for service-based architecture, enabling loose coupling and extensibility in the plugin system.

3

4

## Capabilities

5

6

### IConnectionLost Token

7

8

Service token and interface for handling server connection failures with customizable dialog behavior.

9

10

```typescript { .api }

11

/**

12

* Connection lost handler function type

13

* @param manager - Service manager instance

14

* @param err - Network error that occurred

15

* @param translator - Optional translator for internationalization

16

* @returns Promise resolving when handling is complete

17

*/

18

type IConnectionLost = (

19

manager: ServiceManager.IManager,

20

err: ServerConnection.NetworkError,

21

translator?: ITranslator

22

) => Promise<void>;

23

24

/**

25

* Service token for connection lost handling

26

*/

27

const IConnectionLost: Token<IConnectionLost>;

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

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

34

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

35

36

// Using connection lost service in a plugin

37

const connectionPlugin: JupyterFrontEndPlugin<void> = {

38

id: 'my-connection-plugin',

39

autoStart: true,

40

requires: [IConnectionLost],

41

activate: (app, connectionLost: IConnectionLost) => {

42

// Monitor service manager for connection issues

43

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

44

await connectionLost(app.serviceManager, err);

45

});

46

}

47

};

48

49

// Providing custom connection lost handler

50

const customConnectionLostPlugin: JupyterFrontEndPlugin<IConnectionLost> = {

51

id: 'custom-connection-lost',

52

provides: IConnectionLost,

53

activate: (app) => {

54

return async (manager, err, translator) => {

55

// Custom connection lost handling

56

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

57

58

// Show custom dialog or notification

59

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

60

dialog.textContent = 'Connection to server lost. Attempting to reconnect...';

61

document.body.appendChild(dialog);

62

63

// Attempt reconnection

64

try {

65

await manager.ready;

66

dialog.remove();

67

} catch (reconnectErr) {

68

dialog.textContent = 'Failed to reconnect. Please refresh the page.';

69

}

70

};

71

}

72

};

73

```

74

75

### ILabStatus Token

76

77

Service token and interface for managing application busy and dirty states with reactive signals.

78

79

```typescript { .api }

80

/**

81

* Application status management interface

82

*/

83

interface ILabStatus {

84

/** Signal emitted when application busy state changes */

85

readonly busySignal: ISignal<JupyterFrontEnd<any, any>, boolean>;

86

87

/** Signal emitted when application dirty state changes */

88

readonly dirtySignal: ISignal<JupyterFrontEnd<any, any>, boolean>;

89

90

/** Whether the application is currently busy */

91

readonly isBusy: boolean;

92

93

/** Whether the application has unsaved changes */

94

readonly isDirty: boolean;

95

96

/**

97

* Set the application state to busy

98

* @returns A disposable used to clear the busy state for the caller

99

*/

100

setBusy(): IDisposable;

101

102

/**

103

* Set the application state to dirty

104

* @returns A disposable used to clear the dirty state for the caller

105

*/

106

setDirty(): IDisposable;

107

}

108

109

/**

110

* Service token for application status management

111

*/

112

const ILabStatus: Token<ILabStatus>;

113

```

114

115

**Usage Examples:**

116

117

```typescript

118

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

119

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

120

121

// Using status service in a plugin

122

const statusPlugin: JupyterFrontEndPlugin<void> = {

123

id: 'my-status-plugin',

124

autoStart: true,

125

requires: [ILabStatus],

126

activate: (app, status: ILabStatus) => {

127

// Listen to status changes

128

status.busySignal.connect((sender, isBusy) => {

129

console.log('Application busy state:', isBusy);

130

// Update UI (e.g., show/hide spinner)

131

document.body.classList.toggle('busy', isBusy);

132

});

133

134

status.dirtySignal.connect((sender, isDirty) => {

135

console.log('Application dirty state:', isDirty);

136

// Update UI (e.g., show unsaved indicator)

137

document.title = isDirty ? '• My App' : 'My App';

138

});

139

140

// Set busy state during long operations

141

const performLongOperation = async () => {

142

const busyDisposable = status.setBusy();

143

try {

144

await someAsyncOperation();

145

} finally {

146

busyDisposable.dispose(); // Clear busy state

147

}

148

};

149

150

// Set dirty state when content changes

151

const handleContentChange = () => {

152

const dirtyDisposable = status.setDirty();

153

// Keep the disposable until content is saved

154

return dirtyDisposable;

155

};

156

}

157

};

158

```

159

160

### IRouter Token

161

162

Service token for URL routing functionality (covered in detail in URL Routing documentation).

163

164

```typescript { .api }

165

/**

166

* Service token for URL router

167

*/

168

const IRouter: Token<IRouter>;

169

170

/**

171

* URL routing service interface

172

*/

173

interface IRouter {

174

readonly base: string;

175

readonly commands: CommandRegistry;

176

readonly current: IRouter.ILocation;

177

readonly routed: ISignal<IRouter, IRouter.ILocation>;

178

readonly stop: Token<void>;

179

navigate(path: string, options?: IRouter.INavOptions): void;

180

register(options: IRouter.IRegisterOptions): IDisposable;

181

reload(): void;

182

route(url: string): void;

183

}

184

```

185

186

### ILayoutRestorer Token

187

188

Service token for layout restoration functionality (covered in detail in Layout Restoration documentation).

189

190

```typescript { .api }

191

/**

192

* Service token for layout restoration

193

*/

194

const ILayoutRestorer: Token<ILayoutRestorer>;

195

196

/**

197

* Layout restoration service interface

198

*/

199

interface ILayoutRestorer extends IRestorer {

200

readonly restored: Promise<void>;

201

add(widget: Widget, name: string): void;

202

restore<T extends Widget>(

203

tracker: WidgetTracker<T>,

204

options: IRestorer.IOptions<T>

205

): Promise<any>;

206

}

207

```

208

209

### IMimeDocumentTracker Token

210

211

Service token for tracking MIME document widgets across the application.

212

213

```typescript { .api }

214

/**

215

* MIME document widget tracker interface

216

*/

217

interface IMimeDocumentTracker extends IWidgetTracker<MimeDocument> {

218

// Inherits all IWidgetTracker methods for tracking MimeDocument widgets

219

}

220

221

/**

222

* Service token for MIME document tracker

223

*/

224

const IMimeDocumentTracker: Token<IMimeDocumentTracker>;

225

```

226

227

**Usage Examples:**

228

229

```typescript

230

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

231

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

232

233

const mimeTrackerPlugin: JupyterFrontEndPlugin<void> = {

234

id: 'my-mime-tracker-plugin',

235

autoStart: true,

236

requires: [IMimeDocumentTracker],

237

activate: (app, tracker: IMimeDocumentTracker) => {

238

// Listen for new MIME documents

239

tracker.widgetAdded.connect((sender, widget) => {

240

console.log('New MIME document added:', widget.context.path);

241

});

242

243

// Access current MIME document

244

const current = tracker.currentWidget;

245

if (current) {

246

console.log('Current MIME document:', current.title.label);

247

}

248

249

// Find specific MIME documents

250

const htmlDocs = tracker.filter(widget =>

251

widget.context.path.endsWith('.html')

252

);

253

console.log(`Found ${htmlDocs.length} HTML documents`);

254

}

255

};

256

```

257

258

### ITreePathUpdater Token

259

260

Service token for updating tree path information in the application.

261

262

```typescript { .api }

263

/**

264

* Tree path updater function type

265

* @param treePath - New tree path to set

266

*/

267

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

268

269

/**

270

* Service token for tree path updating

271

*/

272

const ITreePathUpdater: Token<ITreePathUpdater>;

273

```

274

275

**Usage Examples:**

276

277

```typescript

278

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

279

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

280

281

const pathUpdaterPlugin: JupyterFrontEndPlugin<void> = {

282

id: 'my-path-updater-plugin',

283

autoStart: true,

284

requires: [ITreePathUpdater],

285

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

286

// Update path when navigating

287

const navigateToPath = (newPath: string) => {

288

updatePath(newPath);

289

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

290

};

291

292

// Example usage

293

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

294

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

295

}

296

};

297

```

298

299

### Application-Specific Tokens

300

301

Additional service tokens from the JupyterFrontEnd namespace.

302

303

```typescript { .api }

304

/**

305

* Service token for application paths configuration

306

*/

307

const IPaths: Token<JupyterFrontEnd.IPaths>;

308

309

/**

310

* Service token for tree resolver functionality

311

*/

312

const ITreeResolver: Token<JupyterFrontEnd.ITreeResolver>;

313

```

314

315

## Plugin Integration Patterns

316

317

Common patterns for using service tokens in plugin development.

318

319

### Basic Service Usage

320

321

```typescript

322

// Single service dependency

323

const basicPlugin: JupyterFrontEndPlugin<void> = {

324

id: 'basic-service-plugin',

325

autoStart: true,

326

requires: [ILabStatus],

327

activate: (app, status: ILabStatus) => {

328

// Use the service

329

const disposable = status.setBusy();

330

// ... do work

331

disposable.dispose();

332

}

333

};

334

```

335

336

### Multiple Service Dependencies

337

338

```typescript

339

// Multiple service dependencies

340

const multiServicePlugin: JupyterFrontEndPlugin<void> = {

341

id: 'multi-service-plugin',

342

autoStart: true,

343

requires: [ILabStatus, IRouter, ILayoutRestorer],

344

activate: (app, status: ILabStatus, router: IRouter, restorer: ILayoutRestorer) => {

345

// Use multiple services together

346

router.routed.connect(() => {

347

const busyDisposable = status.setBusy();

348

349

// Restore layout after routing

350

restorer.restored.then(() => {

351

busyDisposable.dispose();

352

});

353

});

354

}

355

};

356

```

357

358

### Optional Service Dependencies

359

360

```typescript

361

// Optional service dependencies

362

const optionalServicePlugin: JupyterFrontEndPlugin<void> = {

363

id: 'optional-service-plugin',

364

autoStart: true,

365

requires: [ILabStatus],

366

optional: [IRouter],

367

activate: (app, status: ILabStatus, router: IRouter | null) => {

368

// Required service is always available

369

status.setBusy();

370

371

// Optional service might be null

372

if (router) {

373

router.navigate('/optional-feature');

374

} else {

375

console.log('Router not available, using fallback');

376

}

377

}

378

};

379

```

380

381

### Providing Custom Services

382

383

```typescript

384

// Providing a service implementation

385

const serviceProviderPlugin: JupyterFrontEndPlugin<IConnectionLost> = {

386

id: 'custom-connection-lost-provider',

387

provides: IConnectionLost,

388

activate: (app): IConnectionLost => {

389

return async (manager, err, translator) => {

390

// Custom implementation

391

console.error('Custom connection lost handler:', err);

392

};

393

}

394

};

395

396

// Overriding default service

397

const overrideServicePlugin: JupyterFrontEndPlugin<ILabStatus> = {

398

id: 'custom-status-provider',

399

provides: ILabStatus,

400

activate: (app): ILabStatus => {

401

// Return custom implementation

402

return new CustomLabStatus(app);

403

}

404

};

405

```

406

407

### Service Composition

408

409

```typescript

410

// Composing services to create higher-level functionality

411

const compositeServicePlugin: JupyterFrontEndPlugin<IMyCompositeService> = {

412

id: 'composite-service',

413

provides: IMyCompositeService,

414

requires: [ILabStatus, IRouter, ILayoutRestorer],

415

activate: (app, status, router, restorer): IMyCompositeService => {

416

return new MyCompositeService(status, router, restorer);

417

}

418

};

419

420

interface IMyCompositeService {

421

navigateWithBusyState(path: string): Promise<void>;

422

saveAndNavigate(path: string): Promise<void>;

423

}

424

425

class MyCompositeService implements IMyCompositeService {

426

constructor(

427

private status: ILabStatus,

428

private router: IRouter,

429

private restorer: ILayoutRestorer

430

) {}

431

432

async navigateWithBusyState(path: string): Promise<void> {

433

const busyDisposable = this.status.setBusy();

434

try {

435

this.router.navigate(path);

436

await this.restorer.restored;

437

} finally {

438

busyDisposable.dispose();

439

}

440

}

441

442

async saveAndNavigate(path: string): Promise<void> {

443

const dirtyDisposable = this.status.setDirty();

444

try {

445

// Save current state

446

await this.saveCurrentState();

447

dirtyDisposable.dispose();

448

449

// Navigate to new path

450

await this.navigateWithBusyState(path);

451

} catch (error) {

452

// Keep dirty state if save failed

453

throw error;

454

}

455

}

456

457

private async saveCurrentState(): Promise<void> {

458

// Implementation for saving state

459

}

460

}

461

```

462

463

## Service Token Best Practices

464

465

### Token Definition

466

467

```typescript

468

// Good: Descriptive token with documentation

469

const IMyService: Token<IMyService> = new Token<IMyService>(

470

'@myapp/myservice:IMyService',

471

'A service for managing custom functionality in my application.'

472

);

473

474

// Good: Interface with clear contracts

475

interface IMyService {

476

/** Initialize the service */

477

initialize(): Promise<void>;

478

479

/** Clean up resources */

480

dispose(): void;

481

}

482

```

483

484

### Error Handling

485

486

```typescript

487

// Service with proper error handling

488

const robustServicePlugin: JupyterFrontEndPlugin<void> = {

489

id: 'robust-service-plugin',

490

requires: [ILabStatus],

491

activate: (app, status: ILabStatus) => {

492

try {

493

// Service initialization

494

const disposable = status.setBusy();

495

496

// Handle service errors gracefully

497

status.busySignal.connect((sender, isBusy) => {

498

if (isBusy) {

499

// Set up error recovery

500

setTimeout(() => {

501

if (status.isBusy) {

502

console.warn('Operation taking longer than expected');

503

}

504

}, 5000);

505

}

506

});

507

508

} catch (error) {

509

console.error('Failed to initialize service:', error);

510

// Graceful degradation

511

}

512

}

513

};

514

```