PKU harness

dashboard

看板小组件的数据类型:Widget 类型,Binding 和 WidgetSource 的 schema,以及 WidgetSize。services.widgets 也使用这些类型。

这个模块定义看板上小组件的数据结构。看板上的小组件有两种:一种由助手生成,用一份界面描述(spec)加上数据绑定(bindings)来显示;另一种由插件提供,插件自己用原生组件绘制。插件通过 services.widgets 读写小组件时,用的就是这里的类型。

源码:packages/sdk/src/dashboard.ts。概念介绍见看板。

类型与 schema

import { z } from 'zod';

export const bindingSchema = z.object({
  tool: z.string().describe('read-only tool id, e.g. "calendar.today"'),
  args: z.record(z.string(), z.unknown()).optional(),
  /** 工具结果中的点分路径;为空表示整个结果。 */
  path: z.string().optional(),
  /** 缓存有效期,单位为分钟(默认 5)。 */
  ttlMinutes: z.number().min(0).max(24 * 60).optional(),
});
export type Binding = z.infer<typeof bindingSchema>;

export const widgetSizeSchema = z
  .enum(['sm', 'md', 'lg'])
  .describe('sm = half width tile, md = full width, lg = full width hero');
export type WidgetSize = z.infer<typeof widgetSizeSchema>;

/** 插件提供的小组件(`contributes.widgets`),按键名放到看板上。 */
export const widgetSourceSchema = z.object({
  plugin: z.string(),
  widget: z.string().describe("key in the plugin's contributes.widgets"),
  config: z.record(z.string(), z.unknown()).optional(),
});
export type WidgetSource = z.infer<typeof widgetSourceSchema>;

/**
 * 两种小组件并排显示:助手生成的(`spec` + `bindings`),以及插件提供的
 * (`source`,由插件原生绘制;`spec`/`bindings` 留空)。
 */
export type Widget = {
  id: string;
  title: string;
  size: WidgetSize;
  /** json-render 界面描述({ root, elements, state? })。 */
  spec: Record<string, unknown>;
  /** state 路径(JSON pointer,例如 "/card")→ 数据来源。 */
  bindings: Record<string, Binding>;
  source?: WidgetSource;
  position: number;
  createdAt: number;
  updatedAt: number;
};

sm 是半宽的小方块,md 占满整行,lg 是占满整行的大尺寸卡片。

绑定如何填充数据

每个绑定会调用一个只读工具,再用 setPointer 把结果写进 spec 的 state。例如,一个挂在 /card、path 为 "balance" 的绑定,会让 spec 里的 { "$state": "/card" } 取到余额。

在工具里放置插件小组件

要在工具里放置插件提供的小组件,先构造一个带 source 的 Widget,再调用 put:

const w: Widget = {
  id: ctx.services.widgets.newId(),
  title: '校园卡余额',
  size: 'md',
  spec: {},
  bindings: {},
  source: { plugin: 'wallet', widget: 'card', config: { warnBelow: 30 } },
  position: ctx.services.widgets.list().length,
  createdAt: Date.now(),
  updatedAt: Date.now(),
};
await ctx.services.widgets.put(w);

大多数插件不需要这样做,因为助手会自己调用 dashboard.addPluginWidget 放置小组件。

本页目录