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 放置小组件。