API del SDK de Dashboards
Accedé al namespace de dashboards via sdk.dashboards. Una sesión de dashboard
(instancia de Dashboard) se abre con sdk.dashboards.open() o
sdk.dashboards.view() y comunica sobre un documento CRDT Y.js en vivo.
El campo visibility acepta private, workspace y public. (unlisted es un
alias legacy retirado, aún aceptado en la API y tratado como public.)
Nivel superior: sdk.dashboards
Sección titulada «Nivel superior: sdk.dashboards»sdk.dashboards.create()
Sección titulada «sdk.dashboards.create()»create(options: CreateOptions): Promise<CreateResult>
interface CreateOptions { title: string; description?: string; template?: string; layout?: 'fixed' | 'responsive'; columns?: number; // default 12 rowHeight?: number; // default 80 (px) visibility?: 'private' | 'workspace' | 'public';}
interface CreateResult { id: string; editorUrl: string; // shareout.site/a/{slug} publishedUrl: string; // shareout.site/p/{slug} editorArtifactId: string; publishedArtifactId: string;}const result = await sdk.dashboards.create({ title: 'Sales Dashboard', visibility: 'public',});sdk.dashboards.open()
Sección titulada «sdk.dashboards.open()»Abre un dashboard para editar. Requiere autenticación. Devuelve una instancia
de Dashboard ya conectada.
open(id: string): Promise<Dashboard>sdk.dashboards.view()
Sección titulada «sdk.dashboards.view()»Abre un dashboard en modo publicado/vista. No requiere autenticación para
dashboards public.
view(id: string): Promise<Dashboard>sdk.dashboards.list()
Sección titulada «sdk.dashboards.list()»list(): Promise<DashboardInfo[]>
interface DashboardInfo { id: string; title: string; widgetCount: number; editorUrl: string; publishedUrl: string; visibility: 'private' | 'workspace' | 'public'; createdAt: string; updatedAt: string;}sdk.dashboards.delete()
Sección titulada «sdk.dashboards.delete()»delete(id: string): Promise<boolean>Devuelve false si no existe; lanza excepción en otros errores.
Instancia de Dashboard
Sección titulada «Instancia de Dashboard»Devuelta por open() y view(). La conexión se establece automáticamente;
no necesitás llamar a connect() manualmente.
connect(): Promise<void> // reconectar después de un disconnectdisconnect(): void // desconectar pero mantener el documentodestroy(): void // limpieza completadashboard.meta
Sección titulada «dashboard.meta»Configuración a nivel del dashboard. Las propiedades establecidas acá se propagan en cascada a todos los widgets, a menos que un widget especifique un override.
meta.get()
Sección titulada «meta.get()»get(): DashboardMeta
interface DashboardMeta { id: string; title: string; description: string;
// Layout layout: 'fixed' | 'responsive'; columns: number; rowHeight: number; gap: number; padding: number;
// Defaults visuales en cascada (heredados por widgets) defaultFont: { heading: string; body: string; mono: string }; defaultColors: { background: string; surface: string; text: string; textSecondary: string; accent: string; positive: string; negative: string; neutral: string; };
// Defaults de datos refreshInterval: number | null; // auto-refresh en segundos timezone: string; dateFormat: string; numberFormat: { locale: string; currency?: string };
createdBy: string; updatedAt: string;}meta.set()
Sección titulada «meta.set()»set(changes: Partial<DashboardMeta>): voiddashboard.meta.set({ title: 'Dashboard Q4 Ventas', defaultColors: { background: '#0f172a', surface: '#1e293b', text: '#f8fafc', accent: '#3b82f6', }, refreshInterval: 300,});meta.observe()
Sección titulada «meta.observe()»observe(handler: (meta: DashboardMeta) => void): () => voidDevuelve una función para cancelar la suscripción.
dashboard.widgets
Sección titulada «dashboard.widgets»widgets.list()
Sección titulada «widgets.list()»list(): Widget[]
interface Widget { id: string; type: WidgetType; title: string; dataSource: string | null; query?: DataQuery; config: WidgetConfig; overrides?: WidgetOverrides; owner: string | null; locked: boolean;}
type WidgetType = 'kpi' | 'chart' | 'table' | 'text' | 'image' | 'embed' | 'filter' | 'html';
interface DataQuery { filter?: Record<string, any>; sort?: { field: string; order: 'asc' | 'desc' }; limit?: number; transform?: string; // expresión JavaScript de transformación}
interface WidgetOverrides { surface?: string; font?: { heading?: string; body?: string; mono?: string };}widgets.get()
Sección titulada «widgets.get()»get(id: string): Widget | nullwidgets.add()
Sección titulada «widgets.add()»add(type: WidgetType, config: WidgetConfig, position?: LayoutItem): Widget
interface LayoutItem { x: number; // columna de inicio (índice cero) y: number; // fila de inicio w: number; // ancho en columnas h: number; // alto en filas minW?: number; maxW?: number; minH?: number; maxH?: number;}Formas de config por tipo — ver KPI config, Chart config, Table config más abajo.
widgets.update()
Sección titulada «widgets.update()»update(id: string, changes: Partial<Widget>): voidwidgets.delete()
Sección titulada «widgets.delete()»delete(id: string): booleanwidgets.duplicate()
Sección titulada «widgets.duplicate()»duplicate(id: string): Widgetwidgets.observe()
Sección titulada «widgets.observe()»observe(handler: (widgets: Widget[]) => void): () => voidwidgets.getContent() / widgets.setContent()
Sección titulada «widgets.getContent() / widgets.setContent()»Para widgets html y text. getContent() devuelve un Y.Text para binding
colaborativo; setContent() reemplaza el contenido directamente.
getContent(id: string): Y.TextsetContent(id: string, html: string): voidwidgets.setOwner() / widgets.lock() / widgets.unlock()
Sección titulada «widgets.setOwner() / widgets.lock() / widgets.unlock()»setOwner(id: string, userId: string | null): voidlock(id: string): voidunlock(id: string): voidLos widgets bloqueados solo pueden editarlos su owner.
dashboard.layout
Sección titulada «dashboard.layout»Gestión de posiciones en la grilla.
get(): LayoutItem[]update(widgetId: string, position: Partial<LayoutItem>): voidmove(widgetId: string, x: number, y: number): voidresize(widgetId: string, w: number, h: number): voidobserve(handler: (layout: LayoutItem[]) => void): () => voiddashboard.dataSources
Sección titulada «dashboard.dataSources»type DataSourceType = 'static' | 'api' | 'sql' | 'shareout' | 'csv' | 'websocket';
interface DataSource { id: string; name: string; type: DataSourceType; config: DataSourceConfig; refreshInterval?: number; lastRefreshed?: string;}Métodos
Sección titulada «Métodos»list(): DataSource[]add(config: Omit<DataSource, 'id'>): DataSourceupdate(id: string, changes: Partial<DataSource>): voiddelete(id: string): booleanrefresh(id: string): Promise<void>refreshAll(): Promise<void>getData(id: string): any[]getFilteredData(id: string): any[]observe(id: string, handler: (data: any[]) => void): () => void// Datos estáticosdashboard.dataSources.add({ name: 'Datos de Ventas', type: 'static', config: { data: salesArray },});
// REST API con auto-refreshdashboard.dataSources.add({ name: 'Métricas en Vivo', type: 'api', config: { url: 'https://api.example.com/metrics', method: 'GET', headers: { Authorization: 'Bearer ...' }, }, refreshInterval: 60,});
// Tabla de ShareOutdashboard.dataSources.add({ name: 'Clientes', type: 'shareout', config: { tableId: 'customers' },});dashboard.filters
Sección titulada «dashboard.filters»Definiciones de filtros
Sección titulada «Definiciones de filtros»interface FilterDefinition { id: string; type: 'select' | 'multiselect' | 'daterange' | 'numberrange' | 'search'; label: string; dataSource?: string; field?: string; options?: { value: string; label: string }[]; defaultValue?: FilterValue; affects: string[]; // IDs de widgets o '*' para todos}
type FilterValue = | string | string[] | { from: string; to: string } | { min: number; max: number };Métodos
Sección titulada «Métodos»getDefinitions(): FilterDefinition[]addDefinition(def: Omit<FilterDefinition, 'id'>): FilterDefinitionupdateDefinition(id: string, changes: Partial<FilterDefinition>): voiddeleteDefinition(id: string): booleangetState(): FilterState // { [filterId]: FilterValue }setValue(filterId: string, value: FilterValue): voidreset(): void // resetear todos a sus defaultsobserve(handler: (state: FilterState) => void): () => voiddashboard.presets
Sección titulada «dashboard.presets»Combinaciones de filtros guardadas para acceso rápido.
interface FilterPreset { id: string; name: string; description?: string; icon?: string; color?: string; filters: FilterState; isDefault: boolean; isPinned: boolean; isShared: boolean; createdBy: string; createdAt: string;}list(): FilterPreset[]create(preset: Omit<FilterPreset, 'id' | 'createdAt'>): FilterPresetupdate(id: string, changes: Partial<FilterPreset>): voiddelete(id: string): booleanapply(id: string): voidsetDefault(id: string | null): voidgetDefault(): FilterPreset | nullpin(id: string): voidunpin(id: string): voidgetPinned(): FilterPreset[]observe(handler: (presets: FilterPreset[]) => void): () => voiddashboard.presets.create({ name: 'Q4 2026', icon: '📊', filters: dashboard.filters.getState(), isPinned: true, isShared: true, isDefault: false,});
dashboard.presets.apply('preset-q4-2026');dashboard.presets.setDefault('preset-this-week');dashboard.interactions
Sección titulada «dashboard.interactions»Interacciones entre widgets: hacer click en uno filtra a otros.
interface InteractionConfig { id?: string; trigger: { widgetId: string; event: 'click' | 'select' | 'hover'; field?: string; }; action: { type: 'filter' | 'navigate' | 'highlight' | 'custom'; target: string | string[]; // IDs de widgets o '*' config: any; };}define(config: InteractionConfig): string // devuelve el ID de la interacciónremove(id: string): voidlist(): InteractionConfig[]trigger(widgetId: string, event: 'click' | 'select' | 'hover', data: Record<string, unknown>): voidonInteraction(handler: (event: InteractionEvent) => void): () => voidonWidgetInteraction(widgetId: string, handler: (event: InteractionEvent) => void): () => voiddashboard.interactions.define({ trigger: { widgetId: 'sales-chart', event: 'click', field: 'region' }, action: { type: 'filter', target: ['sales-table', 'kpi-revenue'], config: { filterField: 'region' }, },});dashboard.presenter
Sección titulada «dashboard.presenter»El modo presentador sincroniza foco, puntero y ciclo automático a todos los viewers en tiempo real.
start(options?: PresenterOptions): Promise<void>stop(): voidstate(): DashboardPresentationStateisActive(): booleanisPresenter(): boolean
// Foco de widgetsfocusWidget(widgetId: string): voidclearFocus(): voidnextWidget(): voidpreviousWidget(): void
// Ciclo automáticostartCycle(options?: CycleOptions): voidstopCycle(): void
// Timertimer.elapsed(): numbertimer.setCountdown(seconds: number): voidtimer.remaining(): number | nulltimer.pause(): voidtimer.resume(): void
// Punteropointer.enable(): voidpointer.disable(): voidpointer.move(x: number, y: number): void
subscribe(handler: (state: DashboardPresentationState) => void): () => voidawait dashboard.presenter.start({ countdown: 1800 }); // timer de 30 mindashboard.presenter.focusWidget('kpi-revenue');dashboard.presenter.startCycle({ interval: 30, loop: true });dashboard.versions
Sección titulada «dashboard.versions»versions.list(): Promise<Version[]>versions.create(name: string, description?: string): Promise<Version>versions.restore(versionId: string): Promise<void>versions.diff(fromId: string, toId: string): Promise<VersionDiff>versions.delete(versionId: string): Promise<boolean>versions.subscribe(handler: (versions: Version[]) => void): () => voidawait dashboard.versions.create('Antes de la reunión', 'Snapshot antes de ediciones en vivo');const versions = await dashboard.versions.list();await dashboard.versions.restore(versions[2].id);dashboard.publish
Sección titulada «dashboard.publish»getUrl(): string // shareout.site/p/{slug}setVisibility(v: 'private' | 'workspace' | 'public'): voidunpublish(): voidrepublish(): voiddashboard.presence
Sección titulada «dashboard.presence»Presencia efímera de usuarios sobre WebSocket (no persiste en el documento Y.js).
set(state: Partial<DashboardPresenceState>): voidget(): Map<string, DashboardPresenceState>subscribe(handler: (users: Map<string, DashboardPresenceState>) => void): () => voiddashboard.undo
Sección titulada «dashboard.undo»Stack de undo por usuario, limitado a los cambios propios.
undo.manager(): Y.UndoManagerundo.canUndo(): booleanundo.canRedo(): booleanundo.undo(): voidundo.redo(): voiddashboard.transact()
Sección titulada «dashboard.transact()»Agrupa múltiples cambios en un único paso de undo.
transact(fn: () => void): voiddashboard.transact(() => { const widget = dashboard.widgets.add('kpi', config, position); dashboard.widgets.setOwner(widget.id, currentUserId);});// Ambos cambios aparecen como un único paso de undoEventos
Sección titulada «Eventos»dashboard.on(event: DashboardEvent, handler: Function): voiddashboard.off(event: DashboardEvent, handler: Function): void
type DashboardEvent = | 'widget:added' | 'widget:deleted' | 'widget:updated' | 'layout:changed' | 'filter:changed' | 'data:refreshed' | 'presentation:start' | 'presentation:end' | 'sync' | 'status';sdk.dashboards.helpers
Sección titulada «sdk.dashboards.helpers»Utilidades de formateo y datos.
helpers.formatNumber(value: number, options?: Intl.NumberFormatOptions): stringhelpers.formatCurrency(value: number, currency?: string): stringhelpers.formatPercent(value: number, decimals?: number): stringhelpers.formatDate(date: Date | string, format?: string): string
helpers.getColorScale(type: 'sequential' | 'diverging' | 'categorical', name?: string): string[]helpers.getSemanticColor(type: 'positive' | 'negative' | 'neutral' | 'warning'): string
helpers.aggregate(data: any[], groupBy: string, aggs: Aggregation[]): any[]helpers.pivot(data: any[], rows: string, cols: string, values: string): any[]helpers.timeSeries(data: any[], dateField: string, interval: 'day' | 'week' | 'month'): any[]Tipos de config de widgets
Sección titulada «Tipos de config de widgets»KPI config
Sección titulada «KPI config»interface KPIConfig { value: string; label: string; format: 'number' | 'currency' | 'percent' | 'custom'; formatOptions?: Intl.NumberFormatOptions; comparison?: { value: string; type: 'absolute' | 'percent'; invertColors?: boolean; }; sparkline?: { field: string; type: 'line' | 'bar' | 'area' }; icon?: string; size?: 'sm' | 'md' | 'lg';}Chart config
Sección titulada «Chart config»interface ChartConfig { chartType: 'line' | 'bar' | 'area' | 'pie' | 'donut' | 'scatter' | 'heatmap' | 'gauge' | 'funnel' | 'treemap'; xAxis?: { field: string; type: 'category' | 'time' | 'value'; label?: string }; yAxis?: { field: string; label?: string; min?: number; max?: number }; series?: { field: string; name?: string; color?: string }[]; nameField?: string; valueField?: string; legend?: { show: boolean; position: 'top' | 'bottom' | 'left' | 'right' }; tooltip?: { show: boolean }; animation?: boolean;}Table config
Sección titulada «Table config»interface TableConfig { columns: TableColumn[]; pageSize?: number; sortable?: boolean; filterable?: boolean; exportable?: boolean; selectable?: boolean; condensed?: boolean; striped?: boolean;}
interface TableColumn { field: string; header: string; width?: string; align?: 'left' | 'center' | 'right'; format?: 'text' | 'number' | 'currency' | 'percent' | 'date' | 'boolean' | 'link' | 'image' | 'badge'; sortable?: boolean; filterable?: boolean;}Text config
Sección titulada «Text config»interface TextConfig { content: string; contentType: 'markdown' | 'html'; align?: 'left' | 'center' | 'right'; padding?: number;}HTML config
Sección titulada «HTML config»interface HTMLConfig { content: string; scripts?: boolean; // default false}Modelo de datos
Sección titulada «Modelo de datos»El documento Y.js que respalda cada dashboard tiene los siguientes maps de nivel superior:
| Map | Tipo | Contenido |
|---|---|---|
meta | Y.Map | Metadata del dashboard y propiedades visuales en cascada |
widgets | Y.Map<string, Widget> | Definiciones de widgets indexadas por widget ID |
widgetContent | Y.Map<string, Y.Text> | Contenido HTML/text colaborativo para widgets html y text |
layout | Y.Map<string, LayoutItem> | Posiciones en la grilla indexadas por widget ID |
dataSources | Y.Map<string, DataSource> | Configuraciones de conexiones de datos |
filters | Y.Map<string, FilterValue> | Estado actual de los filtros |
filterDefs | Y.Array<FilterDefinition> | Definiciones de filtros |
filterPresets | Y.Map<string, FilterPreset> | Combinaciones de filtros guardadas |
interactions | Y.Map<string, InteractionConfig> | Configuraciones de interacciones entre widgets |
presentationState | Y.Map | Estado del presentador en vivo (sincronizado a todos los viewers) |
El estado de presencia es efímero — no está en el documento Y.js; viaja solo por el WebSocket.
Los snapshots de versiones se almacenan por separado como state vectors Y.js
codificados en la tabla dashboard_versions, no embebidos en el documento en
vivo.