-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Dashboards] Embeddables schema registry for Dashboard API validation #192622
Labels
Team:Presentation
Presentation Team for Dashboard, Input Controls, and Canvas
Comments
nickpeihl
added
the
Team:Presentation
Presentation Team for Dashboard, Input Controls, and Canvas
label
Sep 11, 2024
Pinging @elastic/kibana-presentation (Team:Presentation) |
offline feedback from @lukeelmers has raised some open questions around the introduction of validation after the release of MVP. Questions to answer:
|
nickpeihl
added a commit
that referenced
this issue
Nov 8, 2024
Closes #[192618](#192618) Adds public CRUD+List endpoints for the Dashboards API. The schema for the endpoints are generated from Content Management schemas so that the RPC and Public APIs use the same schemas for CRUD operations. A new version (v3) has been added to the Dashboards content management specification that decouples Content from Saved Objects using a translation layer in Content Management. When retrieving a saved object the Content Management layer parses and validates the panelJSON, optionsListJSON, and savedSearchJSON properties against the defines schema and passes the translated content to the consumer (user interface or API). When writing a saved object, the Content Management layer serializes (`JSON.stringify`) the Content object into the saved object schema. So the saved object schema continues to store as stringified JSON, but the user interface and public API see and use the JSON objects. These planned features are out of scope for this PR and may be added in subsequent PRs. 1) #192758 2) #192622 Reviewers, please test both UI and endpoints. # cURL examples: First, `yarn start --no-base-path`. Assumes `elastic:changeme` is the username:password. ## Create <details> <summary>Create an empty dashboard with the minimum required properties</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my empty dashboard" } }' ``` </details> <details> <summary>Create a dashboard of a specific ID with some ES|QL panels</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "panels": [ { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibana_sample_data_ecommerce", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_ecommerce", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "title": "kibana_sample_data_ecommerce" } ], "layers": { "44866844-8fca-482a-a769-006e7d029b9b": { "columns": [ { "columnId": "6376af5c-fdd1-4d72-a3ec-5686b5049664", "fieldName": "customer_gender", "meta": { "esType": "keyword", "type": "string" } }, { "columnId": "a2e3e039-dff6-4893-9c9d-9f0a816207dd", "fieldName": "taxless_total_price", "meta": { "esType": "double", "type": "number" } } ], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } }, "781db49e-f4f1-42e0-975f-7118d2ef7a18": { "columns": [], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" }, "visualization": { "layers": [ { "categoryDisplay": "default", "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "44866844-8fca-482a-a769-006e7d029b9b", "layerType": "data", "legendDisplay": "default", "metrics": [ "a2e3e039-dff6-4893-9c9d-9f0a816207dd" ], "nestedLegend": false, "numberDisplay": "percent", "primaryGroups": [ "6376af5c-fdd1-4d72-a3ec-5686b5049664" ] } ], "shape": "pie" } }, "title": "Table category & category.keyword & currency & customer_first_name & customer_first_name.keyword", "type": "lens", "visualizationType": "lnsPie" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "name": "kibana_sample_data_logs", "runtimeFieldMap": {}, "sourceFilters": [], "timeFieldName": "@timestamp", "title": "kibana_sample_data_logs", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "timeField": "@timestamp", "title": "kibana_sample_data_logs" } ], "layers": { "2e3f211d-289f-4a24-87bb-1ccacd678adb": { "columns": [ { "columnId": "AVG(machine.ram)", "fieldName": "AVG(machine.ram)", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "machine.os.keyword", "fieldName": "machine.os.keyword", "meta": { "esType": "keyword", "type": "string" } } ], "index": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "timeField": "@timestamp" } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "visualization": { "axisTitlesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "fittingFunction": "None", "gridlinesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "labelsOrientation": { "x": 0, "yLeft": 0, "yRight": 0 }, "layers": [ { "accessors": [ "AVG(machine.ram)" ], "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "2e3f211d-289f-4a24-87bb-1ccacd678adb", "layerType": "data", "seriesType": "bar_stacked", "xAccessor": "machine.os.keyword" } ], "legend": { "isVisible": true, "position": "right" }, "preferredSeriesType": "bar_stacked", "tickLabelsVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "valueLabels": "hide" } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsXY" } }, "gridData": { "h": 15, "w": 24, "x": 24, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "name": "kibana_sample_data_flights", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_flights", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "title": "kibana_sample_data_flights" } ], "layers": { "4451c40f-b3ef-464e-b3d4-b10469f65c2a": { "columns": [ { "columnId": "AvgDelayMins", "fieldName": "AvgDelayMins", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "Carrier", "fieldName": "Carrier", "meta": { "esType": "keyword", "type": "string" } } ], "index": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " }, "visualization": { "breakdownByAccessor": "Carrier", "layerId": "4451c40f-b3ef-464e-b3d4-b10469f65c2a", "layerType": "data", "metricAccessor": "AvgDelayMins", "palette": { "name": "status", "params": { "colorStops": [], "continuity": "all", "maxSteps": 5, "name": "status", "progression": "fixed", "rangeMax": 100, "rangeMin": 0, "rangeType": "percent", "reverse": false, "steps": 3, "stops": [ { "color": "#209280", "stop": 33.33 }, { "color": "#d6bf57", "stop": 66.66 }, { "color": "#cc5642", "stop": 100 } ] }, "type": "palette" } } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsMetric" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 15 }, "type": "lens" } ], "timeRestore": false, "title": "several es|ql panels", "version": 3 } }' ``` </details> <details> <summary>Create a dashboard with a Links panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "layout": "vertical", "links": [ { "destinationRefName": "link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "id": "1981a00f-8120-4c80-b37f-ed38969afe09", "order": 0, "type": "dashboardLink" }, { "destinationRefName": "link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "id": "f2e1a75c-fbca-4f41-a290-d5d89a60a797", "order": 1, "type": "dashboardLink" }, { "destination": "https://example.com", "id": "63342ea6-f686-42b2-a526-ec0bcf4476b0", "order": 2, "type": "externalLink" } ] }, "enhancements": {}, "id": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b" }, "gridData": { "h": 7, "i": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "w": 8, "x": 0, "y": 0 }, "panelIndex": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "type": "links" } ], "timeRestore": false, "title": "a links panel", "version": 3 }, "references": [ { "id": "722b74f0-b882-11e8-a6d9-e546fe2bba5f", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "type": "dashboard" }, { "id": "edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "type": "dashboard" } ] }' ``` </details> <details> <summary>Create a dashboard with a Maps panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "description": "", "layerListJSON": "[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"db63eee8-3dfc-48c6-8c8b-7f2c4e32329d\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"},{\"sourceDescriptor\":{\"geoField\":\"geoip.location\",\"scalingType\":\"MVT\",\"id\":\"9ee192e4-18f0-41b2-b8b7-89eb91d0e529\",\"type\":\"ES_SEARCH\",\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"applyForceRefresh\":true,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"sortField\":\"\",\"sortOrder\":\"desc\",\"topHitsGroupByTimeseries\":false,\"topHitsSplitField\":\"\",\"topHitsSize\":1,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"id\":\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}},\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"color\":\"Blues\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"category.keyword\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":true,\"sigma\":3},\"type\":\"CATEGORICAL\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#41937c\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":0}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":6}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"labelText\":{\"type\":\"STATIC\",\"options\":{\"value\":\"\"}},\"labelColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#000000\"}},\"labelSize\":{\"type\":\"STATIC\",\"options\":{\"size\":14}},\"labelZoomRange\":{\"options\":{\"useLayerZoomRange\":true,\"minZoom\":0,\"maxZoom\":24}},\"labelBorderColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}},\"labelPosition\":{\"options\":{\"position\":\"CENTER\"}}},\"isTimeAware\":true},\"includeInFitToBounds\":true,\"type\":\"MVT_VECTOR\",\"joins\":[],\"disableTooltips\":false}]", "mapStateJSON": "{\"adHocDataViews\":[],\"zoom\":1.57,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[{\"meta\":{\"disabled\":false,\"negate\":false,\"alias\":\"males only\",\"index\":\"ff959d40-b880-11e8-a6d9-e546fe2bba5f\",\"key\":\"customer_gender\",\"field\":\"customer_gender\",\"params\":{\"query\":\"MALE\"},\"type\":\"phrase\"},\"query\":{\"match_phrase\":{\"customer_gender\":\"MALE\"}},\"$state\":{\"store\":\"appState\"}}],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}", "title": "", "uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\"]}" }, "enhancements": { "dynamicActions": { "events": [] } }, "hiddenLayers": [], "id": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "isLayerTOCOpen": false, "mapBuffer": { "maxLat": 85.05113, "maxLon": 180, "minLat": -66.51326, "minLon": -180 }, "mapCenter": { "lat": 19.94277, "lon": 0, "zoom": 1.57 }, "openTOCDetails": [ "65710bbc-f41c-4fe7-b0c3-a6dbc0613220" ] }, "gridData": { "h": 25, "i": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "w": 38, "x": 0, "y": 0 }, "panelIndex": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "type": "map" } ], "timeRestore": false, "title": "a maps panel", "version": 3 }, "references": [ { "type": "tag", "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a" }, { "name": "108b2f72-0101-4e09-b8a9-22f7aa9573b0:layer_1_source_index_pattern", "type": "index-pattern", "id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f" } ] }' ``` </details> <details> <summary>Create a dashboard with a Filter pill and a Field statistics panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "kibanaSavedObjectMeta": { "searchSource": { "filter": [ { "$state": { "store": "appState" }, "meta": { "alias": "gnomehouse", "disabled": false, "field": "products.manufacturer.keyword", "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "key": "products.manufacturer.keyword", "negate": false, "params": [ "Gnomehouse", "Gnomehouse mom" ], "type": "phrases" }, "query": { "bool": { "minimum_should_match": 1, "should": [ { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse" } }, { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse mom" } } ] } } } ], "query": { "language": "kuery", "query": "" } } }, "panels": [ { "panelConfig": { "dataViewId": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "enhancements": {}, "id": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "query": { "esql": "from kibana_sample_data_ecommerce | limit 10" }, "viewType": "esql" }, "gridData": { "h": 18, "i": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "w": 48, "x": 0, "y": 0 }, "panelIndex": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "type": "field_stats_table" } ], "timeRestore": false, "title": "field stats panel", "version": 2 }, "references": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "type": "index-pattern" }, { "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "type": "tag" }, { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4:fieldStatsTableDataViewId", "type": "index-pattern" } ] }' ``` </details> <details> <summary>Create a dashboard with a Lens panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "a lens panel", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "attributes": { "title": "", "visualizationType": "lnsDatatable", "type": "lens", "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ], "state": { "visualization": { "layerId": "b9789655-f916-4732-9bf2-641a88075210", "layerType": "data", "columns": [ { "isTransposed": false, "columnId": "4175e737-76b9-46db-894b-57106a06b9cb" }, { "isTransposed": false, "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, { "isTransposed": false, "columnId": "8eb92ea9-5b76-45a2-865e-d78511c1e506" } ] }, "query": { "query": "", "language": "kuery" }, "filters": [], "datasourceStates": { "formBased": { "layers": { "b9789655-f916-4732-9bf2-641a88075210": { "columns": { "4175e737-76b9-46db-894b-57106a06b9cb": { "label": "Top 5 values of Carrier", "dataType": "string", "operationType": "terms", "scale": "ordinal", "sourceField": "Carrier", "isBucketed": true, "params": { "size": 5, "orderBy": { "type": "column", "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, "orderDirection": "desc", "otherBucket": true, "missingBucket": false, "parentFormat": { "id": "terms" }, "include": [], "exclude": [], "includeIsRegex": false, "excludeIsRegex": false } }, "1494f183-3bfa-4602-a780-6a41624f6c69": { "label": "Count of records", "dataType": "number", "operationType": "count", "isBucketed": false, "scale": "ratio", "sourceField": "___records___", "params": { "emptyAsNull": true } }, "8eb92ea9-5b76-45a2-865e-d78511c1e506": { "label": "Median of AvgTicketPrice", "dataType": "number", "operationType": "median", "sourceField": "AvgTicketPrice", "isBucketed": false, "scale": "ratio", "params": { "emptyAsNull": true } } }, "columnOrder": [ "4175e737-76b9-46db-894b-57106a06b9cb", "1494f183-3bfa-4602-a780-6a41624f6c69", "8eb92ea9-5b76-45a2-865e-d78511c1e506" ], "incompleteColumns": {}, "sampling": 1 } } }, "indexpattern": { "layers": {} }, "textBased": { "layers": {} } }, "internalReferences": [], "adHocDataViews": {} } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "lens" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ] }' ``` </details> <details> <summary>Create a dashboard in a specific Space</summary> ``` curl -X POST \ 'http://localhost:5601/s/space-1/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my other demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)." }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15, "i": "1" }, "type": "visualization", "version": "7.9.2" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [], "spaces": ["space-1"] }' ``` </details> ## Update <details> <summary>Update an existing dashboard</summary> ``` curl -X PUT \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html).\nWubba lubba dub-dub!" }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "visualization" } ], "version": 3 }, "references": [] }' ``` </details> ## Get / List <details> <summary>Get a dashboard</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> <details> <summary>Get a paginated list of dashboards</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> ## Delete <details> <summary>Delete a dashboard</summary> ``` curl -X DELETE \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' ``` </details> ## Open API specification <details> <summary>Retrieve the Open API specification</summary> ``` curl -X GET \ 'http://localhost:5601/api/oas?pathStartsWith=%2Fapi%2Fdashboard' \ --user elastic:changeme \ --header 'Accept: */*' ``` </details> --------- Co-authored-by: kibanamachine <[email protected]>
kibanamachine
pushed a commit
to kibanamachine/kibana
that referenced
this issue
Nov 8, 2024
Closes #[192618](elastic#192618) Adds public CRUD+List endpoints for the Dashboards API. The schema for the endpoints are generated from Content Management schemas so that the RPC and Public APIs use the same schemas for CRUD operations. A new version (v3) has been added to the Dashboards content management specification that decouples Content from Saved Objects using a translation layer in Content Management. When retrieving a saved object the Content Management layer parses and validates the panelJSON, optionsListJSON, and savedSearchJSON properties against the defines schema and passes the translated content to the consumer (user interface or API). When writing a saved object, the Content Management layer serializes (`JSON.stringify`) the Content object into the saved object schema. So the saved object schema continues to store as stringified JSON, but the user interface and public API see and use the JSON objects. These planned features are out of scope for this PR and may be added in subsequent PRs. 1) elastic#192758 2) elastic#192622 Reviewers, please test both UI and endpoints. # cURL examples: First, `yarn start --no-base-path`. Assumes `elastic:changeme` is the username:password. ## Create <details> <summary>Create an empty dashboard with the minimum required properties</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my empty dashboard" } }' ``` </details> <details> <summary>Create a dashboard of a specific ID with some ES|QL panels</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "panels": [ { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibana_sample_data_ecommerce", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_ecommerce", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "title": "kibana_sample_data_ecommerce" } ], "layers": { "44866844-8fca-482a-a769-006e7d029b9b": { "columns": [ { "columnId": "6376af5c-fdd1-4d72-a3ec-5686b5049664", "fieldName": "customer_gender", "meta": { "esType": "keyword", "type": "string" } }, { "columnId": "a2e3e039-dff6-4893-9c9d-9f0a816207dd", "fieldName": "taxless_total_price", "meta": { "esType": "double", "type": "number" } } ], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } }, "781db49e-f4f1-42e0-975f-7118d2ef7a18": { "columns": [], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" }, "visualization": { "layers": [ { "categoryDisplay": "default", "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "44866844-8fca-482a-a769-006e7d029b9b", "layerType": "data", "legendDisplay": "default", "metrics": [ "a2e3e039-dff6-4893-9c9d-9f0a816207dd" ], "nestedLegend": false, "numberDisplay": "percent", "primaryGroups": [ "6376af5c-fdd1-4d72-a3ec-5686b5049664" ] } ], "shape": "pie" } }, "title": "Table category & category.keyword & currency & customer_first_name & customer_first_name.keyword", "type": "lens", "visualizationType": "lnsPie" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "name": "kibana_sample_data_logs", "runtimeFieldMap": {}, "sourceFilters": [], "timeFieldName": "@timestamp", "title": "kibana_sample_data_logs", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "timeField": "@timestamp", "title": "kibana_sample_data_logs" } ], "layers": { "2e3f211d-289f-4a24-87bb-1ccacd678adb": { "columns": [ { "columnId": "AVG(machine.ram)", "fieldName": "AVG(machine.ram)", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "machine.os.keyword", "fieldName": "machine.os.keyword", "meta": { "esType": "keyword", "type": "string" } } ], "index": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "timeField": "@timestamp" } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "visualization": { "axisTitlesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "fittingFunction": "None", "gridlinesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "labelsOrientation": { "x": 0, "yLeft": 0, "yRight": 0 }, "layers": [ { "accessors": [ "AVG(machine.ram)" ], "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "2e3f211d-289f-4a24-87bb-1ccacd678adb", "layerType": "data", "seriesType": "bar_stacked", "xAccessor": "machine.os.keyword" } ], "legend": { "isVisible": true, "position": "right" }, "preferredSeriesType": "bar_stacked", "tickLabelsVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "valueLabels": "hide" } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsXY" } }, "gridData": { "h": 15, "w": 24, "x": 24, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "name": "kibana_sample_data_flights", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_flights", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "title": "kibana_sample_data_flights" } ], "layers": { "4451c40f-b3ef-464e-b3d4-b10469f65c2a": { "columns": [ { "columnId": "AvgDelayMins", "fieldName": "AvgDelayMins", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "Carrier", "fieldName": "Carrier", "meta": { "esType": "keyword", "type": "string" } } ], "index": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " }, "visualization": { "breakdownByAccessor": "Carrier", "layerId": "4451c40f-b3ef-464e-b3d4-b10469f65c2a", "layerType": "data", "metricAccessor": "AvgDelayMins", "palette": { "name": "status", "params": { "colorStops": [], "continuity": "all", "maxSteps": 5, "name": "status", "progression": "fixed", "rangeMax": 100, "rangeMin": 0, "rangeType": "percent", "reverse": false, "steps": 3, "stops": [ { "color": "#209280", "stop": 33.33 }, { "color": "#d6bf57", "stop": 66.66 }, { "color": "#cc5642", "stop": 100 } ] }, "type": "palette" } } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsMetric" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 15 }, "type": "lens" } ], "timeRestore": false, "title": "several es|ql panels", "version": 3 } }' ``` </details> <details> <summary>Create a dashboard with a Links panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "layout": "vertical", "links": [ { "destinationRefName": "link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "id": "1981a00f-8120-4c80-b37f-ed38969afe09", "order": 0, "type": "dashboardLink" }, { "destinationRefName": "link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "id": "f2e1a75c-fbca-4f41-a290-d5d89a60a797", "order": 1, "type": "dashboardLink" }, { "destination": "https://example.com", "id": "63342ea6-f686-42b2-a526-ec0bcf4476b0", "order": 2, "type": "externalLink" } ] }, "enhancements": {}, "id": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b" }, "gridData": { "h": 7, "i": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "w": 8, "x": 0, "y": 0 }, "panelIndex": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "type": "links" } ], "timeRestore": false, "title": "a links panel", "version": 3 }, "references": [ { "id": "722b74f0-b882-11e8-a6d9-e546fe2bba5f", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "type": "dashboard" }, { "id": "edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "type": "dashboard" } ] }' ``` </details> <details> <summary>Create a dashboard with a Maps panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "description": "", "layerListJSON": "[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"db63eee8-3dfc-48c6-8c8b-7f2c4e32329d\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"},{\"sourceDescriptor\":{\"geoField\":\"geoip.location\",\"scalingType\":\"MVT\",\"id\":\"9ee192e4-18f0-41b2-b8b7-89eb91d0e529\",\"type\":\"ES_SEARCH\",\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"applyForceRefresh\":true,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"sortField\":\"\",\"sortOrder\":\"desc\",\"topHitsGroupByTimeseries\":false,\"topHitsSplitField\":\"\",\"topHitsSize\":1,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"id\":\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}},\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"color\":\"Blues\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"category.keyword\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":true,\"sigma\":3},\"type\":\"CATEGORICAL\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#41937c\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":0}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":6}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"labelText\":{\"type\":\"STATIC\",\"options\":{\"value\":\"\"}},\"labelColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#000000\"}},\"labelSize\":{\"type\":\"STATIC\",\"options\":{\"size\":14}},\"labelZoomRange\":{\"options\":{\"useLayerZoomRange\":true,\"minZoom\":0,\"maxZoom\":24}},\"labelBorderColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}},\"labelPosition\":{\"options\":{\"position\":\"CENTER\"}}},\"isTimeAware\":true},\"includeInFitToBounds\":true,\"type\":\"MVT_VECTOR\",\"joins\":[],\"disableTooltips\":false}]", "mapStateJSON": "{\"adHocDataViews\":[],\"zoom\":1.57,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[{\"meta\":{\"disabled\":false,\"negate\":false,\"alias\":\"males only\",\"index\":\"ff959d40-b880-11e8-a6d9-e546fe2bba5f\",\"key\":\"customer_gender\",\"field\":\"customer_gender\",\"params\":{\"query\":\"MALE\"},\"type\":\"phrase\"},\"query\":{\"match_phrase\":{\"customer_gender\":\"MALE\"}},\"$state\":{\"store\":\"appState\"}}],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}", "title": "", "uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\"]}" }, "enhancements": { "dynamicActions": { "events": [] } }, "hiddenLayers": [], "id": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "isLayerTOCOpen": false, "mapBuffer": { "maxLat": 85.05113, "maxLon": 180, "minLat": -66.51326, "minLon": -180 }, "mapCenter": { "lat": 19.94277, "lon": 0, "zoom": 1.57 }, "openTOCDetails": [ "65710bbc-f41c-4fe7-b0c3-a6dbc0613220" ] }, "gridData": { "h": 25, "i": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "w": 38, "x": 0, "y": 0 }, "panelIndex": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "type": "map" } ], "timeRestore": false, "title": "a maps panel", "version": 3 }, "references": [ { "type": "tag", "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a" }, { "name": "108b2f72-0101-4e09-b8a9-22f7aa9573b0:layer_1_source_index_pattern", "type": "index-pattern", "id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f" } ] }' ``` </details> <details> <summary>Create a dashboard with a Filter pill and a Field statistics panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "kibanaSavedObjectMeta": { "searchSource": { "filter": [ { "$state": { "store": "appState" }, "meta": { "alias": "gnomehouse", "disabled": false, "field": "products.manufacturer.keyword", "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "key": "products.manufacturer.keyword", "negate": false, "params": [ "Gnomehouse", "Gnomehouse mom" ], "type": "phrases" }, "query": { "bool": { "minimum_should_match": 1, "should": [ { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse" } }, { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse mom" } } ] } } } ], "query": { "language": "kuery", "query": "" } } }, "panels": [ { "panelConfig": { "dataViewId": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "enhancements": {}, "id": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "query": { "esql": "from kibana_sample_data_ecommerce | limit 10" }, "viewType": "esql" }, "gridData": { "h": 18, "i": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "w": 48, "x": 0, "y": 0 }, "panelIndex": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "type": "field_stats_table" } ], "timeRestore": false, "title": "field stats panel", "version": 2 }, "references": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "type": "index-pattern" }, { "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "type": "tag" }, { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4:fieldStatsTableDataViewId", "type": "index-pattern" } ] }' ``` </details> <details> <summary>Create a dashboard with a Lens panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "a lens panel", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "attributes": { "title": "", "visualizationType": "lnsDatatable", "type": "lens", "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ], "state": { "visualization": { "layerId": "b9789655-f916-4732-9bf2-641a88075210", "layerType": "data", "columns": [ { "isTransposed": false, "columnId": "4175e737-76b9-46db-894b-57106a06b9cb" }, { "isTransposed": false, "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, { "isTransposed": false, "columnId": "8eb92ea9-5b76-45a2-865e-d78511c1e506" } ] }, "query": { "query": "", "language": "kuery" }, "filters": [], "datasourceStates": { "formBased": { "layers": { "b9789655-f916-4732-9bf2-641a88075210": { "columns": { "4175e737-76b9-46db-894b-57106a06b9cb": { "label": "Top 5 values of Carrier", "dataType": "string", "operationType": "terms", "scale": "ordinal", "sourceField": "Carrier", "isBucketed": true, "params": { "size": 5, "orderBy": { "type": "column", "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, "orderDirection": "desc", "otherBucket": true, "missingBucket": false, "parentFormat": { "id": "terms" }, "include": [], "exclude": [], "includeIsRegex": false, "excludeIsRegex": false } }, "1494f183-3bfa-4602-a780-6a41624f6c69": { "label": "Count of records", "dataType": "number", "operationType": "count", "isBucketed": false, "scale": "ratio", "sourceField": "___records___", "params": { "emptyAsNull": true } }, "8eb92ea9-5b76-45a2-865e-d78511c1e506": { "label": "Median of AvgTicketPrice", "dataType": "number", "operationType": "median", "sourceField": "AvgTicketPrice", "isBucketed": false, "scale": "ratio", "params": { "emptyAsNull": true } } }, "columnOrder": [ "4175e737-76b9-46db-894b-57106a06b9cb", "1494f183-3bfa-4602-a780-6a41624f6c69", "8eb92ea9-5b76-45a2-865e-d78511c1e506" ], "incompleteColumns": {}, "sampling": 1 } } }, "indexpattern": { "layers": {} }, "textBased": { "layers": {} } }, "internalReferences": [], "adHocDataViews": {} } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "lens" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ] }' ``` </details> <details> <summary>Create a dashboard in a specific Space</summary> ``` curl -X POST \ 'http://localhost:5601/s/space-1/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my other demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)." }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15, "i": "1" }, "type": "visualization", "version": "7.9.2" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [], "spaces": ["space-1"] }' ``` </details> ## Update <details> <summary>Update an existing dashboard</summary> ``` curl -X PUT \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html).\nWubba lubba dub-dub!" }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "visualization" } ], "version": 3 }, "references": [] }' ``` </details> ## Get / List <details> <summary>Get a dashboard</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> <details> <summary>Get a paginated list of dashboards</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> ## Delete <details> <summary>Delete a dashboard</summary> ``` curl -X DELETE \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' ``` </details> ## Open API specification <details> <summary>Retrieve the Open API specification</summary> ``` curl -X GET \ 'http://localhost:5601/api/oas?pathStartsWith=%2Fapi%2Fdashboard' \ --user elastic:changeme \ --header 'Accept: */*' ``` </details> --------- Co-authored-by: kibanamachine <[email protected]> (cherry picked from commit a227021)
nickpeihl
added a commit
to nickpeihl/kibana
that referenced
this issue
Nov 8, 2024
Closes #[192618](elastic#192618) Adds public CRUD+List endpoints for the Dashboards API. The schema for the endpoints are generated from Content Management schemas so that the RPC and Public APIs use the same schemas for CRUD operations. A new version (v3) has been added to the Dashboards content management specification that decouples Content from Saved Objects using a translation layer in Content Management. When retrieving a saved object the Content Management layer parses and validates the panelJSON, optionsListJSON, and savedSearchJSON properties against the defines schema and passes the translated content to the consumer (user interface or API). When writing a saved object, the Content Management layer serializes (`JSON.stringify`) the Content object into the saved object schema. So the saved object schema continues to store as stringified JSON, but the user interface and public API see and use the JSON objects. These planned features are out of scope for this PR and may be added in subsequent PRs. 1) elastic#192758 2) elastic#192622 Reviewers, please test both UI and endpoints. # cURL examples: First, `yarn start --no-base-path`. Assumes `elastic:changeme` is the username:password. ## Create <details> <summary>Create an empty dashboard with the minimum required properties</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my empty dashboard" } }' ``` </details> <details> <summary>Create a dashboard of a specific ID with some ES|QL panels</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "panels": [ { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibana_sample_data_ecommerce", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_ecommerce", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "title": "kibana_sample_data_ecommerce" } ], "layers": { "44866844-8fca-482a-a769-006e7d029b9b": { "columns": [ { "columnId": "6376af5c-fdd1-4d72-a3ec-5686b5049664", "fieldName": "customer_gender", "meta": { "esType": "keyword", "type": "string" } }, { "columnId": "a2e3e039-dff6-4893-9c9d-9f0a816207dd", "fieldName": "taxless_total_price", "meta": { "esType": "double", "type": "number" } } ], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } }, "781db49e-f4f1-42e0-975f-7118d2ef7a18": { "columns": [], "index": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_ecommerce | LIMIT 100" }, "visualization": { "layers": [ { "categoryDisplay": "default", "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "44866844-8fca-482a-a769-006e7d029b9b", "layerType": "data", "legendDisplay": "default", "metrics": [ "a2e3e039-dff6-4893-9c9d-9f0a816207dd" ], "nestedLegend": false, "numberDisplay": "percent", "primaryGroups": [ "6376af5c-fdd1-4d72-a3ec-5686b5049664" ] } ], "shape": "pie" } }, "title": "Table category & category.keyword & currency & customer_first_name & customer_first_name.keyword", "type": "lens", "visualizationType": "lnsPie" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "name": "kibana_sample_data_logs", "runtimeFieldMap": {}, "sourceFilters": [], "timeFieldName": "@timestamp", "title": "kibana_sample_data_logs", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "timeField": "@timestamp", "title": "kibana_sample_data_logs" } ], "layers": { "2e3f211d-289f-4a24-87bb-1ccacd678adb": { "columns": [ { "columnId": "AVG(machine.ram)", "fieldName": "AVG(machine.ram)", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "machine.os.keyword", "fieldName": "machine.os.keyword", "meta": { "esType": "keyword", "type": "string" } } ], "index": "e3465e67bdeced2befff9f9dca7ecf9c48504cad68a10efd881f4c7dd5ade28a", "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "timeField": "@timestamp" } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_logs| STATS AVG(machine.ram) BY machine.os.keyword " }, "visualization": { "axisTitlesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "fittingFunction": "None", "gridlinesVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "labelsOrientation": { "x": 0, "yLeft": 0, "yRight": 0 }, "layers": [ { "accessors": [ "AVG(machine.ram)" ], "colorMapping": { "assignments": [], "colorMode": { "type": "categorical" }, "paletteId": "eui_amsterdam_color_blind", "specialAssignments": [ { "color": { "type": "loop" }, "rule": { "type": "other" }, "touched": false } ] }, "layerId": "2e3f211d-289f-4a24-87bb-1ccacd678adb", "layerType": "data", "seriesType": "bar_stacked", "xAccessor": "machine.os.keyword" } ], "legend": { "isVisible": true, "position": "right" }, "preferredSeriesType": "bar_stacked", "tickLabelsVisibilitySettings": { "x": true, "yLeft": true, "yRight": true }, "valueLabels": "hide" } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsXY" } }, "gridData": { "h": 15, "w": 24, "x": 24, "y": 0 }, "type": "lens" }, { "panelConfig": { "attributes": { "references": [], "state": { "adHocDataViews": { "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03": { "allowHidden": false, "allowNoIndex": false, "fieldFormats": {}, "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "name": "kibana_sample_data_flights", "runtimeFieldMap": {}, "sourceFilters": [], "title": "kibana_sample_data_flights", "type": "esql" } }, "datasourceStates": { "textBased": { "indexPatternRefs": [ { "id": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "title": "kibana_sample_data_flights" } ], "layers": { "4451c40f-b3ef-464e-b3d4-b10469f65c2a": { "columns": [ { "columnId": "AvgDelayMins", "fieldName": "AvgDelayMins", "inMetricDimension": true, "meta": { "esType": "double", "type": "number" } }, { "columnId": "Carrier", "fieldName": "Carrier", "meta": { "esType": "keyword", "type": "string" } } ], "index": "5d671714fc025d173ee40f0825b86d59b6e432344593b725be28f1f8f17a8a03", "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " } } } } }, "filters": [], "query": { "esql": "FROM kibana_sample_data_flights| STATS AvgDelayMins = AVG(FlightDelayMin) BY Carrier " }, "visualization": { "breakdownByAccessor": "Carrier", "layerId": "4451c40f-b3ef-464e-b3d4-b10469f65c2a", "layerType": "data", "metricAccessor": "AvgDelayMins", "palette": { "name": "status", "params": { "colorStops": [], "continuity": "all", "maxSteps": 5, "name": "status", "progression": "fixed", "rangeMax": 100, "rangeMin": 0, "rangeType": "percent", "reverse": false, "steps": 3, "stops": [ { "color": "#209280", "stop": 33.33 }, { "color": "#d6bf57", "stop": 66.66 }, { "color": "#cc5642", "stop": 100 } ] }, "type": "palette" } } }, "title": "Bar vertical stacked", "type": "lens", "visualizationType": "lnsMetric" } }, "gridData": { "h": 15, "w": 24, "x": 0, "y": 15 }, "type": "lens" } ], "timeRestore": false, "title": "several es|ql panels", "version": 3 } }' ``` </details> <details> <summary>Create a dashboard with a Links panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "layout": "vertical", "links": [ { "destinationRefName": "link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "id": "1981a00f-8120-4c80-b37f-ed38969afe09", "order": 0, "type": "dashboardLink" }, { "destinationRefName": "link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "id": "f2e1a75c-fbca-4f41-a290-d5d89a60a797", "order": 1, "type": "dashboardLink" }, { "destination": "https://example.com", "id": "63342ea6-f686-42b2-a526-ec0bcf4476b0", "order": 2, "type": "externalLink" } ] }, "enhancements": {}, "id": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b" }, "gridData": { "h": 7, "i": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "w": 8, "x": 0, "y": 0 }, "panelIndex": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b", "type": "links" } ], "timeRestore": false, "title": "a links panel", "version": 3 }, "references": [ { "id": "722b74f0-b882-11e8-a6d9-e546fe2bba5f", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_1981a00f-8120-4c80-b37f-ed38969afe09_dashboard", "type": "dashboard" }, { "id": "edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b", "name": "abbbaedc-62f5-46ee-9d17-8367dcf4f52b:link_f2e1a75c-fbca-4f41-a290-d5d89a60a797_dashboard", "type": "dashboard" } ] }' ``` </details> <details> <summary>Create a dashboard with a Maps panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "panels": [ { "panelConfig": { "attributes": { "description": "", "layerListJSON": "[{\"locale\":\"autoselect\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\"},\"id\":\"db63eee8-3dfc-48c6-8c8b-7f2c4e32329d\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":1,\"visible\":true,\"style\":{\"type\":\"EMS_VECTOR_TILE\",\"color\":\"\"},\"includeInFitToBounds\":true,\"type\":\"EMS_VECTOR_TILE\"},{\"sourceDescriptor\":{\"geoField\":\"geoip.location\",\"scalingType\":\"MVT\",\"id\":\"9ee192e4-18f0-41b2-b8b7-89eb91d0e529\",\"type\":\"ES_SEARCH\",\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"applyForceRefresh\":true,\"filterByMapBounds\":true,\"tooltipProperties\":[],\"sortField\":\"\",\"sortOrder\":\"desc\",\"topHitsGroupByTimeseries\":false,\"topHitsSplitField\":\"\",\"topHitsSize\":1,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"id\":\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"marker\"}},\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"color\":\"Blues\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"category.keyword\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":true,\"sigma\":3},\"type\":\"CATEGORICAL\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#41937c\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":0}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":6}},\"iconOrientation\":{\"type\":\"STATIC\",\"options\":{\"orientation\":0}},\"labelText\":{\"type\":\"STATIC\",\"options\":{\"value\":\"\"}},\"labelColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#000000\"}},\"labelSize\":{\"type\":\"STATIC\",\"options\":{\"size\":14}},\"labelZoomRange\":{\"options\":{\"useLayerZoomRange\":true,\"minZoom\":0,\"maxZoom\":24}},\"labelBorderColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}},\"labelPosition\":{\"options\":{\"position\":\"CENTER\"}}},\"isTimeAware\":true},\"includeInFitToBounds\":true,\"type\":\"MVT_VECTOR\",\"joins\":[],\"disableTooltips\":false}]", "mapStateJSON": "{\"adHocDataViews\":[],\"zoom\":1.57,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-7d\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":60000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[{\"meta\":{\"disabled\":false,\"negate\":false,\"alias\":\"males only\",\"index\":\"ff959d40-b880-11e8-a6d9-e546fe2bba5f\",\"key\":\"customer_gender\",\"field\":\"customer_gender\",\"params\":{\"query\":\"MALE\"},\"type\":\"phrase\"},\"query\":{\"match_phrase\":{\"customer_gender\":\"MALE\"}},\"$state\":{\"store\":\"appState\"}}],\"settings\":{\"autoFitToDataBounds\":false,\"backgroundColor\":\"#ffffff\",\"customIcons\":[],\"disableInteractive\":false,\"disableTooltipControl\":false,\"hideToolbarOverlay\":false,\"hideLayerControl\":false,\"hideViewControl\":false,\"initialLocation\":\"LAST_SAVED_LOCATION\",\"fixedLocation\":{\"lat\":0,\"lon\":0,\"zoom\":2},\"browserLocation\":{\"zoom\":2},\"keydownScrollZoom\":false,\"maxZoom\":24,\"minZoom\":0,\"showScaleControl\":false,\"showSpatialFilters\":true,\"showTimesliderToggleButton\":true,\"spatialFiltersAlpa\":0.3,\"spatialFiltersFillColor\":\"#DA8B45\",\"spatialFiltersLineColor\":\"#DA8B45\"}}", "title": "", "uiStateJSON": "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[\"65710bbc-f41c-4fe7-b0c3-a6dbc0613220\"]}" }, "enhancements": { "dynamicActions": { "events": [] } }, "hiddenLayers": [], "id": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "isLayerTOCOpen": false, "mapBuffer": { "maxLat": 85.05113, "maxLon": 180, "minLat": -66.51326, "minLon": -180 }, "mapCenter": { "lat": 19.94277, "lon": 0, "zoom": 1.57 }, "openTOCDetails": [ "65710bbc-f41c-4fe7-b0c3-a6dbc0613220" ] }, "gridData": { "h": 25, "i": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "w": 38, "x": 0, "y": 0 }, "panelIndex": "108b2f72-0101-4e09-b8a9-22f7aa9573b0", "type": "map" } ], "timeRestore": false, "title": "a maps panel", "version": 3 }, "references": [ { "type": "tag", "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a" }, { "name": "108b2f72-0101-4e09-b8a9-22f7aa9573b0:layer_1_source_index_pattern", "type": "index-pattern", "id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f" } ] }' ``` </details> <details> <summary>Create a dashboard with a Filter pill and a Field statistics panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "description": "", "kibanaSavedObjectMeta": { "searchSource": { "filter": [ { "$state": { "store": "appState" }, "meta": { "alias": "gnomehouse", "disabled": false, "field": "products.manufacturer.keyword", "indexRefName": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "key": "products.manufacturer.keyword", "negate": false, "params": [ "Gnomehouse", "Gnomehouse mom" ], "type": "phrases" }, "query": { "bool": { "minimum_should_match": 1, "should": [ { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse" } }, { "match_phrase": { "products.manufacturer.keyword": "Gnomehouse mom" } } ] } } } ], "query": { "language": "kuery", "query": "" } } }, "panels": [ { "panelConfig": { "dataViewId": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "enhancements": {}, "id": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "query": { "esql": "from kibana_sample_data_ecommerce | limit 10" }, "viewType": "esql" }, "gridData": { "h": 18, "i": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "w": 48, "x": 0, "y": 0 }, "panelIndex": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4", "type": "field_stats_table" } ], "timeRestore": false, "title": "field stats panel", "version": 2 }, "references": [ { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", "type": "index-pattern" }, { "id": "662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "name": "tag-ref-662b28f2-71e4-4c04-b4e5-0c6249b1c08a", "type": "tag" }, { "id": "32eec79c9673ab1b9265f3e422e8f952778f02c82eaf13147a9c0ba86290337a", "name": "3c9dee70-4a01-4c2f-9ccd-0c2812e2a5d4:fieldStatsTableDataViewId", "type": "index-pattern" } ] }' ``` </details> <details> <summary>Create a dashboard with a Lens panel</summary> ``` curl -X POST \ 'http://localhost:5601/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "a lens panel", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "attributes": { "title": "", "visualizationType": "lnsDatatable", "type": "lens", "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ], "state": { "visualization": { "layerId": "b9789655-f916-4732-9bf2-641a88075210", "layerType": "data", "columns": [ { "isTransposed": false, "columnId": "4175e737-76b9-46db-894b-57106a06b9cb" }, { "isTransposed": false, "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, { "isTransposed": false, "columnId": "8eb92ea9-5b76-45a2-865e-d78511c1e506" } ] }, "query": { "query": "", "language": "kuery" }, "filters": [], "datasourceStates": { "formBased": { "layers": { "b9789655-f916-4732-9bf2-641a88075210": { "columns": { "4175e737-76b9-46db-894b-57106a06b9cb": { "label": "Top 5 values of Carrier", "dataType": "string", "operationType": "terms", "scale": "ordinal", "sourceField": "Carrier", "isBucketed": true, "params": { "size": 5, "orderBy": { "type": "column", "columnId": "1494f183-3bfa-4602-a780-6a41624f6c69" }, "orderDirection": "desc", "otherBucket": true, "missingBucket": false, "parentFormat": { "id": "terms" }, "include": [], "exclude": [], "includeIsRegex": false, "excludeIsRegex": false } }, "1494f183-3bfa-4602-a780-6a41624f6c69": { "label": "Count of records", "dataType": "number", "operationType": "count", "isBucketed": false, "scale": "ratio", "sourceField": "___records___", "params": { "emptyAsNull": true } }, "8eb92ea9-5b76-45a2-865e-d78511c1e506": { "label": "Median of AvgTicketPrice", "dataType": "number", "operationType": "median", "sourceField": "AvgTicketPrice", "isBucketed": false, "scale": "ratio", "params": { "emptyAsNull": true } } }, "columnOrder": [ "4175e737-76b9-46db-894b-57106a06b9cb", "1494f183-3bfa-4602-a780-6a41624f6c69", "8eb92ea9-5b76-45a2-865e-d78511c1e506" ], "incompleteColumns": {}, "sampling": 1 } } }, "indexpattern": { "layers": {} }, "textBased": { "layers": {} } }, "internalReferences": [], "adHocDataViews": {} } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "lens" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [ { "type": "index-pattern", "id": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "name": "indexpattern-datasource-layer-b9789655-f916-4732-9bf2-641a88075210" } ] }' ``` </details> <details> <summary>Create a dashboard in a specific Space</summary> ``` curl -X POST \ 'http://localhost:5601/s/space-1/api/dashboards/dashboard/' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my other demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)." }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15, "i": "1" }, "type": "visualization", "version": "7.9.2" } ], "options": { "hidePanelTitles": false, "useMargins": true, "syncColors": false, "syncTooltips": true, "syncCursor": true }, "version": 3 }, "references": [], "spaces": ["space-1"] }' ``` </details> ## Update <details> <summary>Update an existing dashboard</summary> ``` curl -X PUT \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' \ --header 'Content-Type: application/json' \ --data-raw '{ "attributes": { "title": "my demo dashboard", "kibanaSavedObjectMeta": { "searchSource": {} }, "timeRestore": false, "panels": [ { "panelConfig": { "savedVis": { "description": "", "type": "markdown", "params": { "fontSize": 12, "openLinksInNewTab": false, "markdown": "## Sample eCommerce Data\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html).\nWubba lubba dub-dub!" }, "uiState": {}, "data": { "aggs": [], "searchSource": { "query": { "query": "", "language": "kuery" }, "filter": [] } } }, "enhancements": {} }, "gridData": { "x": 0, "y": 0, "w": 24, "h": 15 }, "type": "visualization" } ], "version": 3 }, "references": [] }' ``` </details> ## Get / List <details> <summary>Get a dashboard</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> <details> <summary>Get a paginated list of dashboards</summary> ``` curl -X GET \ 'http://localhost:5601/api/dashboards/dashboard' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' ``` </details> ## Delete <details> <summary>Delete a dashboard</summary> ``` curl -X DELETE \ 'http://localhost:5601/api/dashboards/dashboard/foo-123' \ --user elastic:changeme \ --header 'Accept: */*' \ --header 'elastic-api-version: 2023-10-31' \ --header 'kbn-xsrf: true' ``` </details> ## Open API specification <details> <summary>Retrieve the Open API specification</summary> ``` curl -X GET \ 'http://localhost:5601/api/oas?pathStartsWith=%2Fapi%2Fdashboard' \ --user elastic:changeme \ --header 'Accept: */*' ``` </details> --------- Co-authored-by: kibanamachine <[email protected]> (cherry picked from commit a227021)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Follow up to #192618
Implement a registry for embeddables to optionally register their configuration schemas for stricter validation and a better API schema definitions for the public Dashboards API. If a schema is not registered for an embeddable, the configuration will not be validated and the OpenAPI specification for that embeddable type will not be defined.
The text was updated successfully, but these errors were encountered: