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

General form improvements #307

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading