diff --git a/kbncontent.go b/kbncontent.go index e45bc29..4826f48 100644 --- a/kbncontent.go +++ b/kbncontent.go @@ -28,7 +28,7 @@ func (v VisualizationDescriptor) findDocumentPathsAsString(paths []string) strin m := objx.Map(v.Doc) for _, path := range paths { - if m.Get(path).IsStr() { + if m.Get(path).IsStr() && m.Get(path).Str() != "" { return m.Get(path).Str() } } @@ -137,6 +137,7 @@ func (v VisualizationDescriptor) HasFilters() (bool, error) { queryPaths := []string{ "attributes.kibanaSavedObjectMeta.searchSourceJSON.query.query", "attributes.state.query.query", + "embeddableConfig.attributes.mapStateJSON.query.query", "embeddableConfig.attributes.state.query.query", "embeddableConfig.savedVis.data.searchSource.query.query", } @@ -150,6 +151,7 @@ func (v VisualizationDescriptor) HasFilters() (bool, error) { filterPaths := []string{ "attributes.state.filters", "embeddableConfig.attributes.state.filters", + "embeddableConfig.attributes.mapStateJSON.filters", "embeddableConfig.savedVis.data.searchSource.filter", "attributes.kibanaSavedObjectMeta.searchSourceJSON.filter", } @@ -178,10 +180,6 @@ func (v VisualizationDescriptor) TSVBType() string { // Title returns the visualization title func (v VisualizationDescriptor) Title() string { - if v.SavedObjectType != "visualization" { - return "" - } - return v.findDocumentPathsAsString([]string{ "attributes.title", "title", @@ -191,9 +189,14 @@ func (v VisualizationDescriptor) Title() string { func deserializeSubPaths(doc objx.Map) error { jsonPaths := []string{ + "attributes.kibanaSavedObjectMeta.searchSourceJSON", + "attributes.mapStateJSON", "attributes.uiStateJSON", "attributes.visState", - "attributes.kibanaSavedObjectMeta.searchSourceJSON", + "embeddableConfig.attributes.kibanaSavedObjectMeta.searchSourceJSON", + "embeddableConfig.attributes.mapStateJSON", + "embeddableConfig.attributes.uiStateJSON", + "embeddableConfig.attributes.visState", } for _, fieldName := range jsonPaths { field := doc.Get(fieldName) @@ -207,6 +210,22 @@ func deserializeSubPaths(doc objx.Map) error { doc.Set(fieldName, parsed) } + jsonSlicePaths := []string{ + "attributes.layerListJSON", + "embeddableConfig.attributes.layerListJSON", + } + for _, fieldName := range jsonSlicePaths { + field := doc.Get(fieldName) + if !field.IsStr() { + continue + } + parsed, err := objx.FromJSONSlice(field.Str()) + if err != nil { + return fmt.Errorf("failed to decode embedded json in %q: %w", fieldName, err) + } + doc.Set(fieldName, parsed) + } + /* these transformations from the original script facilitate the vis_tsvb_aggs and other TSVB-related runtime fields TODO - implement these or convert the vis_tsvb_aggs and any other necessary runtime fields to Go diff --git a/kbncontent_test.go b/kbncontent_test.go index 90d5231..f5d4c76 100644 --- a/kbncontent_test.go +++ b/kbncontent_test.go @@ -21,7 +21,7 @@ func TestDescribeByValueDashboardPanels(t *testing.T) { }{ {title: "Legacy input control vis", editor: "Aggs-based", legacy: false, soType: "visualization", visType: "input_control_vis", tsvbType: "", makesQueries: true}, {title: "", editor: "Aggs-based", legacy: false, soType: "visualization", visType: "markdown", tsvbType: ""}, - {title: "", editor: "Lens", legacy: false, soType: "lens", visType: "", tsvbType: "", makesQueries: true}, + {title: "Lens bar", editor: "Lens", legacy: false, soType: "lens", visType: "", tsvbType: "", makesQueries: true}, {title: "Vega time series", editor: "Vega", legacy: false, soType: "visualization", visType: "vega", tsvbType: "", makesQueries: true}, {title: "", editor: "Maps", legacy: false, soType: "map", visType: "", tsvbType: "", makesQueries: true}, {title: "TSVB Markdown", editor: "TSVB", legacy: false, soType: "visualization", visType: "metrics", tsvbType: "markdown", makesQueries: true}, @@ -34,6 +34,8 @@ func TestDescribeByValueDashboardPanels(t *testing.T) { {title: "Aggs-based tag cloud", editor: "Aggs-based", legacy: true, soType: "visualization", visType: "tagcloud", tsvbType: "", makesQueries: true}, {title: "", editor: "Aggs-based", legacy: true, soType: "visualization", visType: "heatmap", tsvbType: "", makesQueries: true}, {title: "Timelion time series", editor: "Timelion", legacy: true, soType: "visualization", visType: "timelion", tsvbType: "", makesQueries: true}, + {title: "Unique IPs map", editor: "Maps", legacy: false, soType: "map", visType: "", tsvbType: "", makesQueries: true, hasFilters: true}, + {title: "Unique IPs map encoded", editor: "Maps", legacy: false, soType: "map", visType: "", tsvbType: "", makesQueries: true, hasFilters: true}, } content, err := ioutil.ReadFile("./testdata/dashboard.json") @@ -48,12 +50,11 @@ func TestDescribeByValueDashboardPanels(t *testing.T) { } descriptions, err := DescribeByValueDashboardPanels(dashboard) - if err != nil { t.Fatalf("Encountered error during subject execution: %v", err) } - assert.Equal(t, len(descriptions), 15, "The number of panels should be correct") + assert.Equal(t, len(descriptions), 17, "The number of panels should be correct") for i, desc := range descriptions { title := desc.Title() var editor string diff --git a/testdata/dashboard.json b/testdata/dashboard.json index 8f4f685..21a26e7 100644 --- a/testdata/dashboard.json +++ b/testdata/dashboard.json @@ -944,6 +944,275 @@ "panelRefName": "panel_6cc10baa-1976-4288-ba3a-9b8b8d5a5373", "type": "search", "version": "8.7.1" + }, + { + "embeddableConfig": { + "attributes": { + "description": "", + "layerListJSON": [ + { + "alpha": 1, + "id": "0378861a-232d-4383-a60b-ee38d55ce263", + "includeInFitToBounds": true, + "label": null, + "maxZoom": 24, + "minZoom": 0, + "sourceDescriptor": { + "isAutoSelect": true, + "lightModeDefault": "road_map_desaturated", + "type": "EMS_TMS" + }, + "style": { + "type": "TILE" + }, + "type": "EMS_VECTOR_TILE", + "visible": true + }, + { + "alpha": 0.75, + "id": "ced4b190-2f39-417e-ab9e-6557cb4996a2", + "includeInFitToBounds": true, + "joins": [], + "label": "Unique IPs map [Logs Apache]", + "maxZoom": 24, + "minZoom": 0, + "sourceDescriptor": { + "applyForceRefresh": true, + "applyGlobalQuery": true, + "applyGlobalTime": true, + "geoField": "source.geo.location", + "id": "844378cb-6817-449e-a434-8b50c9fd3dc9", + "indexPatternRefName": "layer_1_source_index_pattern", + "metrics": [ + { + "field": "source.address", + "type": "cardinality" + } + ], + "requestType": "point", + "resolution": "MOST_FINE", + "type": "ES_GEO_GRID" + }, + "style": { + "isTimeAware": true, + "properties": { + "fillColor": { + "options": { + "color": "Yellow to Red", + "colorCategory": "palette_0", + "field": { + "name": "cardinality_of_source.address", + "origin": "source" + }, + "fieldMetaOptions": { + "isEnabled": false, + "sigma": 3 + }, + "type": "ORDINAL" + }, + "type": "DYNAMIC" + }, + "icon": { + "options": { + "value": "marker" + }, + "type": "STATIC" + }, + "iconOrientation": { + "options": { + "orientation": 0 + }, + "type": "STATIC" + }, + "iconSize": { + "options": { + "field": { + "name": "cardinality_of_source.address", + "origin": "source" + }, + "fieldMetaOptions": { + "isEnabled": false, + "sigma": 3 + }, + "maxSize": 18, + "minSize": 7 + }, + "type": "DYNAMIC" + }, + "labelBorderColor": { + "options": { + "color": "#FFFFFF" + }, + "type": "STATIC" + }, + "labelBorderSize": { + "options": { + "size": "SMALL" + } + }, + "labelColor": { + "options": { + "color": "#000000" + }, + "type": "STATIC" + }, + "labelSize": { + "options": { + "size": 14 + }, + "type": "STATIC" + }, + "labelText": { + "options": { + "value": "" + }, + "type": "STATIC" + }, + "lineColor": { + "options": { + "color": "#3d3d3d" + }, + "type": "STATIC" + }, + "lineWidth": { + "options": { + "size": 1 + }, + "type": "STATIC" + }, + "symbolizeAs": { + "options": { + "value": "circle" + } + } + }, + "type": "VECTOR" + }, + "type": "GEOJSON_VECTOR", + "visible": true + } + ], + "mapStateJSON": { + "adHocDataViews": [], + "center": { + "lat": 19.94277, + "lon": 0 + }, + "filters": [], + "query": { + "language": "kuery", + "query": "data_stream.dataset:apache.access" + }, + "refreshConfig": { + "interval": 0, + "isPaused": true + }, + "settings": { + "autoFitToDataBounds": false, + "backgroundColor": "#ffffff", + "browserLocation": { + "zoom": 2 + }, + "customIcons": [], + "disableInteractive": false, + "disableTooltipControl": false, + "fixedLocation": { + "lat": 0, + "lon": 0, + "zoom": 2 + }, + "hideLayerControl": false, + "hideToolbarOverlay": false, + "hideViewControl": false, + "initialLocation": "LAST_SAVED_LOCATION", + "keydownScrollZoom": false, + "maxZoom": 24, + "minZoom": 0, + "showScaleControl": false, + "showSpatialFilters": true, + "showTimesliderToggleButton": true, + "spatialFiltersAlpa": 0.3, + "spatialFiltersFillColor": "#DA8B45", + "spatialFiltersLineColor": "#DA8B45" + }, + "timeFilters": { + "from": "now-15m", + "to": "now" + }, + "zoom": 1.58 + }, + "title": "", + "uiStateJSON": { + "isLayerTOCOpen": true, + "openTOCDetails": [] + } + }, + "enhancements": {}, + "hiddenLayers": [], + "hidePanelTitles": false, + "isLayerTOCOpen": true, + "mapBuffer": { + "maxLat": 66.51326, + "maxLon": 180, + "minLat": -66.51326, + "minLon": -180 + }, + "mapCenter": { + "lat": 19.94277, + "lon": 0, + "zoom": 1.58 + }, + "openTOCDetails": [] + }, + "gridData": { + "h": 15, + "i": "d9771ad7-cec0-4e4b-a51e-bbc880a8af0d", + "w": 48, + "x": 0, + "y": 30 + }, + "panelIndex": "d9771ad7-cec0-4e4b-a51e-bbc880a8af0d", + "title": "Unique IPs map", + "type": "map", + "version": "8.10.2" + }, + { + "embeddableConfig": { + "attributes": { + "description": "", + "layerListJSON": "[{\"alpha\":1,\"id\":\"0378861a-232d-4383-a60b-ee38d55ce263\",\"includeInFitToBounds\":true,\"label\":null,\"maxZoom\":24,\"minZoom\":0,\"sourceDescriptor\":{\"isAutoSelect\":true,\"lightModeDefault\":\"road_map_desaturated\",\"type\":\"EMS_TMS\"},\"style\":{\"type\":\"TILE\"},\"type\":\"EMS_VECTOR_TILE\",\"visible\":true},{\"alpha\":0.75,\"id\":\"ced4b190-2f39-417e-ab9e-6557cb4996a2\",\"includeInFitToBounds\":true,\"joins\":[],\"label\":\"Unique IPs map [Logs Apache]\",\"maxZoom\":24,\"minZoom\":0,\"sourceDescriptor\":{\"applyForceRefresh\":true,\"applyGlobalQuery\":true,\"applyGlobalTime\":true,\"geoField\":\"source.geo.location\",\"id\":\"844378cb-6817-449e-a434-8b50c9fd3dc9\",\"metrics\":[{\"field\":\"source.address\",\"type\":\"cardinality\"}],\"requestType\":\"point\",\"resolution\":\"MOST_FINE\",\"type\":\"ES_GEO_GRID\",\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"style\":{\"isTimeAware\":true,\"properties\":{\"fillColor\":{\"options\":{\"color\":\"Yellow to Red\",\"colorCategory\":\"palette_0\",\"field\":{\"name\":\"cardinality_of_source.address\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3},\"type\":\"ORDINAL\"},\"type\":\"DYNAMIC\"},\"icon\":{\"options\":{\"value\":\"marker\"},\"type\":\"STATIC\"},\"iconOrientation\":{\"options\":{\"orientation\":0},\"type\":\"STATIC\"},\"iconSize\":{\"options\":{\"field\":{\"name\":\"cardinality_of_source.address\",\"origin\":\"source\"},\"fieldMetaOptions\":{\"isEnabled\":false,\"sigma\":3},\"maxSize\":18,\"minSize\":7},\"type\":\"DYNAMIC\"},\"labelBorderColor\":{\"options\":{\"color\":\"#FFFFFF\"},\"type\":\"STATIC\"},\"labelBorderSize\":{\"options\":{\"size\":\"SMALL\"}},\"labelColor\":{\"options\":{\"color\":\"#000000\"},\"type\":\"STATIC\"},\"labelSize\":{\"options\":{\"size\":14},\"type\":\"STATIC\"},\"labelText\":{\"options\":{\"value\":\"\"},\"type\":\"STATIC\"},\"lineColor\":{\"options\":{\"color\":\"#3d3d3d\"},\"type\":\"STATIC\"},\"lineWidth\":{\"options\":{\"size\":1},\"type\":\"STATIC\"},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}}},\"type\":\"VECTOR\"},\"type\":\"GEOJSON_VECTOR\",\"visible\":true}]", + "mapStateJSON": "{\"adHocDataViews\":[],\"zoom\":1.58,\"center\":{\"lon\":0,\"lat\":19.94277},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":0},\"query\":{\"query\":\"data_stream.dataset:apache.access\",\"language\":\"kuery\"},\"filters\":[],\"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\":[]}" + }, + "enhancements": {}, + "hiddenLayers": [], + "hidePanelTitles": false, + "isLayerTOCOpen": true, + "mapBuffer": { + "maxLat": 66.51326, + "maxLon": 180, + "minLat": -66.51326, + "minLon": -180 + }, + "mapCenter": { + "lat": 19.94277, + "lon": 0, + "zoom": 1.58 + }, + "openTOCDetails": [] + }, + "gridData": { + "h": 15, + "i": "d9771ad7-cec0-4e4b-a51e-bbc880a8af0d", + "w": 48, + "x": 0, + "y": 30 + }, + "panelIndex": "d9771ad7-cec0-4e4b-a51e-bbc880a8af0d", + "title": "Unique IPs map encoded", + "type": "map", + "version": "8.10.2" } ], "timeRestore": false,