Skip to content

Commit

Permalink
Adds individual ISM template UI component (opensearch-project#51)
Browse files Browse the repository at this point in the history
Signed-off-by: Drew Baugher <[email protected]>
  • Loading branch information
dbbaughe authored Aug 11, 2021
1 parent 0d6b814 commit c70a926
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 0 deletions.
5 changes: 5 additions & 0 deletions models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ export interface MessageTemplate {
lang?: string;
}

export interface ISMTemplate {
index_patterns: string[];
priority: number;
}

export interface State {
name: string;
actions: object[];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render } from "@testing-library/react";
import ISMTemplate from "./ISMTemplate";
import { fireEvent } from "@testing-library/dom";
import userEvent from "@testing-library/user-event/dist";

describe("<ISMTemplate /> spec", () => {
it("renders the component", () => {
const { container } = render(
<ISMTemplate
template={{ index_patterns: ["*"], priority: 5 }}
onUpdateTemplate={() => {}}
onRemoveTemplate={() => {}}
isFirst={true}
/>
);
expect(container.firstChild).toMatchSnapshot();
});

it("calls on remove template when clicking remove button", () => {
const onRemoveTemplate = jest.fn();
const { getByTestId } = render(
<ISMTemplate
template={{ index_patterns: ["*"], priority: 5 }}
onUpdateTemplate={() => {}}
onRemoveTemplate={onRemoveTemplate}
isFirst={true}
/>
);
fireEvent.click(getByTestId("ism-template-remove-button"));
expect(onRemoveTemplate).toHaveBeenCalled();
});

it("calls on update template when typing in priority input", async () => {
const template = { index_patterns: ["*"], priority: 7 };
const onUpdateTemplate = jest.fn();
const { getByTestId } = render(
<ISMTemplate template={template} onUpdateTemplate={onUpdateTemplate} onRemoveTemplate={() => {}} isFirst={true} />
);
fireEvent.focus(getByTestId("ism-template-priority-input"));
userEvent.type(getByTestId("ism-template-priority-input"), "2");
fireEvent.blur(getByTestId("ism-template-priority-input"));
expect(onUpdateTemplate).toHaveBeenCalled();
expect(onUpdateTemplate).toHaveBeenCalledWith({ ...template, priority: 72 }); // already contains 7, just added 2
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import React, { ChangeEvent, useState } from "react";
import { EuiButton, EuiFormRow, EuiComboBox, EuiFlexGroup, EuiFlexItem, EuiFieldNumber } from "@elastic/eui";
import "brace/theme/github";
import "brace/mode/json";
import { ISMTemplate as ISMTemplateData } from "../../../../../models/interfaces";
import { ISM_TEMPLATE_INPUT_MAX_WIDTH } from "../../utils/constants";

interface ISMTemplateProps {
template: ISMTemplateData;
onUpdateTemplate: (template: ISMTemplateData) => void;
onRemoveTemplate: () => void;
isFirst: boolean;
}

const ISMTemplate = ({ template, onUpdateTemplate, onRemoveTemplate, isFirst }: ISMTemplateProps) => {
// TODO: Move this top top of form submition
const [isInvalid, setInvalid] = useState(false);
return (
<EuiFlexGroup gutterSize="l" alignItems="center">
<EuiFlexItem style={{ maxWidth: ISM_TEMPLATE_INPUT_MAX_WIDTH }}>
<EuiFormRow isInvalid={false} error={null}>
<EuiComboBox
placeholder="Add index patterns"
noSuggestions
selectedOptions={template.index_patterns.map((pattern) => ({ label: pattern }))}
onChange={(selectedOptions) => {
onUpdateTemplate({ ...template, index_patterns: selectedOptions.map(({ label }) => label) });
setInvalid(false);
}}
onCreateOption={(searchValue) => {
if (!searchValue.trim()) {
return false;
}

if (searchValue.includes(" ")) {
setInvalid(false);
return;
}

onUpdateTemplate({ ...template, index_patterns: [...template.index_patterns, searchValue] });
}}
onSearchChange={(searchValue) => {
if (!searchValue) {
setInvalid(false);

return;
}

if (searchValue.includes(" ")) {
setInvalid(true);
return;
}
//TODO
setInvalid(false);
}}
isClearable={true}
isInvalid={isInvalid}
data-test-subj="ism-template-index-pattern-input"
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow error={null} isInvalid={false}>
<EuiFieldNumber
value={template.priority}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
const priority = e.target.valueAsNumber;
onUpdateTemplate({ ...template, priority });
}}
isInvalid={false}
data-test-subj="ism-template-priority-input"
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton color="danger" onClick={onRemoveTemplate} data-test-subj="ism-template-remove-button">
Remove
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
);
};

export default ISMTemplate;
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<ISMTemplate /> spec renders the component 1`] = `
<div
class="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow euiFlexGroup--responsive"
>
<div
class="euiFlexItem"
style="max-width: 400px;"
>
<div
class="euiFormRow"
id="some_html_id-row"
>
<div
class="euiFormRow__fieldWrapper"
>
<div
aria-expanded="false"
aria-haspopup="listbox"
class="euiComboBox"
data-test-subj="ism-template-index-pattern-input"
role="combobox"
>
<div
class="euiFormControlLayout"
>
<div
class="euiFormControlLayout__childrenWrapper"
>
<div
class="euiComboBox__inputWrap euiComboBox__inputWrap-isClearable"
data-test-subj="comboBoxInput"
tabindex="-1"
>
<span
class="euiBadge euiBadge--hollow euiBadge--iconRight euiComboBoxPill"
title="*"
>
<span
class="euiBadge__content"
>
<span
class="euiBadge__text"
>
*
</span>
<button
aria-label="Remove * from selection in this group"
class="euiBadge__iconButton"
title="Remove * from selection in this group"
>
EuiIconMock
</button>
</span>
</span>
<div
class="euiComboBox__input"
style="font-size: 14px; display: inline-block;"
>
<input
aria-controls=""
data-test-subj="comboBoxSearchInput"
id="some_html_id"
role="textbox"
style="box-sizing: content-box; width: 2px;"
value=""
/>
<div
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
/>
</div>
</div>
<div
class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right"
>
<button
aria-label="Clear input"
class="euiFormControlLayoutClearButton"
data-test-subj="comboBoxClearButton"
type="button"
>
EuiIconMock
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<div
class="euiFormRow"
id="some_html_id-row"
>
<div
class="euiFormRow__fieldWrapper"
>
<div
class="euiFormControlLayout"
>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
class="euiFieldNumber"
data-test-subj="ism-template-priority-input"
id="some_html_id"
type="number"
value="5"
/>
</div>
</div>
</div>
</div>
</div>
<div
class="euiFlexItem euiFlexItem--flexGrowZero"
>
<button
class="euiButton euiButton--danger"
data-test-subj="ism-template-remove-button"
type="button"
>
<span
class="euiButtonContent euiButton__content"
>
<span
class="euiButton__text"
>
Remove
</span>
</span>
</button>
</div>
</div>
`;
14 changes: 14 additions & 0 deletions public/pages/VisualCreatePolicy/components/ISMTemplate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import ISMTemplate from "./ISMTemplate";

export default ISMTemplate;

0 comments on commit c70a926

Please sign in to comment.