-
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] Add a new content management schema to support public API #192618
Labels
impact:high
Addressing this issue will have a high level of impact on the quality/strength of our product.
loe:medium
Medium Level of Effort
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) |
nickpeihl
added
loe:medium
Medium Level of Effort
impact:high
Addressing this issue will have a high level of impact on the quality/strength of our product.
labels
Sep 11, 2024
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)
Fixed by #193067 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
impact:high
Addressing this issue will have a high level of impact on the quality/strength of our product.
loe:medium
Medium Level of Effort
Team:Presentation
Presentation Team for Dashboard, Input Controls, and Canvas
Publish a v3 Content Management Schema version for dashboards. The schema will be used by both the internal RPC and external Public API for validation. This new schema will focus on
twoone primary goal:panelsJSON
,optionsJSON
, etc) into objects2) moving reference injection/extraction to the storage layerMoved to #192758This will introduce a new Content layer that sits between the Persistance layer (saved object) and the public API / internal RPC. To ensure zero downtime the mappings for the persisted saved object will not change. The content layer will be responsible for transforming between the persisted saved object and the API / RPC request/response.
The Dashboards UI will continue to use existing v2 content management schema. Up and down transform functions will be added to the v2 and v3 schemas to seamlessly provide backwards compatibility between the schema versions.Migrating the Dashboards UI to the v3 schema involves some considerable refactoring and will be accomplished in a follow-up PR.2024-09-12 Edit: This has been rescoped a little bit to more quickly introduce a testable feature and reduce complexity. The v3 content management schema will
nothandle reference extraction/injection and the Dashboards UI will immediately adopt the v3 schema.Reference handling by the Dashboards server is moved to a separate effort in #192758.
The text was updated successfully, but these errors were encountered: