Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions api_docs/kbn_dashboard_agent_common.devdocs.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@
"functions": [
{
"parentPluginId": "@kbn/dashboard-agent-common",
"id": "def-common.attachmentToDashboardState",
"id": "def-common.attachmentDataToDashboardState",
"type": "Function",
"tags": [],
"label": "attachmentToDashboardState",
"label": "attachmentDataToDashboardState",
"description": [
"\nConverts a DashboardAttachment to a DashboardState.\nUses provided values from the attachment, falling back to defaults for missing fields."
"\nConverts dashboard attachment data to a DashboardState.\nUses provided values from the attachment data, falling back to defaults for missing fields."
],
"signature": [
"({ data: { panels, filters, pinned_panels, access_control, options, ...rest }, }: ",
"({ panels = [], filters, pinned_panels, access_control, options, ...rest }: ",
{
"pluginId": "@kbn/dashboard-agent-common",
"scope": "common",
"docId": "kibKbnDashboardAgentCommonPluginApi",
"section": "def-common.DashboardAttachment",
"text": "DashboardAttachment"
"section": "def-common.DashboardAttachmentData",
"text": "DashboardAttachmentData"
},
") => ",
{
Expand Down Expand Up @@ -63,18 +63,18 @@
"children": [
{
"parentPluginId": "@kbn/dashboard-agent-common",
"id": "def-common.attachmentToDashboardState.$1",
"id": "def-common.attachmentDataToDashboardState.$1",
"type": "Object",
"tags": [],
"label": "{\n data: { panels = [], filters, pinned_panels, access_control, options, ...rest },\n}",
"label": "{\n panels = [],\n filters,\n pinned_panels,\n access_control,\n options,\n ...rest\n}",
"description": [],
"signature": [
{
"pluginId": "@kbn/dashboard-agent-common",
"scope": "common",
"docId": "kibKbnDashboardAgentCommonPluginApi",
"section": "def-common.DashboardAttachment",
"text": "DashboardAttachment"
"section": "def-common.DashboardAttachmentData",
"text": "DashboardAttachmentData"
}
],
"path": "x-pack/platform/packages/shared/dashboard-agent/dashboard-agent-common/converters/from_attachment.ts",
Expand All @@ -90,10 +90,10 @@
},
{
"parentPluginId": "@kbn/dashboard-agent-common",
"id": "def-common.dashboardStateToAttachment",
"id": "def-common.dashboardStateToAttachmentData",
"type": "Function",
"tags": [],
"label": "dashboardStateToAttachment",
"label": "dashboardStateToAttachmentData",
"description": [
"\nConverts a DashboardState to DashboardAttachmentData.\nPreserves all dashboard state fields for full round-trip support."
],
Expand Down Expand Up @@ -124,7 +124,7 @@
"children": [
{
"parentPluginId": "@kbn/dashboard-agent-common",
"id": "def-common.dashboardStateToAttachment.$1",
"id": "def-common.dashboardStateToAttachmentData.$1",
"type": "Object",
"tags": [],
"label": "state",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { isLensAPIFormat } from '@kbn/lens-embeddable-utils/config_builder/utils
import type {
AttachmentPanel,
DashboardSection as AgentDashboardSection,
DashboardAttachment,
DashboardAttachmentData,
} from '../types';
import { isSection } from '../types';

Expand Down Expand Up @@ -97,9 +97,15 @@ const EMPTY_DASHBOARD_STATE: Readonly<Omit<Required<DashboardState>, 'project_ro
* Converts a DashboardAttachment to a DashboardState.
* Uses provided values from the attachment, falling back to defaults for missing fields.
*/
export const attachmentToDashboardState = ({
data: { panels = [], filters, query, pinned_panels, access_control, options, ...rest },
}: DashboardAttachment): DashboardState => ({
export const attachmentDataToDashboardState = ({
panels = [],
filters,
query,
pinned_panels,
access_control,
options,
...rest
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
}: DashboardAttachmentData): DashboardState => ({
...EMPTY_DASHBOARD_STATE,
...rest,
options: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
* 2.0.
*/

export { isLensAttributes, dashboardStateToAttachment } from './to_attachment';
export { isLensAttributes, dashboardStateToAttachmentData } from './to_attachment';

export { attachmentToDashboardState, DEFAULT_TIME_RANGE } from './from_attachment';
export { attachmentDataToDashboardState, DEFAULT_TIME_RANGE } from './from_attachment';

export {
toEmbeddablePanel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const toAttachmentWidget = (
* Converts a DashboardState to DashboardAttachmentData.
* Preserves all dashboard state fields for full round-trip support.
*/
export const dashboardStateToAttachment = (state: DashboardState): DashboardAttachmentData => {
export const dashboardStateToAttachmentData = (state: DashboardState): DashboardAttachmentData => {
return {
...state,
panels: state.panels
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { z } from '@kbn/zod/v4';

// ============================================================================
// Panel Grid Schema - ideally we should import the schema from dashboard schemas, but they use config-schema library
// which is not compatible with Zod, so we duplicate the relevant parts here for validation of attachment data.
// ============================================================================

/**
* Grid dimensions (in dashboard grid units) for layout.
* Dashboard grid is 48 columns wide; height is in same units.
*/
export const panelGridSchema = z.object({
x: z.number(),
y: z.number(),
w: z.number().int().min(1).max(48),
h: z.number().int().min(1),
});

// ============================================================================
// Panel Schema
// ============================================================================

/**
* Zod schema for dashboard panel entries.
* The `type` field contains the actual embeddable type.
*/
const attachmentPanelSchema = z.object({
type: z.string(),
uid: z.string(),
config: z.record(z.string(), z.unknown()),
grid: panelGridSchema,
});

export type AttachmentPanel = z.infer<typeof attachmentPanelSchema>;

// ============================================================================
// Section Schema
// ============================================================================

export const sectionGridSchema = z.object({
y: z.number().int().min(0).describe('Section position in outer dashboard grid coordinates.'),
});

const dashboardSectionSchema = z.object({
uid: z.string(),
title: z.string(),
collapsed: z.boolean(),
grid: sectionGridSchema,
panels: z.array(attachmentPanelSchema),
});

export type DashboardSection = z.infer<typeof dashboardSectionSchema>;

export const isSection = (
widget: AttachmentPanel | DashboardSection
): widget is DashboardSection => {
return 'panels' in widget;
};

// ============================================================================
// Query Schema
// ============================================================================

const querySchema = z.object({
expression: z.union([z.string(), z.record(z.string(), z.unknown())]),
language: z.string(),
});

// ============================================================================
// Time Range Schema
// ============================================================================

const timeRangeSchema = z.object({
from: z.string(),
to: z.string(),
mode: z.union([z.literal('absolute'), z.literal('relative')]).optional(),
});

// ============================================================================
// Refresh Interval Schema
// ============================================================================

const refreshIntervalSchema = z.object({
pause: z.boolean(),
value: z.number(),
});

// ============================================================================
// Dashboard Options Schema
// ============================================================================

const optionsSchema = z.object({
auto_apply_filters: z.boolean().optional(),
hide_panel_titles: z.boolean().optional(),
hide_panel_borders: z.boolean().optional(),
use_margins: z.boolean().optional(),
sync_colors: z.boolean().optional(),
sync_tooltips: z.boolean().optional(),
sync_cursor: z.boolean().optional(),
});

// ============================================================================
// Access Control Schema
// ============================================================================

const accessControlSchema = z
.object({
access_mode: z.union([z.literal('write_restricted'), z.literal('default')]).optional(),
})
.optional();

// ============================================================================
// Filter Schema
// ============================================================================

// Filters have complex union types that are difficult to express precisely in Zod.
const filterSchema = z.record(z.string(), z.unknown());

// ============================================================================
// Pinned Panels (Controls) Schema
// ============================================================================

// Controls have complex union types. We use a permissive schema here.
const pinnedControlSchema = z.record(z.string(), z.unknown());
const pinnedPanelsSchema = z.array(pinnedControlSchema);

// ============================================================================
// Dashboard Attachment Data Schema (matches DashboardState)
// ============================================================================

/**
* Zod schema for dashboard attachment data.
* This schema matches the structure of DashboardState from @kbn/dashboard-plugin.
*/
export const dashboardAttachmentDataSchema = z.object({
title: z.string(),
description: z.string().optional(),
panels: z.array(z.union([attachmentPanelSchema, dashboardSectionSchema])),
query: querySchema.optional(),
time_range: timeRangeSchema.optional(),
refresh_interval: refreshIntervalSchema.optional(),
filters: z.array(filterSchema).optional(),
options: optionsSchema.optional(),
tags: z.array(z.string()).optional(),
pinned_panels: pinnedPanelsSchema.optional(),
access_control: accessControlSchema.optional(),
project_routing: z.string().optional(),
});

export type DashboardAttachmentData = z.infer<typeof dashboardAttachmentDataSchema>;
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export { DASHBOARD_ATTACHMENT_TYPE } from './constants';
export {
panelGridSchema,
sectionGridSchema,
attachmentPanelSchema,
dashboardSectionSchema,
dashboardAttachmentDataSchema,
isSection,
} from './types';
Expand All @@ -21,14 +19,17 @@ export type {
DashboardSection,
DashboardAttachmentData,
DashboardAttachment,
PendingDashboardAttachment,
} from './types';

export {
dashboardStateToAttachment,
attachmentToDashboardState,
dashboardStateToAttachmentData,
attachmentDataToDashboardState,
toEmbeddablePanel,
fromEmbeddablePanel,
DEFAULT_TIME_RANGE,
type VisualizationContent,
type DashboardPanelInput,
} from './converters';

export { isDashboardAttachment } from './is_dashboard_attachment';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { VersionedAttachment } from '@kbn/agent-builder-common/attachments';
import { DASHBOARD_ATTACHMENT_TYPE } from './constants';
import type { DashboardAttachmentData } from './types';

export const isDashboardAttachment = (
attachment: VersionedAttachment
): attachment is VersionedAttachment<typeof DASHBOARD_ATTACHMENT_TYPE, DashboardAttachmentData> =>
attachment.type === DASHBOARD_ATTACHMENT_TYPE;
Loading
Loading