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

[Cases] Add Lens markdown plugin #96703

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
d1d567f
[Cases] Add Lens markdown plugin
patrykkopycinski Mar 23, 2021
18e90b4
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Apr 8, 2021
77edc5b
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Apr 9, 2021
601aaaa
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Apr 9, 2021
44b89fb
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Apr 9, 2021
4b46590
cleanup
patrykkopycinski Apr 9, 2021
7d49b2d
cleanup
patrykkopycinski Apr 9, 2021
8436ff6
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski May 29, 2021
df69565
Merge 8436ff62f55adf4a8e9de877a7f3852a21e2e334 into 0993a1c32114a0325…
patrykkopycinski Jun 14, 2021
60146c5
add lens to cases
stephmilovic Jun 14, 2021
ab71519
remove comments
stephmilovic Jun 14, 2021
6ff1f5c
Merge branch 'master' into feat/cases-lens-markdown-plugin
kibanamachine Jun 14, 2021
3aef8c6
Merge pull request #5 from stephmilovic/lens_cases
patrykkopycinski Jun 15, 2021
f1060bc
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 15, 2021
1c1cc05
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 15, 2021
022df3b
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 15, 2021
f87be1b
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 15, 2021
44636c3
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 16, 2021
20a0a77
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 17, 2021
c1a91ab
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 17, 2021
3d47eae
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 17, 2021
620e9db
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 18, 2021
48e2b82
[WIP]
patrykkopycinski Jun 18, 2021
1a8306e
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 20, 2021
a56fc49
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 21, 2021
039de02
wip
patrykkopycinski Jun 21, 2021
7a553c3
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 21, 2021
2ae9265
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 21, 2021
f44000e
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 21, 2021
a2740d1
Merge branch 'master' into feat/cases-lens-markdown-plugin
kibanamachine Jun 22, 2021
3c93fff
WIP
patrykkopycinski Jun 22, 2021
706d667
Merge branch 'feat/cases-lens-markdown-plugin' of github.com:patrykko…
patrykkopycinski Jun 22, 2021
15ffab8
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 22, 2021
dfa7473
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
130b9cb
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
9fc6d43
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
f585c32
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
293e470
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
24f377a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
e3a96e2
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
33aa258
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 23, 2021
1ee0f3a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
deffaec
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
5a3d197
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
c706c18
cleanup
patrykkopycinski Jun 24, 2021
485b0ae
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
e29aaf7
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
e7a7ef3
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 24, 2021
bbcbacd
WIP
patrykkopycinski Jun 24, 2021
9342833
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 25, 2021
22275e1
WIP
patrykkopycinski Jun 25, 2021
f0fbc82
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 25, 2021
1264487
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 26, 2021
d3ff6b2
cleanup
patrykkopycinski Jun 27, 2021
1c8fbbf
cleanup
patrykkopycinski Jun 27, 2021
8ab3b71
currentAppId
patrykkopycinski Jun 27, 2021
19c09af
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 27, 2021
5034a24
lens in obs
patrykkopycinski Jun 27, 2021
a05939d
update types
patrykkopycinski Jun 27, 2021
528ce5a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 28, 2021
4a62f3d
i18n
patrykkopycinski Jun 28, 2021
589592e
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 29, 2021
b825b22
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 29, 2021
a4e942c
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 29, 2021
0891047
add feature flag
patrykkopycinski Jun 29, 2021
c422e59
move everything to cases
patrykkopycinski Jun 29, 2021
88b9434
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jun 29, 2021
27c12f3
PR comments
patrykkopycinski Jun 29, 2021
2580a7a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 12, 2021
099fb1a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 12, 2021
a99237d
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 14, 2021
914f931
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 14, 2021
6688536
update types
patrykkopycinski Jul 14, 2021
a5339b4
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 14, 2021
cbe7ecf
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 15, 2021
73d38d3
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 15, 2021
ae1df3e
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 15, 2021
5af9475
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 15, 2021
7973e63
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 15, 2021
e4d8af7
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 16, 2021
1e5d898
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 16, 2021
1fbee5d
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 16, 2021
4104d21
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 17, 2021
e4310b0
cleanup
patrykkopycinski Jul 17, 2021
ae60ba7
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 18, 2021
42b0c7e
migrations
patrykkopycinski Jul 19, 2021
bfacd39
hidden
patrykkopycinski Jul 19, 2021
f5dc789
package.json
patrykkopycinski Jul 19, 2021
e8c5c13
cleanup
patrykkopycinski Jul 19, 2021
1433c78
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 19, 2021
a537d3a
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 19, 2021
88583e0
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 20, 2021
631ec85
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 20, 2021
5cd5962
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 25, 2021
ffa5759
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 25, 2021
e79046d
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Jul 28, 2021
1ac2e1b
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 1, 2021
5d59b6b
update unit tests
patrykkopycinski Aug 1, 2021
c3375d3
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 3, 2021
cfcc356
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 4, 2021
9691ca2
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 4, 2021
835516f
WIP
patrykkopycinski Aug 4, 2021
b63776a
WIP
patrykkopycinski Aug 8, 2021
2d343c8
fix tsconfig
patrykkopycinski Aug 8, 2021
13c4d98
Cleanup
patrykkopycinski Aug 8, 2021
b119cdc
cleanup
patrykkopycinski Aug 8, 2021
b19c377
cleanup
patrykkopycinski Aug 8, 2021
fec3cbd
add mock
patrykkopycinski Aug 9, 2021
2029180
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 9, 2021
a72d875
imports
patrykkopycinski Aug 9, 2021
d11997b
cleanup
patrykkopycinski Aug 9, 2021
1dcc00f
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 12, 2021
35f7bee
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 13, 2021
af3fbe8
UX improvements
patrykkopycinski Aug 13, 2021
83c83d0
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 15, 2021
6e15a15
cleanup
patrykkopycinski Aug 15, 2021
7775cb8
cleanup
patrykkopycinski Aug 15, 2021
5513a45
update unit tests
patrykkopycinski Aug 16, 2021
b043f65
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 16, 2021
317e7dc
PR comments
patrykkopycinski Aug 16, 2021
a0199c5
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 17, 2021
1f85cad
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 17, 2021
c2a439f
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 17, 2021
2565f05
Merge branch 'master' of github.com:elastic/kibana into feat/cases-le…
patrykkopycinski Aug 17, 2021
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/security_solution/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
],
"optionalPlugins": [
"encryptedSavedObjects",
"lens",
"fleet",
"ml",
"newsfeed",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ import {
} from '@elastic/eui';

import * as timelineMarkdownPlugin from './timeline';
import * as lensMarkdownPlugin from './lens';
const uiPlugins: EuiMarkdownEditorUiPlugin[] = getDefaultEuiMarkdownUiPlugins();
uiPlugins.push(timelineMarkdownPlugin.plugin);
uiPlugins.push(lensMarkdownPlugin.plugin);
export { uiPlugins };
export const parsingPlugins = getDefaultEuiMarkdownParsingPlugins();
export const processingPlugins = getDefaultEuiMarkdownProcessingPlugins();

parsingPlugins.push(timelineMarkdownPlugin.parser);
parsingPlugins.push(lensMarkdownPlugin.parser);

// This line of code is TS-compatible and it will break if [1][1] change in the future.
processingPlugins[1][1].components.timeline = timelineMarkdownPlugin.renderer;
processingPlugins[1][1].components.lens = lensMarkdownPlugin.renderer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const ID = 'lens';
export const PREFIX = `[`;
export const LENS_VISUALIZATION_HEIGHT = 200;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { plugin } from './plugin';
import { LensParser } from './parser';
import { LensMarkDownRenderer } from './processor';

export { plugin, LensParser as parser, LensMarkDownRenderer as renderer };
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { Plugin } from 'unified';
import { RemarkTokenizer } from '@elastic/eui';

export const LensParser: Plugin = function () {
const Parser = this.Parser;
const tokenizers = Parser.prototype.blockTokenizers;
const methods = Parser.prototype.blockMethods;

const tokenizeLens: RemarkTokenizer = function (eat, value, silent) {
if (value.startsWith('!{lens') === false) return false;
patrykkopycinski marked this conversation as resolved.
Show resolved Hide resolved

const nextChar = value[6];

if (nextChar !== '{' && nextChar !== '}') return false; // this isn't actually a lens

if (silent) {
return true;
}

// is there a configuration?
const hasConfiguration = nextChar === '{';

let match = '!{lens';
let configuration = {};

if (hasConfiguration) {
let configurationString = '';

let openObjects = 0;

for (let i = 6; i < value.length; i++) {
const char = value[i];
if (char === '{') {
openObjects++;
configurationString += char;
} else if (char === '}') {
openObjects--;
if (openObjects === -1) {
break;
}
configurationString += char;
} else {
configurationString += char;
}
}

match += configurationString;
try {
configuration = JSON.parse(configurationString);
} catch (e) {
const now = eat.now();
this.file.fail(`Unable to parse lens JSON configuration: ${e}`, {
line: now.line,
column: now.column + 6,
});
}
}

match += '}';

return eat(match)({
type: 'lens',
...configuration,
});
};

tokenizers.lens = tokenizeLens;
methods.splice(methods.indexOf('text'), 0, 'lens');
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import {
EuiComboBox,
EuiModalBody,
EuiModalHeader,
EuiModalHeaderTitle,
EuiMarkdownEditorUiPlugin,
EuiCodeBlock,
EuiSpacer,
EuiModalFooter,
EuiButtonEmpty,
EuiButton,
EuiFlexItem,
EuiFlexGroup,
EuiFormRow,
EuiDatePicker,
EuiDatePickerRange,
} from '@elastic/eui';
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import moment, { Moment } from 'moment';

import { TypedLensByValueInput } from '../../../../../../../lens/public';
import { useKibana } from '../../../../lib/kibana';
import { LensMarkDownRenderer } from './processor';
import { ID } from './constants';
import * as i18n from './translations';

const ModalContainer = styled.div`
width: ${({ theme }) => theme.eui.euiBreakpoints.m};
`;

interface LensEditorProps {
id?: string | null;
title?: string | null;
startDate?: Moment | null;
endDate?: Moment | null;
onClosePopover: () => void;
onInsert: (markdown: string, config: { block: boolean }) => void;
}

const LensEditorComponent: React.FC<LensEditorProps> = ({
id,
title,
startDate: defaultStartDate,
endDate: defaultEndDate,
onClosePopover,
onInsert,
}) => {
const soClient = useKibana().services.savedObjects.client;
const [lensOptions, setLensOptions] = useState<Array<{ label: string; value: string }>>([]);
const [selectedOptions, setSelectedOptions] = useState<Array<{ label: string; value: string }>>(
id && title ? [{ value: id, label: title }] : []
);
const [lensSavedObjectId, setLensSavedObjectId] = useState<string | null>(id ?? null);
const [startDate, setStartDate] = useState<Moment | null>(
defaultStartDate ? moment(defaultStartDate) : moment().subtract(7, 'd')
);
const [endDate, setEndDate] = useState<Moment | null>(
defaultEndDate ? moment(defaultEndDate) : moment()
);

useEffect(() => {
const fetchLensSavedObjects = async () => {
const { savedObjects } = await soClient.find<TypedLensByValueInput['attributes']>({
type: 'lens',
perPage: 1000,
patrykkopycinski marked this conversation as resolved.
Show resolved Hide resolved
});
const options = savedObjects.map((lensSO) => ({
label: lensSO.attributes.title,
value: lensSO.id,
}));

setLensOptions(options);
};
fetchLensSavedObjects();
}, [soClient]);

const handleChange = useCallback((options) => {
setSelectedOptions(options);
setLensSavedObjectId(options[0] ? options[0].value : null);
}, []);

const handleLensDateChange = useCallback((data) => {
if (data.range?.length === 2) {
setStartDate(moment(data.range[0]));
setEndDate(moment(data.range[1]));
}
}, []);

const handleAdd = useCallback(() => {
if (lensSavedObjectId && selectedOptions[0]) {
onInsert(
`!{lens${JSON.stringify({
id: lensSavedObjectId,
startDate,
endDate,
title: selectedOptions[0].label,
})}}`,
{
block: true,
}
);
}
}, [lensSavedObjectId, selectedOptions, onInsert, startDate, endDate]);

return (
<ModalContainer>
<EuiModalHeader>
<EuiModalHeaderTitle>
{id && title ? 'Edit Lens visualization' : 'Add Lens visualization'}
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow label="Title">
<EuiComboBox
placeholder="Select a single option"
singleSelection={{ asPlainText: true }}
options={lensOptions}
selectedOptions={selectedOptions}
onChange={handleChange}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow label="Date range">
<EuiDatePickerRange
startDateControl={
<EuiDatePicker
selected={startDate}
onChange={setStartDate}
startDate={startDate}
endDate={endDate}
isInvalid={startDate && endDate ? startDate > endDate : false}
aria-label="Start date"
showTimeSelect
/>
}
endDateControl={
<EuiDatePicker
selected={endDate}
onChange={setEndDate}
startDate={startDate}
endDate={endDate}
isInvalid={startDate && endDate ? startDate > endDate : false}
aria-label="End date"
showTimeSelect
/>
}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<LensMarkDownRenderer
id={lensSavedObjectId}
startDate={startDate?.format()}
endDate={endDate?.format()}
onBrushEnd={handleLensDateChange}
/>
</EuiModalBody>
<EuiModalFooter>
<EuiButtonEmpty onClick={onClosePopover}>{'Cancel'}</EuiButtonEmpty>
<EuiButton onClick={handleAdd} fill disabled={!lensSavedObjectId}>
{'Add to a Case'}
</EuiButton>
</EuiModalFooter>
</ModalContainer>
);
};

const LensEditor = React.memo(LensEditorComponent);

export const plugin: EuiMarkdownEditorUiPlugin = {
name: ID,
button: {
label: i18n.INSERT_LENS,
iconType: 'lensApp',
},
helpText: (
<EuiCodeBlock language="md" paddingSize="s" fontSize="l">
{'[title](url)'}
</EuiCodeBlock>
),
editor: function editor({ node, onSave, onCancel }) {
return (
<LensEditor
id={node?.id}
startDate={node?.startDate}
endDate={node?.endDate}
title={node?.title}
onClosePopover={onCancel}
onInsert={onSave}
/>
);
},
};
Loading