Skip to content

Commit 51e07f2

Browse files
authored
[Graph] Only show explorable fields (#54101)
1 parent 07278ab commit 51e07f2

File tree

9 files changed

+113
-13
lines changed

9 files changed

+113
-13
lines changed

x-pack/legacy/plugins/graph/public/components/field_manager/field_manager.test.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('field_manager', () => {
3333
selected: true,
3434
type: 'string',
3535
hopSize: 5,
36+
aggregatable: true,
3637
},
3738
{
3839
name: 'field2',
@@ -42,6 +43,7 @@ describe('field_manager', () => {
4243
type: 'string',
4344
hopSize: 0,
4445
lastValidHopSize: 5,
46+
aggregatable: false,
4547
},
4648
{
4749
name: 'field3',
@@ -50,6 +52,16 @@ describe('field_manager', () => {
5052
selected: false,
5153
type: 'string',
5254
hopSize: 5,
55+
aggregatable: true,
56+
},
57+
{
58+
name: 'field4',
59+
color: 'orange',
60+
icon: getSuitableIcon('field4'),
61+
selected: false,
62+
type: 'string',
63+
hopSize: 5,
64+
aggregatable: false,
5365
},
5466
])
5567
);
@@ -86,6 +98,17 @@ describe('field_manager', () => {
8698
).toEqual('field2');
8799
});
88100

101+
it('should show selected non-aggregatable fields in picker, but hide unselected ones', () => {
102+
expect(
103+
getInstance()
104+
.find(FieldPicker)
105+
.dive()
106+
.find(EuiSelectable)
107+
.prop('options')
108+
.map((option: { label: string }) => option.label)
109+
).toEqual(['field1', 'field2', 'field3']);
110+
});
111+
89112
it('should select fields from picker', () => {
90113
expect(
91114
getInstance()
@@ -130,6 +153,25 @@ describe('field_manager', () => {
130153
expect(getInstance().find(FieldEditor).length).toEqual(1);
131154
});
132155

156+
it('should show remove non-aggregatable fields from picker after deselection', () => {
157+
act(() => {
158+
getInstance()
159+
.find(FieldEditor)
160+
.at(1)
161+
.dive()
162+
.find(EuiContextMenu)
163+
.prop('panels')![0].items![2].onClick!({} as any);
164+
});
165+
expect(
166+
getInstance()
167+
.find(FieldPicker)
168+
.dive()
169+
.find(EuiSelectable)
170+
.prop('options')
171+
.map((option: { label: string }) => option.label)
172+
).toEqual(['field1', 'field3']);
173+
});
174+
133175
it('should disable field', () => {
134176
const toggleItem = getInstance()
135177
.find(FieldEditor)

x-pack/legacy/plugins/graph/public/components/field_manager/field_picker.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,26 @@ export function FieldPicker({
114114
function toOptions(
115115
fields: WorkspaceField[]
116116
): Array<{ label: string; checked?: 'on' | 'off'; prepend?: ReactNode }> {
117-
return fields.map(field => ({
118-
label: field.name,
119-
prepend: <FieldIcon type={field.type} size="m" useColor />,
120-
checked: field.selected ? 'on' : undefined,
121-
}));
117+
return (
118+
fields
119+
// don't show non-aggregatable fields, except for the case when they are already selected.
120+
// this is necessary to ensure backwards compatibility with existing workspaces that might
121+
// contain non-aggregatable fields.
122+
.filter(field => isExplorable(field) || field.selected)
123+
.map(field => ({
124+
label: field.name,
125+
prepend: <FieldIcon type={field.type} size="m" useColor />,
126+
checked: field.selected ? 'on' : undefined,
127+
}))
128+
);
129+
}
130+
131+
const explorableTypes = ['string', 'number', 'date', 'ip', 'boolean'];
132+
133+
function isExplorable(field: WorkspaceField) {
134+
if (!field.aggregatable) {
135+
return false;
136+
}
137+
138+
return explorableTypes.includes(field.type);
122139
}

x-pack/legacy/plugins/graph/public/components/settings/settings.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ describe('settings', () => {
112112
code: '1',
113113
label: 'test',
114114
},
115+
aggregatable: true,
115116
},
116117
{
117118
selected: false,
@@ -123,6 +124,7 @@ describe('settings', () => {
123124
code: '1',
124125
label: 'test',
125126
},
127+
aggregatable: true,
126128
},
127129
])
128130
);

x-pack/legacy/plugins/graph/public/services/fetch_top_nodes.test.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,24 @@ describe('fetch_top_nodes', () => {
1313
it('should build terms agg', async () => {
1414
const postMock = jest.fn(() => Promise.resolve({ resp: {} }));
1515
await fetchTopNodes(postMock as any, 'test', [
16-
{ color: '', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' },
17-
{ color: '', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' },
16+
{
17+
color: '',
18+
hopSize: 5,
19+
icon,
20+
name: 'field1',
21+
selected: false,
22+
type: 'string',
23+
aggregatable: true,
24+
},
25+
{
26+
color: '',
27+
hopSize: 5,
28+
icon,
29+
name: 'field2',
30+
selected: false,
31+
type: 'string',
32+
aggregatable: true,
33+
},
1834
]);
1935
expect(postMock).toHaveBeenCalledWith('../api/graph/searchProxy', {
2036
body: JSON.stringify({
@@ -65,8 +81,24 @@ describe('fetch_top_nodes', () => {
6581
})
6682
);
6783
const result = await fetchTopNodes(postMock as any, 'test', [
68-
{ color: 'red', hopSize: 5, icon, name: 'field1', selected: false, type: 'string' },
69-
{ color: 'blue', hopSize: 5, icon, name: 'field2', selected: false, type: 'string' },
84+
{
85+
color: 'red',
86+
hopSize: 5,
87+
icon,
88+
name: 'field1',
89+
selected: false,
90+
type: 'string',
91+
aggregatable: true,
92+
},
93+
{
94+
color: 'blue',
95+
hopSize: 5,
96+
icon,
97+
name: 'field2',
98+
selected: false,
99+
type: 'string',
100+
aggregatable: true,
101+
},
70102
]);
71103
expect(result.length).toEqual(4);
72104
expect(result[0]).toEqual({

x-pack/legacy/plugins/graph/public/services/persistence/deserialize.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ describe('deserialize', () => {
119119
savedWorkspace,
120120
{
121121
getNonScriptedFields: () => [
122-
{ name: 'field1', type: 'string' },
123-
{ name: 'field2', type: 'string' },
124-
{ name: 'field3', type: 'string' },
122+
{ name: 'field1', type: 'string', aggregatable: true },
123+
{ name: 'field2', type: 'string', aggregatable: true },
124+
{ name: 'field3', type: 'string', aggregatable: true },
125125
],
126126
} as IndexPattern,
127127
workspace
@@ -140,6 +140,7 @@ describe('deserialize', () => {
140140
expect(allFields).toMatchInlineSnapshot(`
141141
Array [
142142
Object {
143+
"aggregatable": true,
143144
"color": "black",
144145
"hopSize": undefined,
145146
"icon": undefined,
@@ -149,6 +150,7 @@ describe('deserialize', () => {
149150
"type": "string",
150151
},
151152
Object {
153+
"aggregatable": true,
152154
"color": "black",
153155
"hopSize": undefined,
154156
"icon": undefined,
@@ -158,6 +160,7 @@ describe('deserialize', () => {
158160
"type": "string",
159161
},
160162
Object {
163+
"aggregatable": true,
161164
"color": "#CE0060",
162165
"hopSize": 5,
163166
"icon": Object {

x-pack/legacy/plugins/graph/public/services/persistence/deserialize.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export function mapFields(indexPattern: IndexPattern): WorkspaceField[] {
8989
color: colorChoices[index % colorChoices.length],
9090
selected: false,
9191
type: field.type,
92+
aggregatable: Boolean(field.aggregatable),
9293
}))
9394
.sort((a, b) => {
9495
if (a.name < b.name) {

x-pack/legacy/plugins/graph/public/services/persistence/serialize.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ describe('serialize', () => {
4141
name: 'field1',
4242
selected: true,
4343
type: 'string',
44+
aggregatable: true,
4445
},
4546
{
4647
color: 'black',
4748
icon: { class: 'b', code: '', label: '' },
4849
name: 'field2',
4950
selected: true,
5051
type: 'string',
52+
aggregatable: true,
5153
},
5254
],
5355
selectedIndex: {

x-pack/legacy/plugins/graph/public/types/app_state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export interface WorkspaceField {
2525
icon: FontawesomeIcon;
2626
selected: boolean;
2727
type: string;
28+
aggregatable: boolean;
2829
}
2930

3031
export interface AdvancedSettings {

x-pack/legacy/plugins/graph/public/types/persistence.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface SerializedUrlTemplate extends Omit<UrlTemplate, 'encoder' | 'ic
3737
encoderID: string;
3838
iconClass?: string;
3939
}
40-
export interface SerializedField extends Omit<WorkspaceField, 'icon' | 'type'> {
40+
export interface SerializedField extends Omit<WorkspaceField, 'icon' | 'type' | 'aggregatable'> {
4141
iconClass: string;
4242
}
4343

0 commit comments

Comments
 (0)