# How to Wire a New Operation into iLoader's UI: A Complete Guide

> Learn how to wire a new operation into iLoader's UI. Follow this guide to define operations, add translations, and launch workflows using startOperation in App.tsx.

- Repository: [Nicholas Sharp/iloader](https://github.com/nab138/iloader)
- Tags: how-to-guide
- Published: 2026-09-12

---

**To wire a new operation into iLoader's UI, define an `Operation` constant in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts), add the corresponding translation keys to your locale JSON files, and invoke `startOperation()` from [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx) to launch the workflow in the built-in progress modal.**

iLoader is an open-source Android device management tool built with a modular TypeScript architecture. According to the nab138/iloader source code, every user-facing workflow—from sideloading APKs to managing live containers—is orchestrated through the **Operation** abstraction defined in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts). Learning how to wire a new operation into iLoader's UI enables you to extend the application with custom device management tasks while leveraging the existing internationalization system and progress tracking modal.

## Understanding the Operation Architecture

At the core of iLoader's extensibility is the `Operation` interface exported from [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts). Each operation defines a unique identifier, translation keys for titles and success messages, and an ordered array of steps that the user will see in the progress modal.

The `OperationView` component in [`src/components/OperationView.tsx`](https://github.com/nab138/iloader/blob/main/src/components/OperationView.tsx) renders these workflows visually. It reads the current `OperationState`—created when you call `startOperation()`—and displays step progress, error handling, and completion states based on the metadata you provide in the operation definition.

To successfully wire a new operation into the UI, you must connect three layers: the data definition ([`operations.ts`](https://github.com/nab138/iloader/blob/main/operations.ts)), the display strings (locale JSON files), and the trigger mechanism ([`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx)).

## Step 1: Define the Operation in operations.ts

Create a new `Operation` constant in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts) alongside the existing exports. This object determines the workflow structure that appears in the progress modal.

```typescript
// src/components/operations.ts
export const exportDeviceLogsOperation: Operation = {
  id: "export_device_logs",
  titleKey: "operations.export_device_logs_title",
  successTitleKey: "operations.export_device_logs_success_title",
  successMessageKey: "operations.export_device_logs_success_message",
  steps: [
    {
      id: "gather",
      titleKey: "operations.export_device_logs_step_gather",
    },
    {
      id: "save",
      titleKey: "operations.export_device_logs_step_save",
    },
  ],
};

```

The `steps` array defines the sequential checkpoints that `OperationView` will render as progress indicators. Each step requires a unique `id` and a `titleKey` that maps to your translation files.

## Step 2: Add Translation Keys to Locale Files

iLoader uses a JSON-based internationalization system stored in `src/locales/`. Add translation entries for every `titleKey` and `messageKey` referenced in your operation definition.

```json
// src/locales/en.json
{
  "operations": {
    "export_device_logs_title": "Export Device Logs",
    "export_device_logs_success_title": "Logs Exported Successfully",
    "export_device_logs_success_message": "Your device logs have been saved.",
    "export_device_logs_step_gather": "Gathering logs from the device",
    "export_device_logs_step_save": "Saving logs to a file"
  }
}

```

Repeat this process for every language your application supports (e.g., [`src/locales/zh_cn.json`](https://github.com/nab138/iloader/blob/main/src/locales/zh_cn.json), [`src/locales/de.json`](https://github.com/nab138/iloader/blob/main/src/locales/de.json)). The keys must match exactly the strings defined in your `Operation` constant.

## Step 3: Wire the UI Trigger in App.tsx

Import your new operation constant into [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx) and invoke the `startOperation` helper when the user interacts with a button or menu item. This function creates the `OperationState` that drives the modal view.

```typescript
// src/App.tsx
import { exportDeviceLogsOperation } from "./components/operations";

// Inside your component's return statement or event handler
<button
  onClick={async () => {
    if (!ensuredLoggedIn() || !ensureSelectedDevice()) return;
    
    // Optional: Collect user input (e.g., file path) here
    const params = { destinationPath: "/user/logs" };
    
    startOperation(exportDeviceLogsOperation, params)
      .catch((e) => {
        console.error(e.type, e.message);
      });
  }}
>
  {t("app.export_device_logs")}
</button>

```

The `startOperation` function accepts two arguments: the `Operation` constant and an optional parameters object. Use the parameters to pass data—such as file paths or device IDs—to the underlying implementation logic that executes the actual work.

## Step 4: Implement Step Logic (Optional)

While the UI structure lives in [`operations.ts`](https://github.com/nab138/iloader/blob/main/operations.ts), the actual execution logic for each step typically resides in service files like [`src/update.ts`](https://github.com/nab138/iloader/blob/main/src/update.ts) or dedicated workflow modules. Your implementation should reference the `id` of each step defined in the operation to update progress through the `OperationState` API.

If your operation requires custom UI elements—such as a file picker dialog—present these before calling `startOperation()` and pass the collected data via the parameters object. The modal managed by [`OperationView.tsx`](https://github.com/nab138/iloader/blob/main/OperationView.tsx) handles standard progress display, so custom UI components are only necessary for pre-operation input collection.

## Critical Files for Operation Integration

When wiring a new operation into iLoader's UI, you will modify these specific files:

- **[`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts)** – Central registry where you define the `Operation` constant and step flow.
- **[`src/components/OperationView.tsx`](https://github.com/nab138/iloader/blob/main/src/components/OperationView.tsx)** – Renders the progress modal; consumes the metadata from your operation definition to display titles and step indicators.
- **[`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx)** – Contains the trigger buttons that call `startOperation()`; the entry point for user interaction.
- **`src/locales/*.json`** – Houses translation strings for operation titles, step descriptions, and success messages.
- **[`src/update.ts`](https://github.com/nab138/iloader/blob/main/src/update.ts)** (or similar service files) – Implements the actual device-side logic that executes during each step of the operation.

## Summary

Wiring a new operation into iLoader's UI requires coordination between the operation definition, translation system, and trigger mechanism:

- Define the workflow structure by exporting an `Operation` constant from [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts) with unique IDs and translation keys.
- Localize the user-facing strings by adding entries to [`src/locales/en.json`](https://github.com/nab138/iloader/blob/main/src/locales/en.json) and other supported language files.
- Trigger the workflow by importing the operation into [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx) and calling `startOperation()` with any required parameters.
- Implement the actual step execution logic in appropriate service files, referencing the step IDs defined in your operation.

## Frequently Asked Questions

### What is the Operation abstraction in iLoader?

The **Operation** abstraction is a TypeScript interface defined in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts) that standardizes how iLoader represents user workflows. It encapsulates the workflow ID, display titles (via translation keys), success messages, and an ordered list of steps. This abstraction allows [`OperationView.tsx`](https://github.com/nab138/iloader/blob/main/OperationView.tsx) to render a consistent progress modal for any device management task without knowing the specific implementation details.

### Where should I implement the logic for my new operation's steps?

Step execution logic belongs in service files such as [`src/update.ts`](https://github.com/nab138/iloader/blob/main/src/update.ts) or domain-specific modules that handle device communication. The UI layer in [`operations.ts`](https://github.com/nab138/iloader/blob/main/operations.ts) only defines the structure and display metadata; the actual work—such as gathering logs or sideloading files—should be implemented separately and update the operation's progress state programmatically. Pass necessary data from the UI to these services via the parameters argument in `startOperation()`.

### How do I handle user input like file selection before starting an operation?

Collect user input in the event handler before calling `startOperation()`. For example, open a file dialog in the button's `onClick` handler within [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx), then pass the selected path as a property in the parameters object. The operation implementation in your service file receives these parameters and can use them during step execution. This keeps the `Operation` definition clean of UI-specific logic while allowing dynamic data flow.

### Can I add or skip steps dynamically while an operation is running?

The `Operation` interface defines a static step list for display purposes in [`OperationView.tsx`](https://github.com/nab138/iloader/blob/main/OperationView.tsx). However, the underlying execution logic can control which steps are actually executed or how they behave based on runtime conditions. While the visual progress indicators in the modal reflect the static steps array, your implementation code can skip internal processing steps or add conditional sub-tasks without modifying the operation definition, provided you manage the state transitions appropriately within your service layer.