Example: Components Table Widget

Source project: octopus-widgets/ska-octopus-components-table-widget

Why This Example Matters

It combines:

  • Rich schema shortcuts (INPUT_DEVICES, INPUT_ATTRIBUTES, INPUT_STRINGS)

  • Table interaction persistence (order, widths, sort)

  • Live stream + polling behavior switch

  • Brush filtering and hover value mapping

Definition Pattern

In src/index.ts, the widget:

  • Defines a single schema with both user and persisted table settings

  • Uses polls: true to participate in refresh behavior

  • Exposes a stable key and docsUrl

Snippet adapted from src/index.ts:

const schema = {
  type: "object",
  properties: {
    devices: {
      type: INPUT_DEVICES,
      title: "Devices (rows)",
      minItems: 1,
      default: [{ endpoint: "", device: "low-mccs/tile/s8-1-tpm01" }],
    },
    attributes: {
      type: INPUT_ATTRIBUTES,
      title: "Attributes (columns)",
      default: ["Status", "State", "HealthState"],
    },
    columnOrder: { type: "array", default: [] },
    columnWidths: { type: "object", default: {} },
    sortKey: { type: "string", default: "__component__" },
    sortDir: { type: "string", enum: ["asc", "desc"], default: "asc" },
  },
} as const;

Runtime Pattern

In src/ComponentsTableWidget.tsx, the widget:

  • Normalizes input devices once using variables

  • Reads host layout with useWidgetLayout(instanceId)

  • Persists user table interactions with useWidgetConfigPersistence(instanceId)

  • Applies brush filtering via useBrush

Snippet adapted from src/ComponentsTableWidget.tsx:

const { persistConfig } = useWidgetConfigPersistence(instanceId);

const handleColumnOrderChange = (nextOrder: string[]) => {
  persistConfig({ columnOrder: nextOrder });
};

const handleSortChange = (next: { key: string; dir: "asc" | "desc" }) => {
  persistConfig({ sortKey: next.key, sortDir: next.dir });
};

Table Rendering Pattern

In src/components/ComponentsTable.tsx, the widget:

  • Uses useInteractiveTableState as the state engine

  • Uses InteractiveTable as the rendering layer

  • Uses StateChip for enum-like values

  • Computes responsive width fitting before first user resize

What To Reuse In New Widgets

  • Schema-first configuration approach from src/index.ts

  • Persistence callbacks from src/ComponentsTableWidget.tsx

  • Shared table toolkit integration from src/components/ComponentsTable.tsx

Related docs: