-
Václav Bartoš authoredVáclav Bartoš authored
options_editor.js 5.73 KiB
import React from 'react';
import {
EuiForm,
EuiFormRow,
EuiTitle,
EuiSpacer,
EuiFieldText,
EuiFieldNumber,
EuiSelect,
EuiFlexGroup,
EuiFlexItem,
EuiButton,
EuiButtonIcon,
} from '@elastic/eui';
// Default data types in The Hive
const DEFAULT_THE_HIVE_TYPES = [
'',
'autonomous-system',
'domain',
'file',
'filename',
'fqdn',
'hash',
'ip',
'mail',
'mail_subject',
'regexp',
'registry',
'uri_path',
'url',
'user-agent',
'other',
];
// Options for EuiSelect for selection of field's data type in TheHive
const typesOptions = DEFAULT_THE_HIVE_TYPES.map( dt => ({value: dt, text: dt}) );
export function optionsEditor(props) {
//console.log("editor render(), props:", props);
const { stateParams, setValue, setValidity, vis } = props;
// onClick/onChange handlers
const obsAddNew = () => {
const newObsFields = [...stateParams.obsFields, {name: "", type: "", cnt: 100}];
// For some reason, first click on the button after editor is loaded does
// nothing. Calling setValue twice here fixes it.
setValue("obsFields", newObsFields);
setValue("obsFields", newObsFields);
// setValidity(false); // since new row is empty, form is always invalid
};
const obsRemove = (ix) => {
let newArray = [...stateParams.obsFields];
newArray.splice(ix, 1);
setValue("obsFields", newArray);
// validate();
}
const obsSetName = (ix, name) => {
let newArray = [...stateParams.obsFields];
newArray[ix].name = name;
setValue("obsFields", newArray);
// validate();
}
const obsSetType = (ix, type) => {
let newArray = [...stateParams.obsFields];
newArray[ix].type = type;
setValue("obsFields", newArray);
// validate();
}
const obsSetCnt = (ix, cnt) => {
let newArray = [...stateParams.obsFields];
newArray[ix].cnt = parseInt(cnt);
setValue("obsFields", newArray);
// validate();
}
// const validate = () => {
// let valid = true;
// for (let field of stateParams.obsFields) {
// if (field.name == "" || field.type == "" || field.cnt == "") {
// valid = false;
// break;
// }
// }
// // TODO check for duplicate fields
// setValidity(valid);
// }
// Get list of all fields in index (except those beginning with "_" or "@")
// and create "options" parameter for EuiSelect.
// Also, fields with "aggregatable=false" are removed, as they can't be used
// with "terms" aggregation we need.
// See this for details: https://www.elastic.co/guide/en/elasticsearch/reference/7.x/fielddata.html
// Empty field is added at the beginning, meaning "no selection yet".
const fieldOptions = [{value: "", text: ""}].concat(
vis.indexPattern.fields.raw.filter( f => (f.name[0] != "_" && f.name[0] != "@" && f.aggregatable) ).map( f => ({value: f.name, text: `${f.name} (${f.type})`}) )
);
return <EuiForm>
<EuiFormRow fullWidth={true} label="Base URL of The Hive">
<EuiFieldText
fullWidth={true}
value={stateParams.url}
onChange={e => setValue('url', e.target.value)}
isInvalid={stateParams.url == ""}
/>
</EuiFormRow>
<EuiFlexGroup>
<EuiFlexItem grow={1}>
<EuiFormRow label="API key to access The Hive" helpText="API key of a user with permission to create cases (not admin).">
<EuiFieldText
fullWidth={true}
value={stateParams.apikey}
onChange={e => setValue('apikey', e.target.value)}
isInvalid={stateParams.apikey == ""}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<EuiFormRow label="Assignee" helpText="Assign created cases to this user instead of the owner of the API key (optional, if set, it must be a valid username from The Hive instance). **Note: This currently doesn't work due to a bug in The Hive.**">
<EuiFieldText
value={stateParams.owner}
onChange={e => setValue('owner', e.target.value)}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
<EuiTitle size="s"><h3>Fields to get potential observables from ...</h3></EuiTitle>
<EuiSpacer size="s" />
{stateParams.obsFields.map( (field, ix) => (
<EuiFlexGroup key={ix} gutterSize="s">
<EuiFlexItem grow={3}>
<EuiFormRow label="Field name">
<EuiSelect
options={fieldOptions}
value={field.name}
onChange={ e => obsSetName(ix, e.target.value) }
isInvalid={field.name == ""}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={2}>
<EuiFormRow label="Data type in The Hive">
<EuiSelect
options={typesOptions}
value={field.type}
onChange={ e => obsSetType(ix, e.target.value) }
isInvalid={field.type == ""}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<EuiFormRow label="Max items shown">
<EuiFieldNumber
min={1}
max={1000}
value={parseInt(field.cnt)}
onChange={ e => obsSetCnt(ix, e.target.value) }
isInvalid={!(field.cnt > 0)}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow hasEmptyLabelSpace>
<EuiButtonIcon iconType="trash" iconSize="m" color="danger" aria-label="Remove field" onClick={ e => obsRemove(ix) } />
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
))}
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButton iconType="plusInCircleFilled" color="primary" onClick={obsAddNew}>Add new field ...</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiForm>
}