diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_manager.test.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_manager.test.tsx
index 2f38f68b01f16d..d7cbcf59213be8 100644
--- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_manager.test.tsx
+++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_manager.test.tsx
@@ -33,6 +33,7 @@ describe('field_manager', () => {
selected: true,
type: 'string',
hopSize: 5,
+ aggregatable: true,
},
{
name: 'field2',
@@ -42,6 +43,7 @@ describe('field_manager', () => {
type: 'string',
hopSize: 0,
lastValidHopSize: 5,
+ aggregatable: false,
},
{
name: 'field3',
@@ -50,6 +52,16 @@ describe('field_manager', () => {
selected: false,
type: 'string',
hopSize: 5,
+ aggregatable: true,
+ },
+ {
+ name: 'field4',
+ color: 'orange',
+ icon: getSuitableIcon('field4'),
+ selected: false,
+ type: 'string',
+ hopSize: 5,
+ aggregatable: false,
},
])
);
@@ -86,6 +98,17 @@ describe('field_manager', () => {
).toEqual('field2');
});
+ it('should show selected non-aggregatable fields in picker, but hide unselected ones', () => {
+ expect(
+ getInstance()
+ .find(FieldPicker)
+ .dive()
+ .find(EuiSelectable)
+ .prop('options')
+ .map((option: { label: string }) => option.label)
+ ).toEqual(['field1', 'field2', 'field3']);
+ });
+
it('should select fields from picker', () => {
expect(
getInstance()
@@ -130,6 +153,25 @@ describe('field_manager', () => {
expect(getInstance().find(FieldEditor).length).toEqual(1);
});
+ it('should show remove non-aggregatable fields from picker after deselection', () => {
+ act(() => {
+ getInstance()
+ .find(FieldEditor)
+ .at(1)
+ .dive()
+ .find(EuiContextMenu)
+ .prop('panels')![0].items![2].onClick!({} as any);
+ });
+ expect(
+ getInstance()
+ .find(FieldPicker)
+ .dive()
+ .find(EuiSelectable)
+ .prop('options')
+ .map((option: { label: string }) => option.label)
+ ).toEqual(['field1', 'field3']);
+ });
+
it('should disable field', () => {
const toggleItem = getInstance()
.find(FieldEditor)
diff --git a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx
index 6ad792defb6697..b38e3f8430980e 100644
--- a/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx
+++ b/x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx
@@ -114,9 +114,26 @@ export function FieldPicker({
function toOptions(
fields: WorkspaceField[]
): Array<{ label: string; checked?: 'on' | 'off'; prepend?: ReactNode }> {
- return fields.map(field => ({
- label: field.name,
- prepend: ,
- checked: field.selected ? 'on' : undefined,
- }));
+ return (
+ fields
+ // don't show non-aggregatable fields, except for the case when they are already selected.
+ // this is necessary to ensure backwards compatibility with existing workspaces that might
+ // contain non-aggregatable fields.
+ .filter(field => isExplorable(field) || field.selected)
+ .map(field => ({
+ label: field.name,
+ prepend: ,
+ checked: field.selected ? 'on' : undefined,
+ }))
+ );
+}
+
+const explorableTypes = ['string', 'number', 'date', 'ip', 'boolean'];
+
+function isExplorable(field: WorkspaceField) {
+ if (!field.aggregatable) {
+ return false;
+ }
+
+ return explorableTypes.includes(field.type);
}
diff --git a/x-pack/legacy/plugins/graph/public/components/settings/settings.test.tsx b/x-pack/legacy/plugins/graph/public/components/settings/settings.test.tsx
index a615901f40e253..0109e1f5a5ac7b 100644
--- a/x-pack/legacy/plugins/graph/public/components/settings/settings.test.tsx
+++ b/x-pack/legacy/plugins/graph/public/components/settings/settings.test.tsx
@@ -112,6 +112,7 @@ describe('settings', () => {
code: '1',
label: 'test',
},
+ aggregatable: true,
},
{
selected: false,
@@ -123,6 +124,7 @@ describe('settings', () => {
code: '1',
label: 'test',
},
+ aggregatable: true,
},
])
);
diff --git a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts
index 3bfc868fcb06e9..79ff4debc7e825 100644
--- a/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts
+++ b/x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts
@@ -13,8 +13,24 @@ describe('fetch_top_nodes', () => {
it('should build terms agg', async () => {
const postMock = jest.fn(() => Promise.resolve({ resp: {} }));
await fetchTopNodes(postMock as any, 'test', [
- { color: '', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' },
- { color: '', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' },
+ {
+ color: '',
+ hopSize: 5,
+ icon,
+ name: 'field1',
+ selected: false,
+ type: 'string',
+ aggregatable: true,
+ },
+ {
+ color: '',
+ hopSize: 5,
+ icon,
+ name: 'field2',
+ selected: false,
+ type: 'string',
+ aggregatable: true,
+ },
]);
expect(postMock).toHaveBeenCalledWith('../api/graph/searchProxy', {
body: JSON.stringify({
@@ -65,8 +81,24 @@ describe('fetch_top_nodes', () => {
})
);
const result = await fetchTopNodes(postMock as any, 'test', [
- { color: 'red', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' },
- { color: 'blue', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' },
+ {
+ color: 'red',
+ hopSize: 5,
+ icon,
+ name: 'field1',
+ selected: false,
+ type: 'string',
+ aggregatable: true,
+ },
+ {
+ color: 'blue',
+ hopSize: 5,
+ icon,
+ name: 'field2',
+ selected: false,
+ type: 'string',
+ aggregatable: true,
+ },
]);
expect(result.length).toEqual(4);
expect(result[0]).toEqual({
diff --git a/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.test.ts b/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.test.ts
index d38c950a5986f2..1861479f85f189 100644
--- a/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.test.ts
+++ b/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.test.ts
@@ -119,9 +119,9 @@ describe('deserialize', () => {
savedWorkspace,
{
getNonScriptedFields: () => [
- { name: 'field1', type: 'string' },
- { name: 'field2', type: 'string' },
- { name: 'field3', type: 'string' },
+ { name: 'field1', type: 'string', aggregatable: true },
+ { name: 'field2', type: 'string', aggregatable: true },
+ { name: 'field3', type: 'string', aggregatable: true },
],
} as IndexPattern,
workspace
@@ -140,6 +140,7 @@ describe('deserialize', () => {
expect(allFields).toMatchInlineSnapshot(`
Array [
Object {
+ "aggregatable": true,
"color": "black",
"hopSize": undefined,
"icon": undefined,
@@ -149,6 +150,7 @@ describe('deserialize', () => {
"type": "string",
},
Object {
+ "aggregatable": true,
"color": "black",
"hopSize": undefined,
"icon": undefined,
@@ -158,6 +160,7 @@ describe('deserialize', () => {
"type": "string",
},
Object {
+ "aggregatable": true,
"color": "#CE0060",
"hopSize": 5,
"icon": Object {
diff --git a/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.ts b/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.ts
index af34b4f1a725b4..43425077cc174d 100644
--- a/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.ts
+++ b/x-pack/legacy/plugins/graph/public/services/persistence/deserialize.ts
@@ -89,6 +89,7 @@ export function mapFields(indexPattern: IndexPattern): WorkspaceField[] {
color: colorChoices[index % colorChoices.length],
selected: false,
type: field.type,
+ aggregatable: Boolean(field.aggregatable),
}))
.sort((a, b) => {
if (a.name < b.name) {
diff --git a/x-pack/legacy/plugins/graph/public/services/persistence/serialize.test.ts b/x-pack/legacy/plugins/graph/public/services/persistence/serialize.test.ts
index 0e0c750383a71e..a3942eccfdac36 100644
--- a/x-pack/legacy/plugins/graph/public/services/persistence/serialize.test.ts
+++ b/x-pack/legacy/plugins/graph/public/services/persistence/serialize.test.ts
@@ -41,6 +41,7 @@ describe('serialize', () => {
name: 'field1',
selected: true,
type: 'string',
+ aggregatable: true,
},
{
color: 'black',
@@ -48,6 +49,7 @@ describe('serialize', () => {
name: 'field2',
selected: true,
type: 'string',
+ aggregatable: true,
},
],
selectedIndex: {
diff --git a/x-pack/legacy/plugins/graph/public/types/app_state.ts b/x-pack/legacy/plugins/graph/public/types/app_state.ts
index eef8060f07f5cd..876f2cf23b53a9 100644
--- a/x-pack/legacy/plugins/graph/public/types/app_state.ts
+++ b/x-pack/legacy/plugins/graph/public/types/app_state.ts
@@ -25,6 +25,7 @@ export interface WorkspaceField {
icon: FontawesomeIcon;
selected: boolean;
type: string;
+ aggregatable: boolean;
}
export interface AdvancedSettings {
diff --git a/x-pack/legacy/plugins/graph/public/types/persistence.ts b/x-pack/legacy/plugins/graph/public/types/persistence.ts
index 7fc5e15d9ea72b..adb07605b61c46 100644
--- a/x-pack/legacy/plugins/graph/public/types/persistence.ts
+++ b/x-pack/legacy/plugins/graph/public/types/persistence.ts
@@ -37,7 +37,7 @@ export interface SerializedUrlTemplate extends Omit {
+export interface SerializedField extends Omit {
iconClass: string;
}