Skip to content

Commit

Permalink
General form improvements (#307) (#308)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
(cherry picked from commit cad5eab)

Co-authored-by: Tyler Ohlsen <ohltyler@amazon.com>
  • Loading branch information
opensearch-trigger-bot[bot] and ohltyler authored Aug 22, 2024
1 parent 7b07a96 commit 5125b3a
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 129 deletions.
3 changes: 2 additions & 1 deletion common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { QueryPreset, WORKFLOW_STATE } from './interfaces';
import { MapEntry, QueryPreset, WORKFLOW_STATE } from './interfaces';
import { customStringify } from './utils';

export const PLUGIN_ID = 'flow-framework';
Expand Down Expand Up @@ -254,6 +254,7 @@ export const MAX_STRING_LENGTH = 100;
export const MAX_JSON_STRING_LENGTH = 10000;
export const MAX_WORKFLOW_NAME_TO_DISPLAY = 40;
export const WORKFLOW_NAME_REGEXP = RegExp('^[a-zA-Z0-9_-]*$');
export const EMPTY_MAP_ENTRY = { key: '', value: '' } as MapEntry;

export enum PROCESSOR_CONTEXT {
INGEST = 'ingest',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@
import React from 'react';
import {
EuiAccordion,
EuiButton,
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiLink,
EuiPanel,
EuiSmallButton,
EuiSmallButtonEmpty,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { Field, FieldProps, getIn, useFormikContext } from 'formik';
import {
EMPTY_MAP_ENTRY,
IConfigField,
MapArrayFormValue,
MapEntry,
Expand Down Expand Up @@ -48,7 +51,7 @@ export function MapArrayField(props: MapArrayFieldProps) {

// Adding a map to the end of the existing arr
function addMap(curMapArray: MapArrayFormValue): void {
setFieldValue(props.fieldPath, [...curMapArray, []]);
setFieldValue(props.fieldPath, [...curMapArray, [EMPTY_MAP_ENTRY]]);
setFieldTouched(props.fieldPath, true);
if (props.onMapAdd) {
props.onMapAdd(curMapArray);
Expand All @@ -72,6 +75,17 @@ export function MapArrayField(props: MapArrayFieldProps) {
return (
<Field name={props.fieldPath}>
{({ field, form }: FieldProps) => {
const isNoMaps = field.value?.length === 0;
const isMultipleMaps = field.value?.length > 1;
const isSingleEmptyMap =
field.value !== undefined &&
field.value.length === 1 &&
field.value[0].length === 0;
const isSinglePopulatedMap =
field.value !== undefined &&
field.value.length === 1 &&
field.value[0].length > 0;

return (
<EuiFormRow
fullWidth={true}
Expand All @@ -94,50 +108,83 @@ export function MapArrayField(props: MapArrayFieldProps) {
getIn(touched, field.name).length > 0
}
>
<EuiFlexGroup direction="column">
{field.value?.map((mapping: MapEntry, idx: number) => {
return (
<EuiFlexItem key={idx}>
<EuiAccordion
key={idx}
id={`accordion${idx}`}
buttonContent={`Prediction ${idx + 1}`}
paddingSize="m"
extraAction={
<EuiButtonIcon
style={{ marginTop: '8px' }}
iconType={'trash'}
color="danger"
aria-label="Delete"
onClick={() => {
deleteMap(field.value, idx);
}}
/>
}
>
<EuiPanel grow={true}>
<MapField
fieldPath={`${props.fieldPath}.${idx}`}
keyPlaceholder={props.keyPlaceholder}
valuePlaceholder={props.valuePlaceholder}
keyOptions={props.keyOptions}
valueOptions={props.valueOptions}
/>
</EuiPanel>
</EuiAccordion>
</EuiFlexItem>
);
})}
<EuiFlexGroup direction="column" gutterSize="none">
{isMultipleMaps ? (
<>
{field.value?.map((mapping: MapEntry, idx: number) => {
return (
<EuiFlexItem key={idx}>
<EuiAccordion
key={idx}
id={`accordion${idx}`}
buttonContent={`Prediction ${idx + 1}`}
paddingSize="m"
extraAction={
<EuiButtonIcon
style={{ marginTop: '8px' }}
iconType={'trash'}
color="danger"
aria-label="Delete"
onClick={() => {
deleteMap(field.value, idx);
}}
/>
}
initialIsOpen={true}
>
<EuiPanel grow={true}>
<MapField
fieldPath={`${props.fieldPath}.${idx}`}
keyPlaceholder={props.keyPlaceholder}
valuePlaceholder={props.valuePlaceholder}
keyOptions={props.keyOptions}
valueOptions={props.valueOptions}
/>
</EuiPanel>
</EuiAccordion>
</EuiFlexItem>
);
})}
</>
) : isSinglePopulatedMap ? (
<>
<EuiPanel grow={true}>
<MapField
fieldPath={`${props.fieldPath}.0`}
keyPlaceholder={props.keyPlaceholder}
valuePlaceholder={props.valuePlaceholder}
keyOptions={props.keyOptions}
valueOptions={props.valueOptions}
/>
</EuiPanel>
<EuiSpacer size="s" />
</>
) : undefined}

<EuiFlexItem grow={false}>
<div>
<EuiButton
size="s"
onClick={() => {
addMap(field.value);
}}
>
{field.value?.length > 0 ? 'Add another map' : 'Add map'}
</EuiButton>
<>
{isNoMaps || isSingleEmptyMap ? (
<EuiSmallButton
onClick={() => {
if (isNoMaps) {
addMap(field.value);
} else {
setFieldValue(`${field.name}.0`, [EMPTY_MAP_ENTRY]);
}
}}
>
{'Configure'}
</EuiSmallButton>
) : (
<EuiSmallButtonEmpty
style={{ marginLeft: '-8px', marginTop: '-4px' }}
onClick={() => {
addMap(field.value);
}}
>{`(Advanced) Add another prediction`}</EuiSmallButtonEmpty>
)}
</>
</div>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

import React from 'react';
import {
EuiButton,
EuiSmallButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiCompressedFormRow,
EuiIcon,
EuiLink,
EuiText,
EuiSmallButton,
} from '@elastic/eui';
import { Field, FieldProps, getIn, useFormikContext } from 'formik';
import { isEmpty } from 'lodash';
Expand Down Expand Up @@ -164,16 +164,13 @@ export function MapField(props: MapFieldProps) {
})}
<EuiFlexItem grow={false}>
<div>
<EuiButton
size="s"
<EuiSmallButton
onClick={() => {
addMapEntry(field.value);
}}
>
{field.value?.length > 0
? 'Add another field mapping'
: 'Add field mapping'}
</EuiButton>
{field.value?.length > 0 ? 'Add more' : 'Add field mapping'}
</EuiSmallButton>
</div>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import React, { useState } from 'react';
import { useFormikContext, getIn } from 'formik';
import { isEmpty } from 'lodash';
import {
EuiButton,
EuiCodeEditor,
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -18,6 +17,7 @@ import {
EuiModalHeaderTitle,
EuiSelect,
EuiSelectOption,
EuiSmallButton,
EuiSpacer,
EuiText,
} from '@elastic/eui';
Expand Down Expand Up @@ -100,7 +100,7 @@ export function InputTransformModal(props: InputTransformModalProps) {
<EuiFlexItem>
<>
<EuiText>Expected input</EuiText>
<EuiButton
<EuiSmallButton
style={{ width: '100px' }}
onClick={async () => {
switch (props.context) {
Expand Down Expand Up @@ -207,7 +207,7 @@ export function InputTransformModal(props: InputTransformModalProps) {
}}
>
Fetch
</EuiButton>
</EuiSmallButton>
<EuiSpacer size="s" />
<EuiCodeEditor
mode="json"
Expand All @@ -230,16 +230,13 @@ export function InputTransformModal(props: InputTransformModalProps) {
<EuiFlexItem>
<>
<EuiText>Define transform</EuiText>
<EuiText size="s" color="subdued">
{`Dot notation is used by default. To explicitly use JSONPath, please ensure to prepend with the
root object selector "${JSONPATH_ROOT_SELECTOR}"`}
</EuiText>
<EuiSpacer size="s" />
<MapArrayField
field={props.inputMapField}
fieldPath={props.inputMapFieldPath}
label="Input Map"
helpText={`An array specifying how to map fields from the ingested document to the model’s input.`}
helpText={`An array specifying how to map fields from the ingested document to the model’s input. Dot notation is used by default. To explicitly use JSONPath, please ensure to prepend with the
root object selector "${JSONPATH_ROOT_SELECTOR}"`}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder="Model input field"
valuePlaceholder={
Expand Down Expand Up @@ -278,7 +275,7 @@ export function InputTransformModal(props: InputTransformModalProps) {
}}
/>
<EuiSpacer size="s" />
<EuiButton
<EuiSmallButton
style={{ width: '100px' }}
disabled={isEmpty(map) || isEmpty(JSON.parse(sourceInput))}
onClick={async () => {
Expand Down Expand Up @@ -306,7 +303,7 @@ export function InputTransformModal(props: InputTransformModalProps) {
}}
>
Generate
</EuiButton>
</EuiSmallButton>
<EuiSpacer size="s" />
<EuiCodeEditor
mode="json"
Expand All @@ -329,9 +326,9 @@ export function InputTransformModal(props: InputTransformModalProps) {
</EuiFlexGroup>
</EuiModalBody>
<EuiModalFooter>
<EuiButton onClick={props.onClose} fill={false} color="primary">
<EuiSmallButton onClick={props.onClose} fill={false} color="primary">
Close
</EuiButton>
</EuiSmallButton>
</EuiModalFooter>
</EuiModal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,13 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiText size="s" color="subdued">
{`Dot notation is used by default. To explicitly use JSONPath, please ensure to prepend with the
root object selector "${JSONPATH_ROOT_SELECTOR}"`}
</EuiText>
<EuiSpacer size="s" />
<MapArrayField
field={inputMapField}
fieldPath={inputMapFieldPath}
label="Input Map"
helpText={`An array specifying how to map fields from the ingested document to the model’s input.`}
helpText={`An array specifying how to map fields from the ingested document to the model’s input. Dot notation is used by default. To explicitly use JSONPath, please ensure to prepend with the
root object selector "${JSONPATH_ROOT_SELECTOR}"`}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder="Model input field"
valuePlaceholder={
Expand Down Expand Up @@ -270,7 +267,8 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
field={outputMapField}
fieldPath={outputMapFieldPath}
label="Output Map"
helpText={`An array specifying how to map the model’s output to new document fields.`}
helpText={`An array specifying how to map the model’s output to new document fields. Dot notation is used by default. To explicitly use JSONPath, please ensure to prepend with the
root object selector "${JSONPATH_ROOT_SELECTOR}"`}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder={
props.context === PROCESSOR_CONTEXT.SEARCH_REQUEST
Expand Down
Loading

0 comments on commit 5125b3a

Please sign in to comment.