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 Management] Add Tags List #21274

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
631bc22
Add BeatsTable and control bar components.
justinkambic Jul 24, 2018
31b09ed
Clean yarn.lock.
justinkambic Jul 24, 2018
f9d28f5
Move raw numbers/strings to constants. Remove obsolete state/props.
justinkambic Jul 25, 2018
f261784
Update/add tests.
justinkambic Jul 25, 2018
8860a25
Change prop name from "items" to "beats".
justinkambic Jul 25, 2018
61ec2f2
Add TagsTable component and associated search/action bar.
justinkambic Jul 25, 2018
f00c9b9
Rename some variables.
justinkambic Jul 26, 2018
3bb679a
Merge branch 'ui/beats-table' into ui/tags-table
justinkambic Jul 26, 2018
8035c4b
Add constant after forgetting to save file.
justinkambic Jul 26, 2018
cc99601
Merge branch 'feature/x-pack/management/beats' into ui/beats-table
justinkambic Jul 26, 2018
b66a824
Merge branch 'feature/x-pack/management/beats' into ui/tags-table
justinkambic Jul 26, 2018
80779b2
Merge branch 'feature/x-pack/management/beats' into ui/beats-table
justinkambic Jul 26, 2018
d0e3415
Merge branch 'feature/x-pack/management/beats' into ui/tags-table
justinkambic Jul 26, 2018
43dfc17
Fix design mistake in table component.
justinkambic Jul 26, 2018
d6ac178
Disable delete button when no tags selected.
justinkambic Jul 26, 2018
870150f
Export tags table from index.ts.
justinkambic Jul 26, 2018
eb9495b
Move search bar filter definitions to table render.
justinkambic Jul 26, 2018
9e2a38e
Update table to support assignment options.
justinkambic Aug 2, 2018
f4ed8bc
Update action control position.
justinkambic Aug 2, 2018
05cbac2
Refactor split render function into custom components.
justinkambic Aug 3, 2018
1581966
Merge branch 'feature/x-pack/management/beats' into ui/beats-table
justinkambic Aug 3, 2018
b25d4ec
Merge latest changes to table components.
justinkambic Aug 3, 2018
f8c9fff
Merge branch 'feature/x-pack/management/beats' into ui/tags-table
justinkambic Aug 3, 2018
fe7441a
Add assignment options to Tags List.
justinkambic Aug 6, 2018
2f343c5
Remove obsolete code.
justinkambic Aug 6, 2018
01afe66
Move tooltips for tag icons to top position.
justinkambic Aug 6, 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
1 change: 1 addition & 0 deletions x-pack/plugins/beats_management/common/constants/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
export const TABLE_CONFIG = {
INITIAL_ROW_SIZE: 5,
PAGE_SIZE_OPTIONS: [3, 5, 10, 20],
TRUNCATE_TAG_LENGTH: 33,
};
1 change: 1 addition & 0 deletions x-pack/plugins/beats_management/common/domain_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export interface BeatTag {
id: string;
configuration_blocks: ConfigurationBlock[];
color?: string;
last_updated: Date;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function ControlBar(props: ControlBarProps) {
selectionCount,
showAssignmentOptions,
} = props;
const filters = controlDefinitions.filters.length === 0 ? null : controlDefinitions.filters;
return selectionCount !== 0 && showAssignmentOptions ? (
<AssignmentOptions
actionHandler={actionHandler}
Expand All @@ -41,7 +42,7 @@ export function ControlBar(props: ControlBarProps) {
) : (
<EuiSearchBar
box={{ incremental: true }}
filters={controlDefinitions.filters}
filters={filters}
onChange={(query: any) => actionHandler('search', query)}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

export { Table } from './table';
export { ControlBar } from './controls';
export { BeatsTableType } from './table_type_configs';
export { BeatsTableType, TagsTableType } from './table_type_configs';
12 changes: 10 additions & 2 deletions x-pack/plugins/beats_management/public/components/table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface BeatsTableProps {
assignmentOptions: any[] | null;
assignmentTitle: string | null;
items: any[];
showAssignmentOptions: boolean;
type: TableType;
actionHandler(action: string, payload?: any): void;
}
Expand All @@ -42,7 +43,14 @@ export class Table extends React.Component<BeatsTableProps, BeatsTableState> {
}

public render() {
const { actionHandler, assignmentOptions, assignmentTitle, items, type } = this.props;
const {
actionHandler,
assignmentOptions,
assignmentTitle,
items,
showAssignmentOptions,
type,
} = this.props;

const pagination = {
initialPageSize: TABLE_CONFIG.INITIAL_ROW_SIZE,
Expand All @@ -64,7 +72,7 @@ export class Table extends React.Component<BeatsTableProps, BeatsTableState> {
assignmentTitle={assignmentTitle}
controlDefinitions={type.controlDefinitions(items)}
selectionCount={this.state.selection.length}
showAssignmentOptions={true}
showAssignmentOptions={showAssignmentOptions}
/>
<EuiSpacer size="m" />
<EuiInMemoryTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { EuiBadge, EuiFlexGroup, EuiIcon, EuiLink } from '@elastic/eui';
import { flatten, uniq } from 'lodash';
import moment from 'moment';
import React from 'react';
import { CMPopulatedBeat } from '../../../common/domain_types';
import { TABLE_CONFIG } from '../../../common/constants';
import { BeatTag, CMPopulatedBeat, ConfigurationBlock } from '../../../common/domain_types';

export interface ColumnDefinition {
align?: string;
field: string;
name: string;
sortable?: boolean;
width?: string;
render?(value: any, object?: any): any;
}

Expand Down Expand Up @@ -114,3 +117,41 @@ export const BeatsTableType: TableType = {
],
}),
};

export const TagsTableType: TableType = {
columnDefinitions: [
{
field: 'id',
name: 'Tag name',
render: (id: string, tag: BeatTag) => (
<EuiBadge color={tag.color ? tag.color : 'primary'}>
{tag.id.length > TABLE_CONFIG.TRUNCATE_TAG_LENGTH
? `${tag.id.substring(0, TABLE_CONFIG.TRUNCATE_TAG_LENGTH)}...`
: tag.id}
</EuiBadge>
),
sortable: true,
width: '45%',
},
{
align: 'right',
field: 'configuration_blocks',
name: 'Configurations',
render: (configurationBlocks: ConfigurationBlock[]) => (
<div>{configurationBlocks.length}</div>
),
sortable: false,
},
{
align: 'right',
field: 'last_updated',
name: 'Last update',
render: (lastUpdate: Date) => <div>{moment(lastUpdate).fromNow()}</div>,
sortable: true,
},
],
controlDefinitions: (data: any) => ({
actions: [],
filters: [],
}),
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ export class MemoryBeatsAdapter implements CMBeatsAdapter {
const beatIds = removals.map(r => r.beatId);

const response = this.beatsDB.filter(beat => beatIds.includes(beat.id)).map(beat => {
const tagData = removals.find(r => r.beatId === beat.id);
if (tagData) {
if (beat.tags) {
beat.tags = beat.tags.filter(tag => tag !== tagData.tag);
}
const removalsForBeat = removals.filter(r => r.beatId === beat.id);
if (removalsForBeat.length) {
removalsForBeat.forEach((assignment: BeatsTagAssignment) => {
if (beat.tags) {
beat.tags = beat.tags.filter(tag => tag !== assignment.tag);
}
});
}
return beat;
});
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/beats_management/public/pages/main/beats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ interface BeatsPageProps {

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

export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageState> {
Expand Down Expand Up @@ -93,6 +93,7 @@ export class BeatsPage extends React.PureComponent<BeatsPageProps, BeatsPageStat
assignmentTitle="Set tags"
items={this.state.beats}
ref={this.state.tableRef}
showAssignmentOptions={true}
type={BeatsTableType}
/>
);
Expand Down
132 changes: 130 additions & 2 deletions x-pack/plugins/beats_management/public/pages/main/tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,138 @@
* you may not use this file except in compliance with the Elastic License.
*/

// @ts-ignore EuiToolTip has no typings in current version
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiToolTip } from '@elastic/eui';
import React from 'react';
import { BeatTag, CMBeat } from '../../../common/domain_types';
import { BeatsTagAssignment } from '../../../server/lib/adapters/beats/adapter_types';
import { Table, TagsTableType } from '../../components/table';
import { FrontendLibs } from '../../lib/lib';

interface TagsPageProps {
libs: FrontendLibs;
}

interface TagsPageState {
beats: any;
tableRef: any;
tags: BeatTag[];
}

export class TagsPage extends React.PureComponent<TagsPageProps, TagsPageState> {
constructor(props: TagsPageProps) {
super(props);

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

this.loadTags();
}

export class TagsPage extends React.PureComponent {
public render() {
return <div>tags table and stuff</div>;
return (
<Table
actionHandler={this.handleTagsAction}
assignmentOptions={this.state.beats}
assignmentTitle={'Assign Beats'}
items={this.state.tags}
ref={this.state.tableRef}
showAssignmentOptions={true}
type={TagsTableType}
/>
);
}

private handleTagsAction = (action: string, payload: any) => {
switch (action) {
case 'loadAssignmentOptions':
this.loadBeats();
break;
}

this.loadTags();
};

private async loadTags() {
const tags = await this.props.libs.tags.getAll();
this.setState({
tags,
});
}

private async loadBeats() {
const beats = await this.props.libs.beats.getAll();
const selectedTags = this.getSelectedTags();
const renderedBeats = beats.map((beat: CMBeat) => {
const tagsToRemove: BeatTag[] = [];
const tagsToAdd: BeatTag[] = [];
const tags = beat.tags || [];
selectedTags.forEach((tag: BeatTag) => {
tags.some((tagId: string) => tagId === tag.id)
? tagsToRemove.push(tag)
: tagsToAdd.push(tag);
});

const tagIcons = tags.map((tagId: string) => {
const associatedTag = this.state.tags.find(tag => tag.id === tagId);
return (
<EuiToolTip title={tagId}>
<EuiIcon
key={tagId}
type="stopFilled"
// @ts-ignore color typing does not allow for any string
color={associatedTag.color || 'primary'}
/>
</EuiToolTip>
);
});

return (
<EuiFlexItem key={beat.id}>
<EuiFlexGroup alignItems="center" gutterSize="none">
{tagIcons.map(icon => (
<EuiFlexItem component="span" grow={false}>
{icon}
</EuiFlexItem>
))}
<EuiFlexItem>
<EuiButtonEmpty
onClick={() => {
this.assignTagsToBeats(beat, tagsToAdd);
this.removeTagsFromBeats(beat, tagsToRemove);
this.loadBeats();
}}
>
{beat.id}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
);
});

this.setState({
beats: renderedBeats,
});
}

private createBeatTagAssignments = (beat: CMBeat, tags: BeatTag[]): BeatsTagAssignment[] =>
tags.map(({ id }) => ({ tag: id, beatId: beat.id }));

private removeTagsFromBeats = async (beat: CMBeat, tags: BeatTag[]) => {
const assignments = this.createBeatTagAssignments(beat, tags);
await this.props.libs.beats.removeTagsFromBeats(assignments);
};

private assignTagsToBeats = async (beat: CMBeat, tags: BeatTag[]) => {
const assignments = this.createBeatTagAssignments(beat, tags);
await this.props.libs.beats.assignTagsToBeats(assignments);
};

private getSelectedTags = () => {
return this.state.tableRef.current.state.selection;
};
}