Pinnable Widgets

Create persistent UI widgets for your DAIN service

Overview

Pinnable widgets are persistent UI elements that remain visible and accessible whenever a user is connected to your service. They provide quick access to frequently used features without requiring AI assistance.

Configuration

A pinnable widget is defined using the ServicePinnable type:

interface ServicePinnable {
  id: string;              // Unique identifier
  name: string;           // Display name
  description: string;    // Description of functionality
  type: "widget";        // Type of pinnable
  label: string;         // Widget label
  icon: string;          // Icon identifier
  getWidget: (agentInfo: AgentInfo) => Promise<DainResponse>;  // UI generator
}

Add widgets to your service configuration:

const dainService = defineDAINService({
  // ... other config
  pinnables: [marketOverviewWidget]  // Array of pinnable widgets
});

Example: Market Overview Widget

import { 
  CardUIBuilder, 
  TableUIBuilder, 
  ChartUIBuilder,
  FormUIBuilder,
  AlertUIBuilder 
} from '@dainprotocol/utils';

const getMarketOverviewWidget: ServicePinnable = {
  id: "marketOverview",
  name: "Market Overview",
  description: "Shows current status of major market indices",
  type: "widget",
  label: "Markets",
  icon: "chart-line",
  getWidget: async () => {
    try {
      // Fetch market data
      const results = await fetchMarketData();

      // Create table of market indices
      const tableUI = new TableUIBuilder()
        .addColumns([
          { key: 'name', header: 'Index' },
          { key: 'price', header: 'Price' },
          { key: 'change', header: 'Change' },
          { key: 'changePercent', header: '%' }
        ])
        .rows(results);

      // Create quick lookup form
      const formUI = new FormUIBuilder()
        .title('Get Stock Price')
        .addField({
          name: 'ticker',
          label: 'Stock Symbol',
          type: 'string',
          required: true,
        })
        .onSubmit({
          tool: 'get-stock-price',
          paramSchema: {
            ticker: { type: 'string' }
          }
        });

      // Create overview chart
      const chartUI = new ChartUIBuilder()
        .type('line')
        .title('Market Trends')
        .chartData(results)
        .dataKeys({
          x: 'time',
          y: 'price'
        });

      // Compose final layout
      const cardUI = new CardUIBuilder()
        .addChild(formUI.build())
        .addChild(tableUI.build())
        .addChild(chartUI.build());

      return new DainResponse({
        text: "Market overview data loaded",
        data: results,
        ui: cardUI.build()
      });
    } catch (error) {
      return new DainResponse({
        text: "Failed to load market overview",
        data: null,
        ui: new AlertUIBuilder()
          .variant('error')
          .message('Unable to load market data')
          .build()
      });
    }
  }
};

Common Use Cases

Pinnable widgets are ideal for:

  • Data dashboards
  • Quick search forms
  • Status monitors
  • Activity feeds
  • User preferences
  • Recent items
  • Quick actions
  • Analytics views