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

To wire a new operation into iLoader's UI, define an Operation constant in src/components/operations.ts, add the corresponding translation keys to your locale JSON files, and invoke startOperation() from 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. 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. 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 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), the display strings (locale JSON files), and the trigger mechanism (App.tsx).

Step 1: Define the Operation in operations.ts

Create a new Operation constant in src/components/operations.ts alongside the existing exports. This object determines the workflow structure that appears in the progress modal.

// 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.

// 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, 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 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.

// 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, the actual execution logic for each step typically resides in service files like 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 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 – Central registry where you define the Operation constant and step flow.
  • src/components/OperationView.tsx – Renders the progress modal; consumes the metadata from your operation definition to display titles and step indicators.
  • 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 (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 with unique IDs and translation keys.
  • Localize the user-facing strings by adding entries to src/locales/en.json and other supported language files.
  • Trigger the workflow by importing the operation into 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 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 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 or domain-specific modules that handle device communication. The UI layer in 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, 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →