Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beats/config view #22177

Merged
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
71b162a
[Beats Management] Move to Ingest UI arch and initial TS effort (#20039)
mattapperson Jun 26, 2018
ebffb62
add details page, re-configure routes
mattapperson Aug 8, 2018
85c1e59
move tag crud to new route stuff
mattapperson Aug 8, 2018
e782314
update tag create/edit component api
mattapperson Aug 8, 2018
2151ae3
tags creation now working
mattapperson Aug 8, 2018
7ab3a96
bunch of stuff I should have split up better…
mattapperson Aug 10, 2018
c2d3a4a
fixed perf bug, selected items that are removed are no longer phantom…
mattapperson Aug 13, 2018
8317937
fix rendering of assignments
mattapperson Aug 13, 2018
c1ebd16
remove assign to beats, the UX was too poor
mattapperson Aug 13, 2018
58f4aac
[Beats Management] Move to Ingest UI arch and initial TS effort (#20039)
mattapperson Jun 26, 2018
ce60486
Beats/update (#21702)
mattapperson Aug 8, 2018
b071284
progress on config forms
mattapperson Aug 14, 2018
6298c2f
config view inital input types working
mattapperson Aug 14, 2018
b8c0605
ts fixes
mattapperson Aug 14, 2018
d628018
fix more ts
mattapperson Aug 14, 2018
9373a2c
code now errors on invalid yaml
mattapperson Aug 15, 2018
b533c30
remove un-needed include
mattapperson Aug 15, 2018
40e49e4
fix bad rebase
mattapperson Aug 15, 2018
acbc416
saving config blocks as yaml to db is now working
mattapperson Aug 16, 2018
5219006
propperly formatted YAML
mattapperson Aug 16, 2018
9a11a85
loading tags back on edit screen in-progress
mattapperson Aug 16, 2018
0fd670b
fix types
mattapperson Aug 17, 2018
aac2b30
vis name validation for tag
mattapperson Aug 17, 2018
22c358d
update EUI style
mattapperson Aug 17, 2018
4cd93aa
tweak design
mattapperson Aug 17, 2018
9888cf5
fixed tag assignments (still has a ui glitch)
mattapperson Aug 20, 2018
4e25282
fix form validation on select
mattapperson Aug 20, 2018
00e826a
fix deps
mattapperson Aug 21, 2018
48f3497
update deps
mattapperson Aug 21, 2018
d44f2f4
attached beats now works in the edit tag screen, edit now disables ch…
mattapperson Aug 24, 2018
29a5f07
better un-parsing of yaml, some elements now rendering to edit config…
mattapperson Aug 24, 2018
4679e91
delete config block now works
mattapperson Aug 24, 2018
6a88c35
fix ability to edit config
mattapperson Aug 27, 2018
0103aea
fix deps
mattapperson Aug 27, 2018
d0502fe
fix another rebase issue
mattapperson Aug 27, 2018
57fdb5b
tweaks and fixes
mattapperson Aug 28, 2018
dfa443f
fix several bugs
mattapperson Aug 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
bunch of stuff I should have split up better…
  • Loading branch information
mattapperson committed Aug 27, 2018

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 7ab3a968ba8e537d85c79e52af57fbd1d8c68fa5
Original file line number Diff line number Diff line change
@@ -12,21 +12,21 @@ import {
import React from 'react';
import styled from 'styled-components';
import { TABLE_CONFIG } from '../../../common/constants';
import { CMPopulatedBeat } from '../../../common/domain_types';
import { ControlBar } from './controls';
import { TableType } from './table_type_configs';

interface BeatsTableProps {
assignmentOptions: any[] | null;
assignmentTitle: string | null;
renderAssignmentOptions?: (item: any) => any;
items: any[];
showAssignmentOptions: boolean;
type: TableType;
actionHandler(action: string, payload?: any): void;
}

interface BeatsTableState {
selection: any[];
selection: CMPopulatedBeat[];
}

const TableContainer = styled.div`
@@ -42,15 +42,10 @@ export class Table extends React.Component<BeatsTableProps, BeatsTableState> {
};
}

public resetSelection = () => {
this.setSelection([]);
};

public render() {
const {
actionHandler,
assignmentOptions,
renderAssignmentOptions,
assignmentTitle,
items,
showAssignmentOptions,
@@ -74,7 +69,6 @@ export class Table extends React.Component<BeatsTableProps, BeatsTableState> {
<ControlBar
actionHandler={(action: string, payload: any) => actionHandler(action, payload)}
assignmentOptions={assignmentOptions}
renderAssignmentOptions={renderAssignmentOptions}
assignmentTitle={assignmentTitle}
controlDefinitions={type.controlDefinitions(items)}
selectionCount={this.state.selection.length}
@@ -94,7 +88,7 @@ export class Table extends React.Component<BeatsTableProps, BeatsTableState> {
);
}

private setSelection = (selection: any[]) => {
private setSelection = (selection: any) => {
this.setState({
selection,
});
Original file line number Diff line number Diff line change
@@ -12,13 +12,19 @@ export class RestTagsAdapter implements CMTagsAdapter {
constructor(private readonly REST: RestAPIAdapter) {}

public async getTagsWithIds(tagIds: string[]): Promise<BeatTag[]> {
return (await this.REST.get<{ tags: BeatTag[] }>(`/api/beats/tags/${tagIds.join(',')}`)).tags;
const tags = await this.REST.get<BeatTag[]>(`/api/beats/tags/${tagIds.join(',')}`);
return tags;
}

public async getAll(): Promise<BeatTag[]> {
return await this.REST.get<BeatTag[]>(`/api/beats/tags`);
}

public async delete(tagIds: string[]): Promise<boolean> {
return (await this.REST.delete<{ success: boolean }>(`/api/beats/tags/${tagIds.join(',')}`))
.success;
}

public async upsertTag(tag: BeatTag): Promise<BeatTag | null> {
const response = await this.REST.put<{ success: boolean }>(`/api/beats/tag/${tag.id}`, {
color: tag.color,
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ export class BeatsLib {
return beat;
}

public async getAll(): Promise<CMPopulatedBeat[]> {
public async getAll(): Promise<CMBeat[]> {
const beats = await this.adapter.getAll();
return await this.mergeInTags(beats);
}
68 changes: 30 additions & 38 deletions x-pack/plugins/beats_management/public/pages/main/beats.tsx
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import {
} from '@elastic/eui';

import React from 'react';
import { BeatTag, CMPopulatedBeat } from '../../../common/domain_types';
import { BeatTag, CMBeat, CMPopulatedBeat } from '../../../common/domain_types';
import { BeatsTagAssignment } from '../../../server/lib/adapters/beats/adapter_types';
import { BeatsTableType, Table } from '../../components/table';
import { FrontendLibs } from '../../lib/lib';
@@ -23,19 +23,19 @@ interface BeatsPageProps {
}

interface BeatsPageState {
beats: CMPopulatedBeat[];
beats: CMBeat[];
tableRef: any;
tags: any[] | null;
}

export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageState> {
public static ActionArea = BeatsActionArea;
private tableRef = React.createRef<Table>();

constructor(props: BeatsPageProps) {
super(props);

this.state = {
beats: [],
tableRef: React.createRef(),
tags: null,
};

@@ -51,32 +51,9 @@ export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageStat
<Table
actionHandler={this.handleBeatsActions}
assignmentOptions={this.state.tags}
renderAssignmentOptions={(tag: BeatTag) => {
const selectedBeats = this.getSelectedBeats();
const hasMatches = selectedBeats.some((beat: any) =>
(beat.tags || []).some((t: string) => t === tag.id)
);

return (
<EuiFlexItem key={`${tag.id}-${hasMatches ? 'matched' : 'unmatched'}`}>
<EuiBadge
color={tag.color}
iconType={hasMatches ? 'cross' : undefined}
onClick={
hasMatches
? () => this.removeTagsFromBeats(selectedBeats, tag)
: () => this.assignTagsToBeats(selectedBeats, tag)
}
onClickAriaLabel={tag.id}
>
{tag.id}
</EuiBadge>
</EuiFlexItem>
);
}}
assignmentTitle="Set tags"
items={this.state.beats || []}
ref={this.tableRef}
ref={this.state.tableRef}
showAssignmentOptions={true}
type={BeatsTableType}
/>
@@ -111,9 +88,6 @@ export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageStat
// the max race condition time is really 10ms but doing 100 to be safe
setTimeout(async () => {
await this.loadBeats();
if (this.tableRef && this.tableRef.current) {
this.tableRef.current.resetSelection();
}
}, 100);
};

@@ -131,9 +105,32 @@ export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageStat

private loadTags = async () => {
const tags = await this.props.libs.tags.getAll();
const selectedBeats = this.getSelectedBeats();

const renderedTags = tags.map((tag: BeatTag) => {
const hasMatches = selectedBeats.some((beat: any) =>
(beat.tags || []).some((t: string) => t === tag.id)
);

return (
<EuiFlexItem key={tag.id}>
<EuiBadge
color={tag.color}
iconType={hasMatches ? 'cross' : undefined}
onClick={
hasMatches
? () => this.removeTagsFromBeats(selectedBeats, tag)
: () => this.assignTagsToBeats(selectedBeats, tag)
}
onClickAriaLabel={tag.id}
>
{tag.id}
</EuiBadge>
</EuiFlexItem>
);
});
this.setState({
tags,
tags: renderedTags,
});
};

@@ -154,11 +151,6 @@ export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageStat
};

private getSelectedBeats = (): CMPopulatedBeat[] => {
if (this.tableRef && this.tableRef.current) {
return this.tableRef.current.state.selection.map(
(beat: CMPopulatedBeat) => this.state.beats.find(b => b.id === beat.id) || beat
);
}
return [];
return this.state.tableRef.current.state.selection;
};
}
17 changes: 14 additions & 3 deletions x-pack/plugins/beats_management/public/pages/main/tags.tsx
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ export class TagsPage extends React.PureComponent<TagsPageProps, TagsPageState>
history.push(`/tag/create`);
}}
>
Add Token
Create Tag
</EuiButton>
);
constructor(props: TagsPageProps) {
@@ -67,11 +67,22 @@ export class TagsPage extends React.PureComponent<TagsPageProps, TagsPageState>
);
}

private handleTagsAction = (action: string, payload: any) => {
private handleTagsAction = async (action: string, payload: any) => {
switch (action) {
case 'loadAssignmentOptions':
this.loadBeats();
break;
case 'delete':
const tags = this.getSelectedTags().map(tag => tag.id);
const success = await this.props.libs.tags.delete(tags);
if (!success) {
alert(
'Some of these tags might be assigned to beats. Please ensure tags being removed are not activly assigned'
);
} else {
this.loadTags();
}
break;
}

this.loadTags();
@@ -153,7 +164,7 @@ export class TagsPage extends React.PureComponent<TagsPageProps, TagsPageState>
await this.props.libs.beats.assignTagsToBeats(assignments);
};

private getSelectedTags = () => {
private getSelectedTags = (): BeatTag[] => {
return this.state.tableRef.current.state.selection;
};
}
4 changes: 3 additions & 1 deletion x-pack/plugins/beats_management/public/pages/tag/create.tsx
Original file line number Diff line number Diff line change
@@ -63,7 +63,9 @@ export class CreateTagPage extends React.PureComponent<CreateTagPageProps, Creat
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty>Cancel</EuiButtonEmpty>
<EuiButtonEmpty onClick={() => this.props.history.push('/overview/tags')}>
Cancel
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</div>
2 changes: 1 addition & 1 deletion x-pack/plugins/beats_management/public/pages/tag/index.tsx
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ export class TagPage extends React.PureComponent<EditTagPageProps, EditTagPageSt

public render() {
return (
<PrimaryLayout title="Add a new tag">
<PrimaryLayout title="Create Tag">
<Switch>
<Route
path="/tag/create"
Original file line number Diff line number Diff line change
@@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { get } from 'lodash';
import { flatten, get } from 'lodash';
import { INDEX_NAMES } from '../../../../common/constants';
import { FrameworkUser } from '../framework/adapter_types';

import { BeatTag } from '../../../../common/domain_types';
import { BeatTag, CMBeat } from '../../../../common/domain_types';
import { DatabaseAdapter } from '../database/adapter_types';
import { CMTagsAdapter } from './adapter_types';

@@ -21,6 +21,7 @@ export class ElasticsearchTagsAdapter implements CMTagsAdapter {

public async getAll(user: FrameworkUser) {
const params = {
_source: true,
index: INDEX_NAMES.BEATS,
q: 'type:tag',
type: '_doc',
@@ -31,12 +32,68 @@ export class ElasticsearchTagsAdapter implements CMTagsAdapter {
return tags.map((tag: any) => tag._source.tag);
}

public async delete(user: FrameworkUser, tagIds: string[]) {
const ids = tagIds.map(tag => tag);

const params = {
ignore: [404],
index: INDEX_NAMES.BEATS,
type: '_doc',
body: {
query: {
terms: { 'beat.tags': tagIds },
},
},
};

const beatsResponse = await this.database.search(user, params);

const beats = get<CMBeat[]>(beatsResponse, 'hits.hits', []).map(
(beat: any) => beat._source.beat
);

const inactiveBeats = beats.filter(beat => beat.active === false);
const activeBeats = beats.filter(beat => beat.active === true);
if (activeBeats.length !== 0) {
return false;
}
const beatIds = inactiveBeats.map((beat: CMBeat) => beat.id);

const bulkBeatsUpdates = flatten(
beatIds.map(beatId => {
const script = `
def beat = ctx._source.beat;
if (beat.tags != null) {
beat.tags.removeAll([params.tag]);
}`;

return flatten(
ids.map(tagId => [
{ update: { _id: `beat:${beatId}` } },
{ script: { source: script.replace(' ', ''), params: { tagId } } },
])
);
})
);

const bulkTagsDelete = ids.map(tagId => ({ delete: { _id: `tag:${tagId}` } }));

await this.database.bulk(user, {
body: flatten([...bulkBeatsUpdates, ...bulkTagsDelete]),
index: INDEX_NAMES.BEATS,
refresh: 'wait_for',
type: '_doc',
});

return true;
}

public async getTagsWithIds(user: FrameworkUser, tagIds: string[]) {
const ids = tagIds.map(tag => `tag:${tag}`);

// TODO abstract to kibana adapter as the more generic getDocs
const params = {
_sourceInclude: ['tag.configuration_blocks'],
_source: true,
body: {
ids,
},
9 changes: 5 additions & 4 deletions x-pack/plugins/beats_management/server/lib/domains/tags.ts
Original file line number Diff line number Diff line change
@@ -13,10 +13,7 @@ import { entries } from '../../utils/polyfills';
import { CMTagsAdapter } from '../adapters/tags/adapter_types';

export class CMTagsDomain {
private adapter: CMTagsAdapter;
constructor(adapter: CMTagsAdapter) {
this.adapter = adapter;
}
constructor(private readonly adapter: CMTagsAdapter) {}

public async getAll(user: FrameworkUser) {
return await this.adapter.getAll(user);
@@ -26,6 +23,10 @@ export class CMTagsDomain {
return await this.adapter.getTagsWithIds(user, tagIds);
}

public async delete(user: FrameworkUser, tagIds: string[]) {
return await this.adapter.delete(user, tagIds);
}

public async saveTag(
user: FrameworkUser,
tagId: string,