ToolPlex
Features

Pages

Interactive dashboards and data views powered by your own server, with AI agent assistance built in.

Pages

Pages are interactive dashboards that connect ToolPlex to your own data. Define tables, charts, KPI cards, and actions on your server — ToolPlex renders them as a polished UI with built-in filtering, sorting, selection, CSV export, and an AI agent sidebar.

Pages interface showing an orders dashboard with KPI cards, revenue charts, and a data table with inline actions

How it works

Pages are served by your own app server using the @toolplex/app-server npm package. Your server defines page layouts, data handlers, and actions. ToolPlex connects to your server, proxies the data, and renders the UI.

Your data never leaves your infrastructure except through the authenticated proxy. ToolPlex renders it — your server owns it. The connection is IP-firewalled and token-authenticated, with user auth, org isolation, and role-based page visibility enforced at the proxy layer.

Setting up your app server

1. Install the package

npm install @toolplex/app-server fastify

2. Define pages and resources

import Fastify from "fastify";
import { registerAppPages } from "@toolplex/app-server";

const server = Fastify({ logger: true });

await server.register(registerAppPages, {
  authToken: process.env.APP_TOKEN,

  pages: {
    orders: {
      title: "Orders Dashboard",
      sections: [
        { type: "card-row", source: "order_kpis" },
        {
          type: "table",
          source: "order_list",
          rowKey: "id",
          downloadable: true,
          actions: [
            { label: "Cancel", action: "cancel_order", variant: "danger" },
          ],
          columns: [
            { key: "id", label: "Order ID" },
            { key: "customer", label: "Customer" },
            { key: "total", label: "Total", format: "currency" },
            { key: "status", label: "Status", format: { type: "status", colors: { pending: "yellow", shipped: "green" } } },
          ],
        },
      ],
    },
  },

  resources: {
    order_list: {
      fetch: async ({ page, pageSize, sort, filters }) => {
        // Query your database here
        const rows = await db.query("SELECT * FROM orders ...");
        return { rows, total: rows.length };
      },
    },
    order_kpis: {
      fetch: async () => ({
        rows: [
          { label: "Revenue", value: 125000, format: "currency" },
          { label: "Pending", value: 12, format: "integer" },
        ],
        total: 2,
      }),
    },
  },

  actions: {
    cancel_order: async ({ ids, params }) => {
      await db.query("UPDATE orders SET status = 'cancelled' WHERE id = ANY($1)", [ids]);
      return { affected: ids.length, message: `${ids.length} order(s) cancelled.` };
    },
  },
});

await server.listen({ port: 3100, host: "0.0.0.0" });

3. Connect to ToolPlex

In Org Settings > Pages, configure:

  1. Enable the Pages toggle
  2. Set the Server URL Variable and Auth Token Variable (environment variables stored in Vault)
  3. Test the connection — ToolPlex will discover your pages automatically

Section types

Tables

The primary section type. Supports column formatting, sorting, pagination, column filters, inline actions, row selection, detail drawers, and CSV download.

{
  type: "table",
  source: "order_list",
  rowKey: "id",
  downloadable: true,
  actions: [
    { label: "Approve", action: "approve", variant: "success" },
  ],
  columns: [
    { key: "id", label: "ID" },
    { key: "total", label: "Total", format: "currency" },
    { key: "status", label: "Status", format: { type: "status", colors: { pending: "yellow", done: "green" } } },
  ],
  detail: { source: "order_detail" },
}

Column formats: text, integer, number, percent, currency, date, boolean, or rich formats like status (colored badges), delta (signed change), progress (bar), link, image.

KPI Cards

Summary metrics displayed as a horizontal row of cards.

{ type: "card-row", source: "order_kpis" }

The resource returns rows shaped as { label, value, format }.

Charts

Line charts, bar charts, and pie charts with optional timeframe controls.

{
  type: "chart",
  source: "revenue_trend",
  chart: "line",
  title: "Revenue Trend",
  controls: [
    { key: "range", options: ["7d", "14d", "30d"], default: "7d" },
  ],
  x: { key: "date" },
  y: [
    { key: "revenue", label: "Revenue" },
    { key: "orders", label: "Orders", color: "#6366F1", axis: "right" },
  ],
}

Charts support dual Y-axes, copy/download as CSV or PNG, and expand to full screen.

Layouts

Sections can be arranged in a 12-column grid by wrapping them in arrays with span:

sections: [
  { type: "card-row", source: "kpis" },
  [
    { type: "chart", source: "trend", span: 7, ... },
    { type: "chart", source: "breakdown", span: 5, ... },
  ],
  { type: "table", source: "data", ... },
]

Actions

Actions are buttons that trigger server-side operations. They appear inline on table rows and in the toolbar when rows are selected.

{
  label: "Transfer Stock",
  action: "transfer_stock",
  variant: "primary",
  toolbar_only: true,
  inputs: [
    { key: "to_warehouse", label: "To Warehouse", type: "select", options: ["WH-01", "WH-02"] },
    { key: "quantity", label: "Quantity", type: "number", default: 50 },
  ],
  condition: { key: "status", neq: "shipped" },
}
  • variant: default, primary, success, danger, warning
  • inputs: Dynamic form fields collected in a confirmation modal before execution
  • condition: Show/hide the action based on row values (e.g., only show "Cancel" on non-cancelled rows)
  • bulk: Set to false to hide from toolbar (single-row only)
  • toolbar_only: Set to true to hide from inline buttons
  • context: Optional resource fetched when the modal opens, rendered as additional context for the user

Every action opens a confirmation modal showing affected rows, optional inputs, and a confirm/cancel footer. No window.confirm() — a proper UI.

Page-level actions (on PageDefinition.actions) operate on the page entity itself, not rows. They appear in the page header.

Agent sidebar

Every page has an AI agent sidebar that can query the page's data, filter results, and answer questions about what's on screen.

  • Selection-aware: Select rows or charts, then ask the agent about them
  • View-aware: The agent sees the current sort, filters, and chart timeframe
  • Cmd+K: Quick shortcut to open the agent with selected context

The agent has read-only access — it cannot execute actions. Users trigger actions through the UI.

CSV download

Tables with downloadable: true get a download button. Clicking it streams the full filtered dataset as CSV directly from the server — no size limit on the client, with a 1M row safety cap on the server.

Access control

Pages are gated by two org-level controls:

Pages enabled

A global toggle in Org Settings > Pages. When off, no one in the org sees Pages. Default: off.

Per-role page visibility

In Team > Roles & Permissions > AI Settings, admins can configure which pages each role can see:

  • All pages (default): The role sees every page the server provides
  • Specific pages: Only the selected pages are visible
  • No pages: The role cannot see Pages at all

Visibility is enforced server-side — the API filters the page list and blocks access to restricted page definitions.

Data flow

All data flows through ToolPlex's proxy:

  1. Your app server is IP-firewalled to only accept connections from ToolPlex
  2. ToolPlex authenticates with a bearer token stored in Vault
  3. User requests are authenticated, org-isolated, and RBAC-filtered
  4. Data is streamed through — ToolPlex renders it, your server owns it

No data is stored by ToolPlex. Pages are stateless — every view is a live query to your server.