= ({
onCancel,
selectedObjects,
}) => {
+ const undeletableObjects = useMemo(() => {
+ return selectedObjects.filter((obj) => obj.meta.hiddenType);
+ }, [selectedObjects]);
+ const deletableObjects = useMemo(() => {
+ return selectedObjects.filter((obj) => !obj.meta.hiddenType);
+ }, [selectedObjects]);
+
if (isDeleting) {
return (
@@ -49,7 +57,6 @@ export const DeleteConfirmModal: FC = ({
);
}
-
// can't use `EuiConfirmModal` here as the confirm modal body is wrapped
// inside a `` element, causing UI glitches with the table.
return (
@@ -63,6 +70,29 @@ export const DeleteConfirmModal: FC = ({
+ {undeletableObjects.length > 0 && (
+ <>
+
+ }
+ iconType="alert"
+ color="warning"
+ >
+
+
+
+
+
+ >
+ )}
= ({
{
const component = shallowRender();
const mockSelectedSavedObjects = [
- { id: '1', type: 'index-pattern' },
- { id: '3', type: 'dashboard' },
+ { id: '1', type: 'index-pattern', meta: {} },
+ { id: '3', type: 'dashboard', meta: {} },
] as SavedObjectWithMetadata[];
// Ensure all promises resolve
@@ -498,8 +498,8 @@ describe('SavedObjectsTable', () => {
it('should delete selected objects', async () => {
const mockSelectedSavedObjects = [
- { id: '1', type: 'index-pattern' },
- { id: '3', type: 'dashboard' },
+ { id: '1', type: 'index-pattern', meta: {} },
+ { id: '3', type: 'dashboard', meta: {} },
] as SavedObjectWithMetadata[];
const mockSavedObjects = mockSelectedSavedObjects.map((obj) => ({
@@ -529,7 +529,6 @@ describe('SavedObjectsTable', () => {
await component.instance().delete();
expect(defaultProps.indexPatterns.clearCache).toHaveBeenCalled();
- expect(mockSavedObjectsClient.bulkGet).toHaveBeenCalledWith(mockSelectedSavedObjects);
expect(mockSavedObjectsClient.delete).toHaveBeenCalledWith(
mockSavedObjects[0].type,
mockSavedObjects[0].id,
@@ -542,5 +541,44 @@ describe('SavedObjectsTable', () => {
);
expect(component.state('selectedSavedObjects').length).toBe(0);
});
+
+ it('should not delete hidden selected objects', async () => {
+ const mockSelectedSavedObjects = [
+ { id: '1', type: 'index-pattern', meta: {} },
+ { id: '3', type: 'hidden-type', meta: { hiddenType: true } },
+ ] as SavedObjectWithMetadata[];
+
+ const mockSavedObjects = mockSelectedSavedObjects.map((obj) => ({
+ id: obj.id,
+ type: obj.type,
+ source: {},
+ }));
+
+ const mockSavedObjectsClient = {
+ ...defaultProps.savedObjectsClient,
+ bulkGet: jest.fn().mockImplementation(() => ({
+ savedObjects: mockSavedObjects,
+ })),
+ delete: jest.fn(),
+ };
+
+ const component = shallowRender({ savedObjectsClient: mockSavedObjectsClient });
+
+ // Ensure all promises resolve
+ await new Promise((resolve) => process.nextTick(resolve));
+ // Ensure the state changes are reflected
+ component.update();
+
+ // Set some as selected
+ component.instance().onSelectionChanged(mockSelectedSavedObjects);
+
+ await component.instance().delete();
+
+ expect(defaultProps.indexPatterns.clearCache).toHaveBeenCalled();
+ expect(mockSavedObjectsClient.delete).toHaveBeenCalledTimes(1);
+ expect(mockSavedObjectsClient.delete).toHaveBeenCalledWith('index-pattern', '1', {
+ force: true,
+ });
+ });
});
});
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
index 1d272e818ea1e..c207766918a70 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx
@@ -455,10 +455,9 @@ export class SavedObjectsTable extends Component
- savedObjectsClient.delete(object.type, object.id, { force: true })
- );
+ const deletes = selectedSavedObjects
+ .filter((object) => !object.meta.hiddenType)
+ .map((object) => savedObjectsClient.delete(object.type, object.id, { force: true }));
await Promise.all(deletes);
// Unset this
diff --git a/src/plugins/saved_objects_management/public/services/types/record.ts b/src/plugins/saved_objects_management/public/services/types/record.ts
index 17bdbc3a075f5..fc92c83cfc790 100644
--- a/src/plugins/saved_objects_management/public/services/types/record.ts
+++ b/src/plugins/saved_objects_management/public/services/types/record.ts
@@ -15,6 +15,7 @@ export interface SavedObjectsManagementRecord {
icon: string;
title: string;
namespaceType: SavedObjectsNamespaceType;
+ hiddenType: boolean;
};
references: SavedObjectReference[];
namespaces?: string[];
diff --git a/src/plugins/saved_objects_management/server/lib/find_relationships.test.ts b/src/plugins/saved_objects_management/server/lib/find_relationships.test.ts
index 686715aba7f17..0da14cbee4fd5 100644
--- a/src/plugins/saved_objects_management/server/lib/find_relationships.test.ts
+++ b/src/plugins/saved_objects_management/server/lib/find_relationships.test.ts
@@ -317,6 +317,7 @@ describe('findRelationships', () => {
title: 'title',
icon: 'icon',
editUrl: 'editUrl',
+ hiddenType: false,
inAppUrl: {
path: 'path',
uiCapabilitiesPath: 'uiCapabilitiesPath',
diff --git a/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.test.ts b/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.test.ts
index bc775a03e276d..7b5f52d6bf968 100644
--- a/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.test.ts
+++ b/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.test.ts
@@ -49,6 +49,7 @@ describe('injectMetaAttributes', () => {
uiCapabilitiesPath: 'uiCapabilitiesPath',
},
namespaceType: 'single',
+ hiddenType: false,
},
});
});
diff --git a/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.ts b/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.ts
index ee64010994109..d5b585371cbdf 100644
--- a/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.ts
+++ b/src/plugins/saved_objects_management/server/lib/inject_meta_attributes.ts
@@ -25,6 +25,7 @@ export function injectMetaAttributes(
result.meta.editUrl = savedObjectsManagement.getEditUrl(savedObject);
result.meta.inAppUrl = savedObjectsManagement.getInAppUrl(savedObject);
result.meta.namespaceType = savedObjectsManagement.getNamespaceType(savedObject);
+ result.meta.hiddenType = savedObjectsManagement.isHidden(savedObject);
return result;
}
diff --git a/src/plugins/saved_objects_management/server/services/management.mock.ts b/src/plugins/saved_objects_management/server/services/management.mock.ts
index 6541c0d2847f5..2ab5bea4f8440 100644
--- a/src/plugins/saved_objects_management/server/services/management.mock.ts
+++ b/src/plugins/saved_objects_management/server/services/management.mock.ts
@@ -19,6 +19,7 @@ const createManagementMock = () => {
getEditUrl: jest.fn(),
getInAppUrl: jest.fn(),
getNamespaceType: jest.fn(),
+ isHidden: jest.fn().mockReturnValue(false),
};
return mocked;
};
diff --git a/src/plugins/saved_objects_management/server/services/management.ts b/src/plugins/saved_objects_management/server/services/management.ts
index 395ba639846a8..176c52c5a21bc 100644
--- a/src/plugins/saved_objects_management/server/services/management.ts
+++ b/src/plugins/saved_objects_management/server/services/management.ts
@@ -44,4 +44,8 @@ export class SavedObjectsManagement {
public getNamespaceType(savedObject: SavedObject) {
return this.registry.getType(savedObject.type)?.namespaceType;
}
+
+ public isHidden(savedObject: SavedObject) {
+ return this.registry.getType(savedObject.type)?.hidden ?? false;
+ }
}
diff --git a/test/api_integration/apis/saved_objects_management/find.ts b/test/api_integration/apis/saved_objects_management/find.ts
index 8fb3884a5b37b..9bf3045bd0138 100644
--- a/test/api_integration/apis/saved_objects_management/find.ts
+++ b/test/api_integration/apis/saved_objects_management/find.ts
@@ -240,6 +240,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(resp.body.saved_objects[0].meta).to.eql({
icon: 'discoverApp',
title: 'OneRecord',
+ hiddenType: false,
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
@@ -259,6 +260,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(resp.body.saved_objects[0].meta).to.eql({
icon: 'dashboardApp',
title: 'Dashboard',
+ hiddenType: false,
editUrl:
'/management/kibana/objects/savedDashboards/b70c7ae0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
@@ -278,6 +280,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(resp.body.saved_objects[0].meta).to.eql({
icon: 'visualizeApp',
title: 'VisualizationFromSavedSearch',
+ hiddenType: false,
editUrl:
'/management/kibana/objects/savedVisualizations/a42c0580-3224-11e8-a572-ffca06da1357',
inAppUrl: {
@@ -289,6 +292,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(resp.body.saved_objects[1].meta).to.eql({
icon: 'visualizeApp',
title: 'Visualization',
+ hiddenType: false,
editUrl:
'/management/kibana/objects/savedVisualizations/add810b0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
@@ -308,6 +312,7 @@ export default function ({ getService }: FtrProviderContext) {
expect(resp.body.saved_objects[0].meta).to.eql({
icon: 'indexPatternApp',
title: 'saved_objects*',
+ hiddenType: false,
editUrl:
'/management/kibana/indexPatterns/patterns/8963ca30-3224-11e8-a572-ffca06da1357',
inAppUrl: {
diff --git a/test/api_integration/apis/saved_objects_management/relationships.ts b/test/api_integration/apis/saved_objects_management/relationships.ts
index fee525067719f..17e562d221d72 100644
--- a/test/api_integration/apis/saved_objects_management/relationships.ts
+++ b/test/api_integration/apis/saved_objects_management/relationships.ts
@@ -27,6 +27,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: schema.string(),
}),
namespaceType: schema.string(),
+ hiddenType: schema.boolean(),
}),
});
const invalidRelationSchema = schema.object({
@@ -89,6 +90,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'management.kibana.indexPatterns',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
{
@@ -105,6 +107,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
]);
@@ -132,6 +135,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'management.kibana.indexPatterns',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'child',
},
@@ -148,6 +152,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'parent',
},
@@ -192,6 +197,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
{
@@ -208,6 +214,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
]);
@@ -232,6 +239,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'child',
},
@@ -248,6 +256,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'child',
},
@@ -292,6 +301,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
{
@@ -308,6 +318,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'dashboard.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
]);
@@ -334,6 +345,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'child',
},
@@ -378,6 +390,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
{
@@ -394,6 +407,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
},
]);
@@ -420,6 +434,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'single',
+ hiddenType: false,
},
relationship: 'parent',
},
@@ -466,6 +481,7 @@ export default function ({ getService }: FtrProviderContext) {
uiCapabilitiesPath: 'visualize.show',
},
namespaceType: 'single',
+ hiddenType: false,
title: 'Visualization',
},
relationship: 'child',
diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/data.json b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/data.json
new file mode 100644
index 0000000000000..057373579c100
--- /dev/null
+++ b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/data.json
@@ -0,0 +1,88 @@
+{
+ "type": "doc",
+ "value": {
+ "index": ".kibana",
+ "type": "doc",
+ "id": "test-actions-export-hidden:obj_1",
+ "source": {
+ "test-actions-export-hidden": {
+ "title": "hidden object 1"
+ },
+ "type": "test-actions-export-hidden",
+ "migrationVersion": {},
+ "updated_at": "2018-12-21T00:43:07.096Z"
+ }
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "index": ".kibana",
+ "type": "doc",
+ "id": "test-actions-export-hidden:obj_2",
+ "source": {
+ "test-actions-export-hidden": {
+ "title": "hidden object 2"
+ },
+ "type": "test-actions-export-hidden",
+ "migrationVersion": {},
+ "updated_at": "2018-12-21T00:43:07.096Z"
+ }
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "index": ".kibana",
+ "type": "doc",
+ "id": "visualization:75c3e060-1e7c-11e9-8488-65449e65d0ed",
+ "source": {
+ "visualization": {
+ "title": "A Pie",
+ "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}",
+ "uiStateJSON": "{}",
+ "description": "",
+ "version": 1,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
+ }
+ },
+ "type": "visualization",
+ "updated_at": "2019-01-22T19:32:31.206Z"
+ },
+ "references" : [
+ {
+ "name" : "kibanaSavedObjectMeta.searchSourceJSON.index",
+ "type" : "index-pattern",
+ "id" : "logstash-*"
+ }
+ ]
+ }
+}
+
+{
+ "type": "doc",
+ "value": {
+ "index": ".kibana",
+ "type": "doc",
+ "id": "dashboard:i-exist",
+ "source": {
+ "dashboard": {
+ "title": "A Dashboard",
+ "hits": 0,
+ "description": "",
+ "panelsJSON": "[{\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"1\"},\"version\":\"7.0.0\",\"panelIndex\":\"1\",\"type\":\"visualization\",\"id\":\"75c3e060-1e7c-11e9-8488-65449e65d0ed\",\"embeddableConfig\":{}}]",
+ "optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
+ "version": 1,
+ "timeRestore": false,
+ "kibanaSavedObjectMeta": {
+ "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[]}"
+ }
+ },
+ "type": "dashboard",
+ "updated_at": "2019-01-22T19:32:47.232Z"
+ }
+ }
+}
diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/mappings.json
new file mode 100644
index 0000000000000..a862731c13f7a
--- /dev/null
+++ b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_types/mappings.json
@@ -0,0 +1,504 @@
+{
+ "type": "index",
+ "value": {
+ "index": ".kibana",
+ "settings": {
+ "index": {
+ "number_of_shards": "1",
+ "auto_expand_replicas": "0-1",
+ "number_of_replicas": "0"
+ }
+ },
+ "mappings": {
+ "dynamic": true,
+ "properties": {
+ "test-actions-export-hidden": {
+ "properties": {
+ "title": { "type": "text" }
+ }
+ },
+ "test-export-transform": {
+ "properties": {
+ "title": { "type": "text" },
+ "enabled": { "type": "boolean" }
+ }
+ },
+ "test-export-add": {
+ "properties": {
+ "title": { "type": "text" }
+ }
+ },
+ "test-export-add-dep": {
+ "properties": {
+ "title": { "type": "text" }
+ }
+ },
+ "test-export-transform-error": {
+ "properties": {
+ "title": { "type": "text" }
+ }
+ },
+ "test-export-invalid-transform": {
+ "properties": {
+ "title": { "type": "text" }
+ }
+ },
+ "apm-telemetry": {
+ "properties": {
+ "has_any_services": {
+ "type": "boolean"
+ },
+ "services_per_agent": {
+ "properties": {
+ "go": {
+ "type": "long",
+ "null_value": 0
+ },
+ "java": {
+ "type": "long",
+ "null_value": 0
+ },
+ "js-base": {
+ "type": "long",
+ "null_value": 0
+ },
+ "nodejs": {
+ "type": "long",
+ "null_value": 0
+ },
+ "python": {
+ "type": "long",
+ "null_value": 0
+ },
+ "ruby": {
+ "type": "long",
+ "null_value": 0
+ }
+ }
+ }
+ }
+ },
+ "canvas-workpad": {
+ "dynamic": "false",
+ "properties": {
+ "@created": {
+ "type": "date"
+ },
+ "@timestamp": {
+ "type": "date"
+ },
+ "id": {
+ "type": "text",
+ "index": false
+ },
+ "name": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword"
+ }
+ }
+ }
+ }
+ },
+ "config": {
+ "dynamic": "true",
+ "properties": {
+ "accessibility:disableAnimations": {
+ "type": "boolean"
+ },
+ "buildNum": {
+ "type": "keyword"
+ },
+ "dateFormat:tz": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ },
+ "defaultIndex": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ },
+ "telemetry:optIn": {
+ "type": "boolean"
+ }
+ }
+ },
+ "dashboard": {
+ "properties": {
+ "description": {
+ "type": "text"
+ },
+ "hits": {
+ "type": "integer"
+ },
+ "kibanaSavedObjectMeta": {
+ "properties": {
+ "searchSourceJSON": {
+ "type": "text"
+ }
+ }
+ },
+ "optionsJSON": {
+ "type": "text"
+ },
+ "panelsJSON": {
+ "type": "text"
+ },
+ "refreshInterval": {
+ "properties": {
+ "display": {
+ "type": "keyword"
+ },
+ "pause": {
+ "type": "boolean"
+ },
+ "section": {
+ "type": "integer"
+ },
+ "value": {
+ "type": "integer"
+ }
+ }
+ },
+ "timeFrom": {
+ "type": "keyword"
+ },
+ "timeRestore": {
+ "type": "boolean"
+ },
+ "timeTo": {
+ "type": "keyword"
+ },
+ "title": {
+ "type": "text"
+ },
+ "uiStateJSON": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ }
+ }
+ },
+ "map": {
+ "properties": {
+ "bounds": {
+ "type": "geo_shape",
+ "tree": "quadtree"
+ },
+ "description": {
+ "type": "text"
+ },
+ "layerListJSON": {
+ "type": "text"
+ },
+ "mapStateJSON": {
+ "type": "text"
+ },
+ "title": {
+ "type": "text"
+ },
+ "uiStateJSON": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ }
+ }
+ },
+ "graph-workspace": {
+ "properties": {
+ "description": {
+ "type": "text"
+ },
+ "kibanaSavedObjectMeta": {
+ "properties": {
+ "searchSourceJSON": {
+ "type": "text"
+ }
+ }
+ },
+ "numLinks": {
+ "type": "integer"
+ },
+ "numVertices": {
+ "type": "integer"
+ },
+ "title": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ },
+ "wsState": {
+ "type": "text"
+ }
+ }
+ },
+ "index-pattern": {
+ "properties": {
+ "fieldFormatMap": {
+ "type": "text"
+ },
+ "fields": {
+ "type": "text"
+ },
+ "intervalName": {
+ "type": "keyword"
+ },
+ "notExpandable": {
+ "type": "boolean"
+ },
+ "sourceFilters": {
+ "type": "text"
+ },
+ "timeFieldName": {
+ "type": "keyword"
+ },
+ "title": {
+ "type": "text"
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "typeMeta": {
+ "type": "keyword"
+ }
+ }
+ },
+ "kql-telemetry": {
+ "properties": {
+ "optInCount": {
+ "type": "long"
+ },
+ "optOutCount": {
+ "type": "long"
+ }
+ }
+ },
+ "migrationVersion": {
+ "dynamic": "true",
+ "properties": {
+ "index-pattern": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ },
+ "space": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 256
+ }
+ }
+ }
+ }
+ },
+ "namespace": {
+ "type": "keyword"
+ },
+ "search": {
+ "properties": {
+ "columns": {
+ "type": "keyword"
+ },
+ "description": {
+ "type": "text"
+ },
+ "hits": {
+ "type": "integer"
+ },
+ "kibanaSavedObjectMeta": {
+ "properties": {
+ "searchSourceJSON": {
+ "type": "text"
+ }
+ }
+ },
+ "sort": {
+ "type": "keyword"
+ },
+ "title": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ }
+ }
+ },
+ "server": {
+ "properties": {
+ "uuid": {
+ "type": "keyword"
+ }
+ }
+ },
+ "space": {
+ "properties": {
+ "_reserved": {
+ "type": "boolean"
+ },
+ "color": {
+ "type": "keyword"
+ },
+ "description": {
+ "type": "text"
+ },
+ "disabledFeatures": {
+ "type": "keyword"
+ },
+ "initials": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 2048
+ }
+ }
+ }
+ }
+ },
+ "spaceId": {
+ "type": "keyword"
+ },
+ "telemetry": {
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ }
+ },
+ "timelion-sheet": {
+ "properties": {
+ "description": {
+ "type": "text"
+ },
+ "hits": {
+ "type": "integer"
+ },
+ "kibanaSavedObjectMeta": {
+ "properties": {
+ "searchSourceJSON": {
+ "type": "text"
+ }
+ }
+ },
+ "timelion_chart_height": {
+ "type": "integer"
+ },
+ "timelion_columns": {
+ "type": "integer"
+ },
+ "timelion_interval": {
+ "type": "keyword"
+ },
+ "timelion_other_interval": {
+ "type": "keyword"
+ },
+ "timelion_rows": {
+ "type": "integer"
+ },
+ "timelion_sheet": {
+ "type": "text"
+ },
+ "title": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ }
+ }
+ },
+ "type": {
+ "type": "keyword"
+ },
+ "updated_at": {
+ "type": "date"
+ },
+ "url": {
+ "properties": {
+ "accessCount": {
+ "type": "long"
+ },
+ "accessDate": {
+ "type": "date"
+ },
+ "createDate": {
+ "type": "date"
+ },
+ "url": {
+ "type": "text",
+ "fields": {
+ "keyword": {
+ "type": "keyword",
+ "ignore_above": 2048
+ }
+ }
+ }
+ }
+ },
+ "visualization": {
+ "properties": {
+ "description": {
+ "type": "text"
+ },
+ "kibanaSavedObjectMeta": {
+ "properties": {
+ "searchSourceJSON": {
+ "type": "text"
+ }
+ }
+ },
+ "savedSearchId": {
+ "type": "keyword"
+ },
+ "title": {
+ "type": "text"
+ },
+ "uiStateJSON": {
+ "type": "text"
+ },
+ "version": {
+ "type": "integer"
+ },
+ "visState": {
+ "type": "text"
+ }
+ }
+ },
+ "references": {
+ "properties": {
+ "id": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ },
+ "type": {
+ "type": "keyword"
+ }
+ },
+ "type": "nested"
+ }
+ }
+ }
+ }
+}
diff --git a/test/functional/page_objects/management/saved_objects_page.ts b/test/functional/page_objects/management/saved_objects_page.ts
index c28d351aa77fb..fc4de6ed7f82f 100644
--- a/test/functional/page_objects/management/saved_objects_page.ts
+++ b/test/functional/page_objects/management/saved_objects_page.ts
@@ -294,10 +294,12 @@ export function SavedObjectsPageProvider({ getService, getPageObjects }: FtrProv
return await testSubjects.isEnabled('savedObjectsManagementDelete');
}
- async clickDelete() {
+ async clickDelete({ confirmDelete = true }: { confirmDelete?: boolean } = {}) {
await testSubjects.click('savedObjectsManagementDelete');
- await testSubjects.click('confirmModalConfirmButton');
- await this.waitTableIsLoaded();
+ if (confirmDelete) {
+ await testSubjects.click('confirmModalConfirmButton');
+ await this.waitTableIsLoaded();
+ }
}
async getImportWarnings() {
diff --git a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
index daaf6426bdddc..408ac03dd946b 100644
--- a/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
+++ b/test/plugin_functional/plugins/saved_object_export_transforms/server/plugin.ts
@@ -90,8 +90,6 @@ export class SavedObjectExportTransformsPlugin implements Plugin {
},
});
- /////////////
- /////////////
// example of a SO type that will throw an object-transform-error
savedObjects.registerType({
name: 'test-export-transform-error',
@@ -134,8 +132,29 @@ export class SavedObjectExportTransformsPlugin implements Plugin {
},
},
});
+
+ // example of a SO type that is exportable while being hidden
+ savedObjects.registerType({
+ name: 'test-actions-export-hidden',
+ hidden: true,
+ namespaceType: 'single',
+ mappings: {
+ properties: {
+ title: { type: 'text' },
+ enabled: {
+ type: 'boolean',
+ },
+ },
+ },
+ management: {
+ defaultSearchField: 'title',
+ importableAndExportable: true,
+ getTitle: (obj) => obj.attributes.title,
+ },
+ });
}
public start() {}
+
public stop() {}
}
diff --git a/test/plugin_functional/test_suites/saved_objects_hidden_type/index.ts b/test/plugin_functional/test_suites/saved_objects_hidden_type/index.ts
index 00ba74a988cf4..ba4835cdab089 100644
--- a/test/plugin_functional/test_suites/saved_objects_hidden_type/index.ts
+++ b/test/plugin_functional/test_suites/saved_objects_hidden_type/index.ts
@@ -15,6 +15,5 @@ export default function ({ loadTestFile }: PluginFunctionalProviderContext) {
loadTestFile(require.resolve('./resolve_import_errors'));
loadTestFile(require.resolve('./find'));
loadTestFile(require.resolve('./delete'));
- loadTestFile(require.resolve('./interface/saved_objects_management'));
});
}
diff --git a/test/plugin_functional/test_suites/saved_objects_hidden_type/interface/saved_objects_management.ts b/test/plugin_functional/test_suites/saved_objects_hidden_type/interface/saved_objects_management.ts
deleted file mode 100644
index dfd0b9dd07476..0000000000000
--- a/test/plugin_functional/test_suites/saved_objects_hidden_type/interface/saved_objects_management.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0 and the Server Side Public License, v 1; you may not use this file except
- * in compliance with, at your election, the Elastic License 2.0 or the Server
- * Side Public License, v 1.
- */
-
-import path from 'path';
-import expect from '@kbn/expect';
-import { PluginFunctionalProviderContext } from '../../../services';
-
-export default function ({ getPageObjects, getService }: PluginFunctionalProviderContext) {
- const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects']);
- const esArchiver = getService('esArchiver');
- const fixturePaths = {
- hiddenImportable: path.join(__dirname, 'exports', '_import_hidden_importable.ndjson'),
- hiddenNonImportable: path.join(__dirname, 'exports', '_import_hidden_non_importable.ndjson'),
- };
-
- describe('Saved objects management Interface', () => {
- before(() => esArchiver.emptyKibanaIndex());
- beforeEach(async () => {
- await PageObjects.settings.navigateTo();
- await PageObjects.settings.clickKibanaSavedObjects();
- });
- describe('importable/exportable hidden type', () => {
- it('imports objects successfully', async () => {
- await PageObjects.savedObjects.importFile(fixturePaths.hiddenImportable);
- await PageObjects.savedObjects.checkImportSucceeded();
- });
-
- it('shows test-hidden-importable-exportable in table', async () => {
- await PageObjects.savedObjects.searchForObject('type:(test-hidden-importable-exportable)');
- const results = await PageObjects.savedObjects.getTableSummary();
- expect(results.length).to.be(1);
-
- const { title } = results[0];
- expect(title).to.be(
- 'test-hidden-importable-exportable [id=ff3733a0-9fty-11e7-ahb3-3dcb94193fab]'
- );
- });
- });
-
- describe('non-importable/exportable hidden type', () => {
- it('fails to import object', async () => {
- await PageObjects.savedObjects.importFile(fixturePaths.hiddenNonImportable);
- await PageObjects.savedObjects.checkImportSucceeded();
-
- const errorsCount = await PageObjects.savedObjects.getImportErrorsCount();
- expect(errorsCount).to.be(1);
- });
- });
- });
-}
diff --git a/test/plugin_functional/test_suites/saved_objects_hidden_type/interface/exports/_import_hidden_importable.ndjson b/test/plugin_functional/test_suites/saved_objects_management/exports/_import_hidden_importable.ndjson
similarity index 100%
rename from test/plugin_functional/test_suites/saved_objects_hidden_type/interface/exports/_import_hidden_importable.ndjson
rename to test/plugin_functional/test_suites/saved_objects_management/exports/_import_hidden_importable.ndjson
diff --git a/test/plugin_functional/test_suites/saved_objects_hidden_type/interface/exports/_import_hidden_non_importable.ndjson b/test/plugin_functional/test_suites/saved_objects_management/exports/_import_hidden_non_importable.ndjson
similarity index 100%
rename from test/plugin_functional/test_suites/saved_objects_hidden_type/interface/exports/_import_hidden_non_importable.ndjson
rename to test/plugin_functional/test_suites/saved_objects_management/exports/_import_hidden_non_importable.ndjson
diff --git a/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts b/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts
new file mode 100644
index 0000000000000..464b7c6e7ced7
--- /dev/null
+++ b/test/plugin_functional/test_suites/saved_objects_management/hidden_types.ts
@@ -0,0 +1,127 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import path from 'path';
+import expect from '@kbn/expect';
+import { PluginFunctionalProviderContext } from '../../services';
+
+const fixturePaths = {
+ hiddenImportable: path.join(__dirname, 'exports', '_import_hidden_importable.ndjson'),
+ hiddenNonImportable: path.join(__dirname, 'exports', '_import_hidden_non_importable.ndjson'),
+};
+
+export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
+ const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects']);
+ const supertest = getService('supertest');
+ const esArchiver = getService('esArchiver');
+ const testSubjects = getService('testSubjects');
+
+ describe('saved objects management with hidden types', () => {
+ before(async () => {
+ await esArchiver.load(
+ '../functional/fixtures/es_archiver/saved_objects_management/hidden_types'
+ );
+ });
+
+ after(async () => {
+ await esArchiver.unload(
+ '../functional/fixtures/es_archiver/saved_objects_management/hidden_types'
+ );
+ });
+
+ beforeEach(async () => {
+ await PageObjects.settings.navigateTo();
+ await PageObjects.settings.clickKibanaSavedObjects();
+ });
+
+ describe('API calls', () => {
+ it('should flag the object as hidden in its meta', async () => {
+ await supertest
+ .get('/api/kibana/management/saved_objects/_find?type=test-actions-export-hidden')
+ .set('kbn-xsrf', 'true')
+ .expect(200)
+ .then((resp) => {
+ expect(
+ resp.body.saved_objects.map((obj: any) => ({
+ id: obj.id,
+ type: obj.type,
+ hidden: obj.meta.hiddenType,
+ }))
+ ).to.eql([
+ {
+ id: 'obj_1',
+ type: 'test-actions-export-hidden',
+ hidden: true,
+ },
+ {
+ id: 'obj_2',
+ type: 'test-actions-export-hidden',
+ hidden: true,
+ },
+ ]);
+ });
+ });
+ });
+
+ describe('Delete modal', () => {
+ it('should display a warning then trying to delete hidden saved objects', async () => {
+ await PageObjects.savedObjects.clickCheckboxByTitle('A Pie');
+ await PageObjects.savedObjects.clickCheckboxByTitle('A Dashboard');
+ await PageObjects.savedObjects.clickCheckboxByTitle('hidden object 1');
+
+ await PageObjects.savedObjects.clickDelete({ confirmDelete: false });
+ expect(await testSubjects.exists('cannotDeleteObjectsConfirmWarning')).to.eql(true);
+ });
+
+ it('should not delete the hidden objects when performing the operation', async () => {
+ await PageObjects.savedObjects.clickCheckboxByTitle('A Pie');
+ await PageObjects.savedObjects.clickCheckboxByTitle('hidden object 1');
+
+ await PageObjects.savedObjects.clickDelete({ confirmDelete: true });
+
+ const objectNames = (await PageObjects.savedObjects.getTableSummary()).map(
+ (obj) => obj.title
+ );
+ expect(objectNames.includes('hidden object 1')).to.eql(true);
+ expect(objectNames.includes('A Pie')).to.eql(false);
+ });
+ });
+
+ describe('importing hidden types', () => {
+ describe('importable/exportable hidden type', () => {
+ it('imports objects successfully', async () => {
+ await PageObjects.savedObjects.importFile(fixturePaths.hiddenImportable);
+ await PageObjects.savedObjects.checkImportSucceeded();
+ });
+
+ it('shows test-hidden-importable-exportable in table', async () => {
+ await PageObjects.savedObjects.searchForObject(
+ 'type:(test-hidden-importable-exportable)'
+ );
+ const results = await PageObjects.savedObjects.getTableSummary();
+ expect(results.length).to.be(1);
+
+ const { title } = results[0];
+ expect(title).to.be(
+ 'test-hidden-importable-exportable [id=ff3733a0-9fty-11e7-ahb3-3dcb94193fab]'
+ );
+ });
+ });
+
+ describe('non-importable/exportable hidden type', () => {
+ it('fails to import object', async () => {
+ await PageObjects.savedObjects.importFile(fixturePaths.hiddenNonImportable);
+ await PageObjects.savedObjects.checkImportSucceeded();
+
+ const errorsCount = await PageObjects.savedObjects.getImportErrorsCount();
+ expect(errorsCount).to.be(1);
+ });
+ });
+ });
+ });
+}
diff --git a/test/plugin_functional/test_suites/saved_objects_management/index.ts b/test/plugin_functional/test_suites/saved_objects_management/index.ts
index 9f2d28b582f78..edaa819e5ea58 100644
--- a/test/plugin_functional/test_suites/saved_objects_management/index.ts
+++ b/test/plugin_functional/test_suites/saved_objects_management/index.ts
@@ -15,5 +15,6 @@ export default function ({ loadTestFile }: PluginFunctionalProviderContext) {
loadTestFile(require.resolve('./get'));
loadTestFile(require.resolve('./export_transform'));
loadTestFile(require.resolve('./import_warnings'));
+ loadTestFile(require.resolve('./hidden_types'));
});
}
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_action.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_action.tsx
index 57ea66f35ba0c..7818e648dd1cf 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_action.tsx
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/copy_saved_objects_to_space_action.tsx
@@ -55,7 +55,7 @@ export class CopyToSpaceSavedObjectsManagementAction extends SavedObjectsManagem
icon: 'copy',
type: 'icon',
available: (object: SavedObjectsManagementRecord) => {
- return object.meta.namespaceType !== 'agnostic';
+ return object.meta.namespaceType !== 'agnostic' && !object.meta.hiddenType;
},
onClick: (object: SavedObjectsManagementRecord) => {
this.start(object);
diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/lib/summarize_copy_result.test.ts b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/lib/summarize_copy_result.test.ts
index 5a0ad95b6bead..6a3d82aaef59c 100644
--- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/lib/summarize_copy_result.test.ts
+++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/lib/summarize_copy_result.test.ts
@@ -33,7 +33,12 @@ const OBJECTS = {
MY_DASHBOARD: {
type: 'dashboard',
id: 'foo',
- meta: { title: 'my-dashboard-title', icon: 'dashboardApp', namespaceType: 'single' },
+ meta: {
+ title: 'my-dashboard-title',
+ icon: 'dashboardApp',
+ namespaceType: 'single',
+ hiddenType: false,
+ },
references: [
{ type: 'visualization', id: 'foo', name: 'Visualization foo' },
{ type: 'visualization', id: 'bar', name: 'Visualization bar' },
@@ -42,25 +47,45 @@ const OBJECTS = {
VISUALIZATION_FOO: {
type: 'visualization',
id: 'bar',
- meta: { title: 'visualization-foo-title', icon: 'visualizeApp', namespaceType: 'single' },
+ meta: {
+ title: 'visualization-foo-title',
+ icon: 'visualizeApp',
+ namespaceType: 'single',
+ hiddenType: false,
+ },
references: [{ type: 'index-pattern', id: 'foo', name: 'Index pattern foo' }],
} as SavedObjectsManagementRecord,
VISUALIZATION_BAR: {
type: 'visualization',
id: 'baz',
- meta: { title: 'visualization-bar-title', icon: 'visualizeApp', namespaceType: 'single' },
+ meta: {
+ title: 'visualization-bar-title',
+ icon: 'visualizeApp',
+ namespaceType: 'single',
+ hiddenType: false,
+ },
references: [{ type: 'index-pattern', id: 'bar', name: 'Index pattern bar' }],
} as SavedObjectsManagementRecord,
INDEX_PATTERN_FOO: {
type: 'index-pattern',
id: 'foo',
- meta: { title: 'index-pattern-foo-title', icon: 'indexPatternApp', namespaceType: 'single' },
+ meta: {
+ title: 'index-pattern-foo-title',
+ icon: 'indexPatternApp',
+ namespaceType: 'single',
+ hiddenType: false,
+ },
references: [],
} as SavedObjectsManagementRecord,
INDEX_PATTERN_BAR: {
type: 'index-pattern',
id: 'bar',
- meta: { title: 'index-pattern-bar-title', icon: 'indexPatternApp', namespaceType: 'single' },
+ meta: {
+ title: 'index-pattern-bar-title',
+ icon: 'indexPatternApp',
+ namespaceType: 'single',
+ hiddenType: false,
+ },
references: [],
} as SavedObjectsManagementRecord,
};
@@ -70,6 +95,7 @@ interface ObjectProperties {
id: string;
meta: { title?: string; icon?: string };
}
+
const createSuccessResult = ({ type, id, meta }: ObjectProperties) => {
return { type, id, meta };
};
@@ -190,6 +216,7 @@ describe('summarizeCopyResult', () => {
"obj": Object {
"id": "bar",
"meta": Object {
+ "hiddenType": false,
"icon": "visualizeApp",
"namespaceType": "single",
"title": "visualization-foo-title",
diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_action.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_action.tsx
index 657ff8ac0bc70..9a0d171342a80 100644
--- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_action.tsx
+++ b/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_action.tsx
@@ -40,7 +40,8 @@ export class ShareToSpaceSavedObjectsManagementAction extends SavedObjectsManage
const hasCapability =
!this.actionContext ||
!!this.actionContext.capabilities.savedObjectsManagement.shareIntoSpace;
- return object.meta.namespaceType === 'multiple' && hasCapability;
+ const { namespaceType, hiddenType } = object.meta;
+ return namespaceType === 'multiple' && !hiddenType && hasCapability;
},
onClick: (object: SavedObjectsManagementRecord) => {
this.isDataChanged = false;
From c24c0d38f8ba40c61a29bb87f6c40da432869ae8 Mon Sep 17 00:00:00 2001
From: Yara Tercero
Date: Tue, 27 Apr 2021 23:06:53 -0700
Subject: [PATCH 20/28] [Security Solution][Tech Debt] - Fix flakey notes tab
cypress test (#98439)
Fix flakey cypress test related to notes_tab before/after hooks.
---
.../cypress/integration/timelines/notes_tab.spec.ts | 2 +-
.../plugins/security_solution/cypress/screens/timeline.ts | 2 +-
x-pack/plugins/security_solution/cypress/tasks/timeline.ts | 6 ++++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/notes_tab.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/notes_tab.spec.ts
index 6653290fc2ebb..ebf40677112e8 100644
--- a/x-pack/plugins/security_solution/cypress/integration/timelines/notes_tab.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/timelines/notes_tab.spec.ts
@@ -41,8 +41,8 @@ describe('Timeline notes tab', () => {
.click({ force: true })
.then(() => {
waitForEventsPanelToBeLoaded();
- goToNotesTab();
addNotesToTimeline(timeline.notes);
+ goToNotesTab();
});
});
});
diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts
index 4c80f266e687c..0352320e25194 100644
--- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts
+++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts
@@ -63,7 +63,7 @@ export const NOTE_CONTENT = (noteId: string) => `${NOTE_BY_NOTE_ID(noteId)} p`;
export const NOTES_TEXT_AREA = '[data-test-subj="add-a-note"] textarea';
-export const NOTES_TAB_BUTTON = '[data-test-subj="timelineTabs-notes"]';
+export const NOTES_TAB_BUTTON = 'button[data-test-subj="timelineTabs-notes"]';
export const NOTES_TEXT = '.euiMarkdownFormat';
diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts
index 2078744393d94..89ced4b64cc2c 100644
--- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts
+++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts
@@ -90,7 +90,9 @@ export const addNameAndDescriptionToTimeline = (timeline: Timeline) => {
};
export const goToNotesTab = () => {
- return cy.get(NOTES_TAB_BUTTON).click({ force: true });
+ cy.get(NOTES_TAB_BUTTON)
+ .pipe(($el) => $el.trigger('click'))
+ .should('be.visible');
};
export const getNotePreviewByNoteId = (noteId: string) => {
@@ -205,7 +207,7 @@ export const openTimelineTemplateFromSettings = (id: string) => {
};
export const openTimelineById = (timelineId: string) => {
- return cy.get(TIMELINE_TITLE_BY_ID(timelineId)).click({ force: true });
+ return cy.get(TIMELINE_TITLE_BY_ID(timelineId)).pipe(($el) => $el.trigger('click'));
};
export const pinFirstEvent = () => {
From bfb363f050200fa29c78f0999adc3d40d77927f2 Mon Sep 17 00:00:00 2001
From: Walter Rafelsberger
Date: Wed, 28 Apr 2021 08:23:07 +0200
Subject: [PATCH 21/28] [ML] Transforms/Data Frame Analytics: Fix freezing
wizard for indices with massive amounts of fields. (#98259)
The transform wizard can become very slow when used with indices with e.g. 1000+ fields.
This PR fixes it by prefetching 500 random documents to create a list of populated/used fields and passes those on to the data grid component instead of all available fields from the list derived via Kibana index patterns.
For example, for an out of the box metricbeat index, this reduces the list of passed on fields from 3000+ to ~120 fields. Previously, the page would freeze on load for tens of seconds and would freeze again on every rerender. With the applied update, the page loads almost instantly again and remains responsive.
Note this fix of reducing available fields is only applied to the data grid preview component. All fields are still available to create the configuration in the UI for groups and aggregations. These UI components, e.g. the virtualized dropdowns, can handle large lists of fields.
---
.../hooks/use_index_data.ts | 83 +++++++++++++++----
.../public/app/hooks/use_index_data.ts | 61 +++++++++++++-
.../public/app/hooks/use_pivot_data.ts | 35 ++++++--
.../apps/transform/creation_index_pattern.ts | 28 ++++---
.../transform/creation_runtime_mappings.ts | 28 ++++++-
.../functional/services/transform/wizard.ts | 9 ++
6 files changed, 206 insertions(+), 38 deletions(-)
diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts
index 2ae75083bff43..87dd6709e82f4 100644
--- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts
+++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/hooks/use_index_data.ts
@@ -50,19 +50,21 @@ function getRuntimeFieldColumns(runtimeMappings: RuntimeMappings) {
});
}
-function getInitialColumns(indexPattern: IndexPattern) {
+function getInitialColumns(indexPattern: IndexPattern, fieldsFilter: string[]) {
const { fields } = newJobCapsServiceAnalytics;
- const columns = fields.map((field: any) => {
- const schema =
- getDataGridSchemaFromESFieldType(field.type) || getDataGridSchemaFromKibanaFieldType(field);
-
- return {
- id: field.name,
- schema,
- isExpandable: schema !== 'boolean',
- isRuntimeFieldColumn: false,
- };
- });
+ const columns = fields
+ .filter((field) => fieldsFilter.includes(field.name))
+ .map((field) => {
+ const schema =
+ getDataGridSchemaFromESFieldType(field.type) || getDataGridSchemaFromKibanaFieldType(field);
+
+ return {
+ id: field.name,
+ schema,
+ isExpandable: schema !== 'boolean',
+ isRuntimeFieldColumn: false,
+ };
+ });
// Add runtime fields defined in index pattern to columns
if (indexPattern) {
@@ -91,10 +93,57 @@ export const useIndexData = (
toastNotifications: CoreSetup['notifications']['toasts'],
runtimeMappings?: RuntimeMappings
): UseIndexDataReturnType => {
- const indexPatternFields = useMemo(() => getFieldsFromKibanaIndexPattern(indexPattern), [
- indexPattern,
- ]);
- const [columns, setColumns] = useState(getInitialColumns(indexPattern));
+ const [indexPatternFields, setIndexPatternFields] = useState();
+
+ // Fetch 500 random documents to determine populated fields.
+ // This is a workaround to avoid passing potentially thousands of unpopulated fields
+ // (for example, as part of filebeat/metricbeat/ECS based indices)
+ // to the data grid component which would significantly slow down the page.
+ const fetchDataGridSampleDocuments = async function () {
+ setErrorMessage('');
+ setStatus(INDEX_STATUS.LOADING);
+
+ const esSearchRequest = {
+ index: indexPattern.title,
+ body: {
+ fields: ['*'],
+ _source: false,
+ query: {
+ function_score: {
+ query: { match_all: {} },
+ random_score: {},
+ },
+ },
+ size: 500,
+ },
+ };
+
+ try {
+ const resp: IndexSearchResponse = await ml.esSearch(esSearchRequest);
+ const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {}));
+
+ // Get all field names for each returned doc and flatten it
+ // to a list of unique field names used across all docs.
+ const allKibanaIndexPatternFields = getFieldsFromKibanaIndexPattern(indexPattern);
+ const populatedFields = [...new Set(docs.map(Object.keys).flat(1))].filter((d) =>
+ allKibanaIndexPatternFields.includes(d)
+ );
+
+ setStatus(INDEX_STATUS.LOADED);
+ setIndexPatternFields(populatedFields);
+ } catch (e) {
+ setErrorMessage(extractErrorMessage(e));
+ setStatus(INDEX_STATUS.ERROR);
+ }
+ };
+
+ useEffect(() => {
+ fetchDataGridSampleDocuments();
+ }, []);
+
+ const [columns, setColumns] = useState(
+ getInitialColumns(indexPattern, indexPatternFields ?? [])
+ );
const dataGrid = useDataGrid(columns);
const {
@@ -151,7 +200,7 @@ export const useIndexData = (
...(combinedRuntimeMappings ? getRuntimeFieldColumns(combinedRuntimeMappings) : []),
]);
} else {
- setColumns(getInitialColumns(indexPattern));
+ setColumns(getInitialColumns(indexPattern, indexPatternFields ?? []));
}
setRowCount(typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total.value);
setRowCountRelation(
diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts
index f97693b8c038a..fe56537450c2b 100644
--- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts
+++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { useEffect, useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import type { estypes } from '@elastic/elasticsearch';
import type { EuiDataGridColumn } from '@elastic/eui';
@@ -46,9 +46,66 @@ export const useIndexData = (
},
} = useAppDependencies();
- const indexPatternFields = getFieldsFromKibanaIndexPattern(indexPattern);
+ const [indexPatternFields, setIndexPatternFields] = useState();
+
+ // Fetch 500 random documents to determine populated fields.
+ // This is a workaround to avoid passing potentially thousands of unpopulated fields
+ // (for example, as part of filebeat/metricbeat/ECS based indices)
+ // to the data grid component which would significantly slow down the page.
+ const fetchDataGridSampleDocuments = async function () {
+ setErrorMessage('');
+ setStatus(INDEX_STATUS.LOADING);
+
+ const esSearchRequest = {
+ index: indexPattern.title,
+ body: {
+ fields: ['*'],
+ _source: false,
+ query: {
+ function_score: {
+ query: { match_all: {} },
+ random_score: {},
+ },
+ },
+ size: 500,
+ },
+ };
+
+ const resp = await api.esSearch(esSearchRequest);
+
+ if (!isEsSearchResponse(resp)) {
+ setErrorMessage(getErrorMessage(resp));
+ setStatus(INDEX_STATUS.ERROR);
+ return;
+ }
+
+ const isCrossClusterSearch = indexPattern.title.includes(':');
+ const isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined');
+
+ const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {}));
+
+ // Get all field names for each returned doc and flatten it
+ // to a list of unique field names used across all docs.
+ const allKibanaIndexPatternFields = getFieldsFromKibanaIndexPattern(indexPattern);
+ const populatedFields = [...new Set(docs.map(Object.keys).flat(1))].filter((d) =>
+ allKibanaIndexPatternFields.includes(d)
+ );
+
+ setCcsWarning(isCrossClusterSearch && isMissingFields);
+ setStatus(INDEX_STATUS.LOADED);
+ setIndexPatternFields(populatedFields);
+ };
+
+ useEffect(() => {
+ fetchDataGridSampleDocuments();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
const columns: EuiDataGridColumn[] = useMemo(() => {
+ if (typeof indexPatternFields === 'undefined') {
+ return [];
+ }
+
let result: Array<{ id: string; schema: string | undefined }> = [];
// Get the the runtime fields that are defined from API field and index patterns
diff --git a/x-pack/plugins/transform/public/app/hooks/use_pivot_data.ts b/x-pack/plugins/transform/public/app/hooks/use_pivot_data.ts
index 24c28effd12bc..9a49ed9480359 100644
--- a/x-pack/plugins/transform/public/app/hooks/use_pivot_data.ts
+++ b/x-pack/plugins/transform/public/app/hooks/use_pivot_data.ts
@@ -11,12 +11,12 @@ import { useEffect, useMemo, useState } from 'react';
import { EuiDataGridColumn } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { getFlattenedObject } from '@kbn/std';
import { ES_FIELD_TYPES } from '../../../../../../src/plugins/data/common';
import type { PreviewMappingsProperties } from '../../../common/api_schemas/transforms';
import { isPostTransformsPreviewResponseSchema } from '../../../common/api_schemas/type_guards';
-import { getNestedProperty } from '../../../common/utils/object_utils';
import {
RenderCellValue,
@@ -159,13 +159,36 @@ export const usePivotData = (
return;
}
- setTableItems(resp.preview);
- setRowCount(resp.preview.length);
+ // To improve UI performance with a latest configuration for indices with a large number
+ // of fields, we reduce the number of available columns to those populated with values.
+
+ // 1. Flatten the returned object structure object documents to match mapping properties
+ const docs = resp.preview.map(getFlattenedObject);
+
+ // 2. Get all field names for each returned doc and flatten it
+ // to a list of unique field names used across all docs.
+ const populatedFields = [...new Set(docs.map(Object.keys).flat(1))];
+
+ // 3. Filter mapping properties by populated fields
+ const populatedProperties: PreviewMappingsProperties = Object.entries(
+ resp.generated_dest_index.mappings.properties
+ )
+ .filter(([key]) => populatedFields.includes(key))
+ .reduce(
+ (p, [key, value]) => ({
+ ...p,
+ [key]: value,
+ }),
+ {}
+ );
+
+ setTableItems(docs);
+ setRowCount(docs.length);
setRowCountRelation(ES_CLIENT_TOTAL_HITS_RELATION.EQ);
- setPreviewMappingsProperties(resp.generated_dest_index.mappings.properties);
+ setPreviewMappingsProperties(populatedProperties);
setStatus(INDEX_STATUS.LOADED);
- if (resp.preview.length === 0) {
+ if (docs.length === 0) {
setNoDataMessage(
i18n.translate('xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', {
defaultMessage:
@@ -201,7 +224,7 @@ export const usePivotData = (
const adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize;
const cellValue = pageData.hasOwnProperty(adjustedRowIndex)
- ? getNestedProperty(pageData[adjustedRowIndex], columnId, null)
+ ? pageData[adjustedRowIndex][columnId] ?? null
: null;
if (typeof cellValue === 'object' && cellValue !== null) {
diff --git a/x-pack/test/functional/apps/transform/creation_index_pattern.ts b/x-pack/test/functional/apps/transform/creation_index_pattern.ts
index 61579ac68ae53..2c26a340a2a26 100644
--- a/x-pack/test/functional/apps/transform/creation_index_pattern.ts
+++ b/x-pack/test/functional/apps/transform/creation_index_pattern.ts
@@ -166,11 +166,6 @@ export default function ({ getService }: FtrProviderContext) {
{ color: '#54B399', percentage: 90 },
],
},
- {
- chartAvailable: false,
- id: 'customer_birth_date',
- legend: '0 documents contain field.',
- },
{ chartAvailable: false, id: 'customer_first_name', legend: 'Chart not supported.' },
{ chartAvailable: false, id: 'customer_full_name', legend: 'Chart not supported.' },
{
@@ -210,6 +205,15 @@ export default function ({ getService }: FtrProviderContext) {
{ color: '#54B399', percentage: 75 },
],
},
+ {
+ chartAvailable: true,
+ id: 'day_of_week_i',
+ legend: '0 - 6',
+ colorStats: [
+ { color: '#000000', percentage: 20 },
+ { color: '#54B399', percentage: 75 },
+ ],
+ },
],
discoverQueryHits: '7,270',
},
@@ -296,7 +300,6 @@ export default function ({ getService }: FtrProviderContext) {
columns: 10,
rows: 5,
},
- histogramCharts: [],
discoverQueryHits: '10',
},
} as PivotTransformTestData,
@@ -336,7 +339,6 @@ export default function ({ getService }: FtrProviderContext) {
columns: 10,
rows: 5,
},
- histogramCharts: [],
transformPreview: {
column: 0,
values: [
@@ -404,10 +406,14 @@ export default function ({ getService }: FtrProviderContext) {
await transform.testExecution.logTestStep('enables the index preview histogram charts');
await transform.wizard.enableIndexPreviewHistogramCharts(true);
- await transform.testExecution.logTestStep('displays the index preview histogram charts');
- await transform.wizard.assertIndexPreviewHistogramCharts(
- testData.expected.histogramCharts
- );
+ if (Array.isArray(testData.expected.histogramCharts)) {
+ await transform.testExecution.logTestStep(
+ 'displays the index preview histogram charts'
+ );
+ await transform.wizard.assertIndexPreviewHistogramCharts(
+ testData.expected.histogramCharts
+ );
+ }
if (isPivotTransformTestData(testData)) {
await transform.testExecution.logTestStep('adds the group by entries');
diff --git a/x-pack/test/functional/apps/transform/creation_runtime_mappings.ts b/x-pack/test/functional/apps/transform/creation_runtime_mappings.ts
index 1ecbdd41c219d..030748026af91 100644
--- a/x-pack/test/functional/apps/transform/creation_runtime_mappings.ts
+++ b/x-pack/test/functional/apps/transform/creation_runtime_mappings.ts
@@ -46,14 +46,37 @@ export default function ({ getService }: FtrProviderContext) {
await transform.api.cleanTransformIndices();
});
- // Only testing that histogram charts are available for runtime fields here
const histogramCharts: HistogramCharts = [
+ {
+ // Skipping colorStats assertion for this chart,
+ // results can be quite different on each run because of sampling.
+ chartAvailable: true,
+ id: '@timestamp',
+ },
+ { chartAvailable: false, id: '@version', legend: 'Chart not supported.' },
+ {
+ chartAvailable: true,
+ id: 'airline',
+ legend: '19 categories',
+ colorStats: [
+ { color: '#000000', percentage: 49 },
+ { color: '#54B399', percentage: 41 },
+ ],
+ },
+ {
+ chartAvailable: true,
+ id: 'responsetime',
+ colorStats: [
+ { color: '#54B399', percentage: 5 },
+ { color: '#000000', percentage: 95 },
+ ],
+ },
{
chartAvailable: true,
id: 'rt_airline_lower',
legend: '19 categories',
colorStats: [
- { color: '#000000', percentage: 48 },
+ { color: '#000000', percentage: 49 },
{ color: '#54B399', percentage: 41 },
],
},
@@ -65,6 +88,7 @@ export default function ({ getService }: FtrProviderContext) {
{ color: '#000000', percentage: 95 },
],
},
+ { chartAvailable: false, id: 'type', legend: 'Chart not supported.' },
];
const testDataList: Array = [
diff --git a/x-pack/test/functional/services/transform/wizard.ts b/x-pack/test/functional/services/transform/wizard.ts
index f82af4f3a6d37..cef6c2724033e 100644
--- a/x-pack/test/functional/services/transform/wizard.ts
+++ b/x-pack/test/functional/services/transform/wizard.ts
@@ -237,6 +237,15 @@ export function TransformWizardProvider({ getService, getPageObjects }: FtrProvi
// For each chart, get the content of each header cell and assert
// the legend text and column id and if the chart should be present or not.
await retry.tryForTime(5000, async () => {
+ const table = await testSubjects.find(`~transformIndexPreview`);
+ const $ = await table.parseDomContent();
+ const actualColumnLength = $('.euiDataGridHeaderCell__content').toArray().length;
+
+ expect(actualColumnLength).to.eql(
+ expectedHistogramCharts.length,
+ `Number of index preview column charts should be '${expectedHistogramCharts.length}' (got '${actualColumnLength}')`
+ );
+
for (const expected of expectedHistogramCharts.values()) {
const id = expected.id;
await testSubjects.existOrFail(`mlDataGridChart-${id}`);
From c408e3ae09e2959a05f3ee5d6a9e9c08d7d34365 Mon Sep 17 00:00:00 2001
From: Pierre Gayvallet
Date: Wed, 28 Apr 2021 09:56:24 +0200
Subject: [PATCH 22/28] SO MigV2: fix logStateTransition (#98445)
* SO MigV2: fix logStateTransition
* extract func
* use info directly
* improve tests & impl
---
.../migrations_state_action_machine.test.ts | 36 +++++++++++++++++--
.../migrations_state_action_machine.ts | 17 ++++-----
.../saved_objects/migrationsv2/types.ts | 9 ++++-
3 files changed, 51 insertions(+), 11 deletions(-)
diff --git a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts
index 161d4a7219c8d..bffe590a39432 100644
--- a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts
+++ b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.test.ts
@@ -10,10 +10,11 @@ import { migrationStateActionMachine } from './migrations_state_action_machine';
import { loggingSystemMock, elasticsearchServiceMock } from '../../mocks';
import * as Either from 'fp-ts/lib/Either';
import * as Option from 'fp-ts/lib/Option';
-import { AllControlStates, State } from './types';
-import { createInitialState } from './model';
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
import { elasticsearchClientMock } from '../../elasticsearch/client/mocks';
+import { LoggerAdapter } from '../../logging/logger_adapter';
+import { AllControlStates, State } from './types';
+import { createInitialState } from './model';
const esClient = elasticsearchServiceMock.createElasticsearchClient();
describe('migrationsStateActionMachine', () => {
@@ -146,6 +147,37 @@ describe('migrationsStateActionMachine', () => {
}
`);
});
+
+ // see https://github.com/elastic/kibana/issues/98406
+ it('correctly logs state transition when using a logger adapter', async () => {
+ const underlyingLogger = mockLogger.get();
+ const logger = new LoggerAdapter(underlyingLogger);
+
+ await expect(
+ migrationStateActionMachine({
+ initialState,
+ logger,
+ model: transitionModel(['LEGACY_REINDEX', 'LEGACY_DELETE', 'LEGACY_DELETE', 'DONE']),
+ next,
+ client: esClient,
+ })
+ ).resolves.toEqual(expect.anything());
+
+ const allLogs = loggingSystemMock.collect(mockLogger);
+ const stateTransitionLogs = allLogs.info
+ .map((call) => call[0])
+ .filter((log) => log.match('control state'));
+
+ expect(stateTransitionLogs).toMatchInlineSnapshot(`
+ Array [
+ "[.my-so-index] Log from LEGACY_REINDEX control state",
+ "[.my-so-index] Log from LEGACY_DELETE control state",
+ "[.my-so-index] Log from LEGACY_DELETE control state",
+ "[.my-so-index] Log from DONE control state",
+ ]
+ `);
+ });
+
it('resolves when reaching the DONE state', async () => {
await expect(
migrationStateActionMachine({
diff --git a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts
index dede52f9758e9..85cc86fe0a468 100644
--- a/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts
+++ b/src/core/server/saved_objects/migrationsv2/migrations_state_action_machine.ts
@@ -49,14 +49,15 @@ const logStateTransition = (
tookMs: number
) => {
if (newState.logs.length > oldState.logs.length) {
- newState.logs.slice(oldState.logs.length).forEach((log) => {
- const getLogger = (level: keyof Logger) => {
- if (level === 'error') {
- return logger[level] as Logger['error'];
- }
- return logger[level] as Logger['info'];
- };
- getLogger(log.level)(logMessagePrefix + log.message);
+ newState.logs.slice(oldState.logs.length).forEach(({ message, level }) => {
+ switch (level) {
+ case 'error':
+ return logger.error(logMessagePrefix + message);
+ case 'info':
+ return logger.info(logMessagePrefix + message);
+ default:
+ throw new Error(`unexpected log level ${level}`);
+ }
});
}
diff --git a/src/core/server/saved_objects/migrationsv2/types.ts b/src/core/server/saved_objects/migrationsv2/types.ts
index b84d483cf6203..50664bc9398fb 100644
--- a/src/core/server/saved_objects/migrationsv2/types.ts
+++ b/src/core/server/saved_objects/migrationsv2/types.ts
@@ -13,6 +13,13 @@ import { AliasAction } from './actions';
import { IndexMapping } from '../mappings';
import { SavedObjectsRawDoc } from '..';
+export type MigrationLogLevel = 'error' | 'info';
+
+export interface MigrationLog {
+ level: MigrationLogLevel;
+ message: string;
+}
+
export interface BaseState extends ControlState {
/** The first part of the index name such as `.kibana` or `.kibana_task_manager` */
readonly indexPrefix: string;
@@ -70,7 +77,7 @@ export interface BaseState extends ControlState {
* In this case, you should set a smaller batchSize value and restart the migration process again.
*/
readonly batchSize: number;
- readonly logs: Array<{ level: 'error' | 'info'; message: string }>;
+ readonly logs: MigrationLog[];
/**
* The current alias e.g. `.kibana` which always points to the latest
* version index
From 10a93366e0ab00e6f5bdc3057830cfa97462294c Mon Sep 17 00:00:00 2001
From: Pierre Gayvallet
Date: Wed, 28 Apr 2021 10:03:02 +0200
Subject: [PATCH 23/28] change config reload message (#98455)
* change config reload message
* change function name
---
src/core/server/bootstrap.ts | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts
index a2267635e86f2..18a5eceb1b2d3 100644
--- a/src/core/server/bootstrap.ts
+++ b/src/core/server/bootstrap.ts
@@ -46,22 +46,22 @@ export async function bootstrap({ configs, cliArgs, applyConfigOverrides }: Boot
const root = new Root(rawConfigService, env, onRootShutdown);
- process.on('SIGHUP', () => reloadLoggingConfig());
+ process.on('SIGHUP', () => reloadConfiguration());
// This is only used by the LogRotator service
// in order to be able to reload the log configuration
// under the cluster mode
process.on('message', (msg) => {
- if (!msg || msg.reloadLoggingConfig !== true) {
+ if (!msg || msg.reloadConfiguration !== true) {
return;
}
- reloadLoggingConfig();
+ reloadConfiguration();
});
- function reloadLoggingConfig() {
+ function reloadConfiguration() {
const cliLogger = root.logger.get('cli');
- cliLogger.info('Reloading logging configuration due to SIGHUP.', { tags: ['config'] });
+ cliLogger.info('Reloading Kibana configuration due to SIGHUP.', { tags: ['config'] });
try {
rawConfigService.reloadConfig();
@@ -69,7 +69,7 @@ export async function bootstrap({ configs, cliArgs, applyConfigOverrides }: Boot
return shutdown(err);
}
- cliLogger.info('Reloaded logging configuration due to SIGHUP.', { tags: ['config'] });
+ cliLogger.info('Reloaded Kibana configuration due to SIGHUP.', { tags: ['config'] });
}
process.on('SIGINT', () => shutdown());
From 0cf12567840665ef555818ddf556766788440323 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Wed, 28 Apr 2021 10:12:29 +0200
Subject: [PATCH 24/28] always load test fixtures (#98464)
---
x-pack/test/functional/apps/lens/index.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts
index 38ba1f698ecce..bfb0aad7177f4 100644
--- a/x-pack/test/functional/apps/lens/index.ts
+++ b/x-pack/test/functional/apps/lens/index.ts
@@ -16,8 +16,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
before(async () => {
log.debug('Starting lens before method');
await browser.setWindowSize(1280, 800);
- await esArchiver.loadIfNeeded('logstash_functional');
- await esArchiver.loadIfNeeded('lens/basic');
+ await esArchiver.load('logstash_functional');
+ await esArchiver.load('lens/basic');
});
after(async () => {
From 3cc6989e5fffc8c458b09ed30fec95b5781d96fe Mon Sep 17 00:00:00 2001
From: Stratoula Kalafateli
Date: Wed, 28 Apr 2021 13:59:19 +0300
Subject: [PATCH 25/28] [Visualize] Fixes V8 theme issues (#97090)
* [Visualize] Fixes K8 theme issues
* Fix ci
* Make it work for v7 too
* Fix
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../vis_default_editor/public/components/agg_add.tsx | 4 ++--
.../wizard/agg_based_selection/agg_based_selection.scss | 3 +++
.../wizard/agg_based_selection/agg_based_selection.tsx | 2 ++
.../public/application/components/visualize_listing.scss | 7 ++++++-
4 files changed, 13 insertions(+), 3 deletions(-)
create mode 100644 src/plugins/visualizations/public/wizard/agg_based_selection/agg_based_selection.scss
diff --git a/src/plugins/vis_default_editor/public/components/agg_add.tsx b/src/plugins/vis_default_editor/public/components/agg_add.tsx
index 37ef08ec640f0..bbe235082e13e 100644
--- a/src/plugins/vis_default_editor/public/components/agg_add.tsx
+++ b/src/plugins/vis_default_editor/public/components/agg_add.tsx
@@ -52,7 +52,7 @@ function DefaultEditorAggAdd({
const addButton = (
setIsPopoverOpen(!isPopoverOpen)}
@@ -88,7 +88,7 @@ function DefaultEditorAggAdd({
repositionOnScroll={true}
closePopover={() => setIsPopoverOpen(false)}
>
-
+
{(groupName !== AggGroupNames.Buckets || !stats.count) && (
}
+ className="aggBasedDialog__card"
/>
);
diff --git a/src/plugins/visualize/public/application/components/visualize_listing.scss b/src/plugins/visualize/public/application/components/visualize_listing.scss
index c3b0df67e317d..840ebf89c129f 100644
--- a/src/plugins/visualize/public/application/components/visualize_listing.scss
+++ b/src/plugins/visualize/public/application/components/visualize_listing.scss
@@ -21,7 +21,12 @@
}
.visListingCallout {
- max-width: 1000px;
+ @include kbnThemeStyle('v7') {
+ max-width: 1000px;
+ }
+ @include kbnThemeStyle('v8') {
+ max-width: 1200px;
+ }
width: 100%;
margin-left: auto;
From 66a1aff924295502b24cfb244944a0d97a2125aa Mon Sep 17 00:00:00 2001
From: Jorge Sanz
Date: Wed, 28 Apr 2021 14:02:35 +0200
Subject: [PATCH 26/28] [Maps] Updated documentation for Elastic Maps Server
7.13 (#98310)
Co-authored-by: Nick Peihl
Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
---
docs/maps/connect-to-ems.asciidoc | 17 +++++++++++------
.../images/elastic-maps-server-basemaps.png | Bin 0 -> 42518 bytes
.../elastic-maps-server-instructions.png | Bin 104953 -> 48671 bytes
3 files changed, 11 insertions(+), 6 deletions(-)
create mode 100644 docs/maps/images/elastic-maps-server-basemaps.png
diff --git a/docs/maps/connect-to-ems.asciidoc b/docs/maps/connect-to-ems.asciidoc
index 8e4695bfc6662..88301123bae3f 100644
--- a/docs/maps/connect-to-ems.asciidoc
+++ b/docs/maps/connect-to-ems.asciidoc
@@ -40,11 +40,9 @@ To disable EMS, change your <> file.
[id=elastic-maps-server]
=== Host Elastic Maps Service locally
-beta::[]
-
If you cannot connect to Elastic Maps Service from the {kib} server or browser clients, and your cluster has the appropriate license level, you can opt to host the service on your own infrastructure.
-{hosted-ems} is a self-managed version of Elastic Maps Service offered as a Docker image that provides both the EMS basemaps and EMS boundaries. You must first download and run the image. After connecting it to your {es} cluster for license validation, you're guided to download and configure the basemaps database, which must be retrieved separately.
+{hosted-ems} is a self-managed version of Elastic Maps Service offered as a Docker image that provides both the EMS basemaps and EMS boundaries. The image is bundled with basemaps up to zoom level 8. After connecting it to your {es} cluster for license validation, you have the option to download and configure a more detailed basemaps database.
IMPORTANT: {hosted-ems} does not serve raster tiles, needed by Vega, coordinate, and region map visualizations.
@@ -69,7 +67,7 @@ docker run --rm --init --publish 8080:8080 \
{ems-docker-image}
----------------------------------
-Once {hosted-ems} is running, follow instructions from the webpage at `localhost:8080` to define a configuration file and download the basemaps database.
+Once {hosted-ems} is running, follow instructions from the webpage at `localhost:8080` to define a configuration file and optionally download a more detailed basemaps database.
[role="screenshot"]
image::images/elastic-maps-server-instructions.png[Set-up instructions]
@@ -92,6 +90,9 @@ endif::[]
| `port`
| Specifies the port used by the backend server. Default: *`8080`*. <>.
+| `basePath`
+ | Specify a path at which to mount the server if you are running behind a proxy. This setting cannot end in a slash (`/`). <>.
+
| `ui`
| Controls the display of the status page and the layer preview. *Default: `true`*
@@ -190,9 +191,13 @@ services:
[[elastic-maps-server-data]]
==== Data
-{hosted-ems} hosts vector layer boundaries and vector tile basemaps for the entire planet. Boundaries include world countries, global administrative regions, and specific country regions. A minimal basemap is provided with {hosted-ems}. This can be used for testing environments but won't be functional for normal operations. The full basemap (around 90GB file) needs to be mounted on the Docker container for {hosted-ems} to run normally.
+{hosted-ems} hosts vector layer boundaries and vector tile basemaps for the entire planet. Boundaries include world countries, global administrative regions, and specific country regions. Basemaps up to zoom level 8 are bundled in the Docker image. These basemaps are sufficient for maps and dashboards at the country level. To present maps with higher detail, follow the instructions of the front page to download and configure the appropriate basemaps database. The most detailed basemaps at zoom level 14 are good for street level maps, but require ~90GB of disk space.
+
+
+[role="screenshot"]
+image::images/elastic-maps-server-basemaps.png[Basemaps download options]
-TIP: The available basemaps and boundaries can be explored from the `/maps` endpoint in a web page that is your self-managed equivalent to https://maps.elastic.co
+TIP: The available basemaps and boundaries can be explored from the `/maps` endpoint in a web page that is your self-managed equivalent to https://maps.elastic.co.
[float]
diff --git a/docs/maps/images/elastic-maps-server-basemaps.png b/docs/maps/images/elastic-maps-server-basemaps.png
new file mode 100644
index 0000000000000000000000000000000000000000..3f51153d2394b9a93e42ea6cda419b0ef8342ae4
GIT binary patch
literal 42518
zcmYg$18`@*_x7i@Z5vzLwvDavsokw@+qP}n*4EsbTX&0pzrUGx=AF68+~g)F&&`>W
zJSRC3N(zz)u(+@Q002Q+N=yX+0LlMO=Fp(uHN}6{%K!k1YELyS7ZoFSVh1OCbD)hG
zv5SX;8L`uSr*unJzQKU@=wq+xR|*sM6=%>e=4n@Z;a-d0pPt*fT=eulG|A
zgznHWs1m`S`X?U`b67vu91aivl?n*nJ$e+LK-Hl^>aX7qc?wGHJjXrjd*_y4jUjcc
z{Pis#68w2`-_M(TLiEL@QsfCA=$G|uKP-~0aUe4Ak3g^f`Q{BdCeA>O&
znjV=>rscTZdUYQ2H918`*>zmUZa%wqP9PWU=5pWdC{oJYs2`WV;;<apqUj4N1oJ>hORJ!5HIHc=)xAlGA-+kvevFy!JWy