Skip to content

Commit

Permalink
[Cases] Fix add Lens markdown plugin UX (#109178) (#110347)
Browse files Browse the repository at this point in the history
# Conflicts:
#	package.json
  • Loading branch information
patrykkopycinski authored Aug 26, 2021
1 parent b828702 commit f283973
Show file tree
Hide file tree
Showing 26 changed files with 1,139 additions and 460 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,9 @@
"redux-saga": "^1.1.3",
"redux-thunk": "^2.3.0",
"redux-thunks": "^1.0.0",
"remark-stringify": "^9.0.0",
"regenerator-runtime": "^0.13.3",
"remark-parse": "^8.0.3",
"remark-stringify": "^9.0.0",
"request": "^2.88.0",
"require-in-the-middle": "^5.0.2",
"reselect": "^4.0.0",
Expand Down
56 changes: 56 additions & 0 deletions x-pack/plugins/cases/common/utils/markdown_plugins/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 { filter } from 'lodash';
import type { Node } from 'unist';
import markdown from 'remark-parse';
import remarkStringify from 'remark-stringify';
import unified from 'unified';

import { TimeRange } from 'src/plugins/data/server';
import { SerializableRecord } from '@kbn/utility-types';
import { LENS_ID, LensParser, LensSerializer } from './lens';
import { TimelineSerializer, TimelineParser } from './timeline';

interface LensMarkdownNode extends Node {
timeRange: TimeRange;
attributes: SerializableRecord;
type: string;
id: string;
}

interface LensMarkdownParent extends Node {
children: Array<LensMarkdownNode | Node>;
}

export const getLensVisualizations = (parsedComment?: Array<LensMarkdownNode | Node>) =>
(parsedComment?.length ? filter(parsedComment, { type: LENS_ID }) : []) as LensMarkdownNode[];

export const parseCommentString = (comment: string) => {
const processor = unified().use([[markdown, {}], LensParser, TimelineParser]);
return processor.parse(comment) as LensMarkdownParent;
};

export const stringifyComment = (comment: LensMarkdownParent) =>
unified()
.use([
[
remarkStringify,
{
allowDangerousHtml: true,
handlers: {
/*
because we're using rison in the timeline url we need
to make sure that markdown parser doesn't modify the url
*/
timeline: TimelineSerializer,
lens: LensSerializer,
},
},
],
])
.stringify(comment);
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ import { EuiTheme } from '../../../../../../../src/plugins/kibana_react/common';
import { securityMock } from '../../../../../security/public/mocks';
import { triggersActionsUiMock } from '../../../../../triggers_actions_ui/public/mocks';

export const mockCreateStartServicesMock = (): StartServices =>
(({
...coreMock.createStart(),
security: securityMock.createStart(),
triggersActionsUi: triggersActionsUiMock.createStart(),
} as unknown) as StartServices);

export const createStartServicesMock = (): StartServices =>
(({
...coreMock.createStart(),
storage: { ...coreMock.createStorage(), remove: jest.fn() },
lens: {
canUseEditor: jest.fn(),
navigateToPrefilledEditor: jest.fn(),
},
security: securityMock.createStart(),
triggersActionsUi: triggersActionsUiMock.createStart(),
} as unknown) as StartServices);
Expand Down
16 changes: 13 additions & 3 deletions x-pack/plugins/cases/public/components/create/description.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,26 @@ interface Props {
export const fieldName = 'description';

const DescriptionComponent: React.FC<Props> = ({ isLoading }) => {
const { draftComment, openLensModal } = useLensDraftComment();
const {
draftComment,
hasIncomingLensState,
openLensModal,
clearDraftComment,
} = useLensDraftComment();
const { setFieldValue } = useFormContext();
const editorRef = useRef<Record<string, any>>();

useEffect(() => {
if (draftComment?.commentId === fieldName && editorRef.current) {
setFieldValue(fieldName, draftComment.comment);
openLensModal({ editorRef: editorRef.current });

if (hasIncomingLensState) {
openLensModal({ editorRef: editorRef.current });
} else {
clearDraftComment();
}
}
}, [draftComment, openLensModal, setFieldValue]);
}, [clearDraftComment, draftComment, hasIncomingLensState, openLensModal, setFieldValue]);

return (
<UseField
Expand Down
19 changes: 17 additions & 2 deletions x-pack/plugins/cases/public/components/markdown_editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ import React, {
ElementRef,
} from 'react';
import { PluggableList } from 'unified';
import { EuiMarkdownEditor, EuiMarkdownEditorUiPlugin } from '@elastic/eui';
import {
EuiMarkdownEditor,
EuiMarkdownEditorProps,
EuiMarkdownAstNode,
EuiMarkdownEditorUiPlugin,
} from '@elastic/eui';
import { ContextShape } from '@elastic/eui/src/components/markdown_editor/markdown_context';
import { usePlugins } from './use_plugins';
import { CommentEditorContext } from './context';
import { useLensButtonToggle } from './plugins/lens/use_lens_button_toggle';

interface MarkdownEditorProps {
ariaLabel: string;
Expand All @@ -43,13 +49,22 @@ export interface MarkdownEditorRef {

const MarkdownEditorComponent = forwardRef<MarkdownEditorRef, MarkdownEditorProps>(
({ ariaLabel, dataTestSubj, editorId, height, onChange, value }, ref) => {
const astRef = useRef<EuiMarkdownAstNode | undefined>(undefined);
const [markdownErrorMessages, setMarkdownErrorMessages] = useState([]);
const onParse = useCallback((err, { messages }) => {
const onParse: EuiMarkdownEditorProps['onParse'] = useCallback((err, { messages, ast }) => {
setMarkdownErrorMessages(err ? [err] : messages);
astRef.current = ast;
}, []);
const { parsingPlugins, processingPlugins, uiPlugins } = usePlugins();
const editorRef = useRef<EuiMarkdownEditorRef>(null);

useLensButtonToggle({
astRef,
uiPlugins,
editorRef: ref as React.MutableRefObject<MarkdownEditorRef>,
value,
});

const commentEditorContextValue = useMemo(
() => ({
editorId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
*/

export const ID = 'lens';
export const PREFIX = `[`;
export const PREFIX = `!{${ID}`;
export const LENS_VISUALIZATION_HEIGHT = 200;
export const DRAFT_COMMENT_STORAGE_ID = 'xpack.cases.commentDraft';
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
import { plugin } from './plugin';
import { LensParser } from './parser';
import { LensMarkDownRenderer } from './processor';
import { INSERT_LENS } from './translations';
import { VISUALIZATION } from './translations';

export { plugin, LensParser as parser, LensMarkDownRenderer as renderer, INSERT_LENS };
export { plugin, LensParser as parser, LensMarkDownRenderer as renderer, VISUALIZATION };
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
* 2.0.
*/

import { EuiFlexGroup } from '@elastic/eui';
import styled from 'styled-components';

export const ModalContainer = styled.div`
export const ModalContainer = styled(EuiFlexGroup)`
width: ${({ theme }) => theme.eui.euiBreakpoints.m};
height: 100%;
.euiModalBody {
min-height: 300px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

import { Plugin } from 'unified';
import { RemarkTokenizer } from '@elastic/eui';
import { ID } from './constants';
import { ID, PREFIX } from './constants';

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(`!{${ID}`) === false) return false;
if (value.startsWith(PREFIX) === false) return false;

const nextChar = value[6];

Expand All @@ -28,7 +28,7 @@ export const LensParser: Plugin = function () {
// is there a configuration?
const hasConfiguration = nextChar === '{';

let match = `!{${ID}`;
let match = PREFIX;
let configuration = {};

if (hasConfiguration) {
Expand Down
Loading

0 comments on commit f283973

Please sign in to comment.