Skip to content

Commit

Permalink
Simplify form navigation (#515)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
(cherry picked from commit d102519)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Dec 7, 2024
1 parent 9a7ad51 commit 138fe60
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 330 deletions.
19 changes: 17 additions & 2 deletions public/pages/workflow_detail/components/export_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
EuiModalBody,
EuiModalFooter,
EuiSmallButtonEmpty,
EuiCallOut,
EuiSpacer,
} from '@elastic/eui';
import {
CREATE_WORKFLOW_LINK,
Expand All @@ -29,6 +31,8 @@ import { reduceToTemplate } from '../../../utils';

interface ExportModalProps {
workflow?: Workflow;
unsavedIngestProcessors: boolean;
unsavedSearchProcessors: boolean;
setIsExportModalOpen(isOpen: boolean): void;
}

Expand Down Expand Up @@ -78,14 +82,25 @@ export function ExportModal(props: ExportModalProps) {
>
<EuiModalHeader>
<EuiModalHeaderTitle>
<p>{`Export ${getCharacterLimitedString(
<p>{`Export '${getCharacterLimitedString(
props.workflow?.name || '',
25
)}`}</p>
)}'`}</p>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiFlexGroup direction="column">
{(props.unsavedIngestProcessors || props.unsavedSearchProcessors) && (
<>
<EuiSpacer size="s" />
<EuiCallOut
size="s"
title="Unsaved configurations detected. Ensure to save and update all resources before exporting."
iconType={'alert'}
color="warning"
/>
</>
)}
<EuiFlexItem grow={false}>
<EuiText size="s">
{`To build out identical resources in other environments, create and provision a workflow using the below template.`}{' '}
Expand Down
2 changes: 2 additions & 0 deletions public/pages/workflow_detail/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
{isExportModalOpen && (
<ExportModal
workflow={props.workflow}
unsavedIngestProcessors={props.unsavedIngestProcessors}
unsavedSearchProcessors={props.unsavedSearchProcessors}
setIsExportModalOpen={setIsExportModalOpen}
/>
)}
Expand Down
1 change: 0 additions & 1 deletion public/pages/workflow_detail/resizable_workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
uiConfig={props.uiConfig}
setUiConfig={props.setUiConfig}
setIngestResponse={setIngestResponse}
setQueryResponse={setQueryResponse}
ingestDocs={props.ingestDocs}
setIngestDocs={props.setIngestDocs}
isRunningIngest={props.isRunningIngest}
Expand Down
18 changes: 10 additions & 8 deletions public/pages/workflow_detail/tools/query/query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export function Query(props: QueryProps) {

// Standalone / sandboxed search request state. Users can test things out
// without updating the base form / persisted value. We default to different values
// based on the context (ingest or search).
// based on the context (ingest or search), and update based on changes to the context
// (ingest v. search), or if the parent form values are changed.
const [tempRequest, setTempRequest] = useState<string>('');
useEffect(() => {
setTempRequest(
Expand All @@ -76,6 +77,14 @@ export function Query(props: QueryProps) {
: values?.search?.request || '{}'
);
}, [props.selectedStep]);
useEffect(() => {
if (
!isEmpty(values?.search?.request) &&
props.selectedStep === CONFIG_STEP.SEARCH
) {
setTempRequest(values?.search?.request);
}
}, [values?.search?.request]);

// state for if to execute search w/ or w/o any configured search pipeline.
// default based on if there is an available search pipeline or not.
Expand All @@ -87,13 +96,6 @@ export function Query(props: QueryProps) {
// query params state
const [queryParams, setQueryParams] = useState<QueryParam[]>([]);

// listen for changes to the upstream / form query, and reset the default
useEffect(() => {
if (!isEmpty(values?.search?.request)) {
setTempRequest(values?.search?.request);
}
}, [values?.search?.request]);

// Do a few things when the request is changed:
// 1. Check if there is a new set of query parameters, and if so,
// reset the form.
Expand Down
13 changes: 3 additions & 10 deletions public/pages/workflow_detail/workflow_detail.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ describe('WorkflowDetail Page with create ingestion option', () => {
expect(
getAllByText((content) => content.startsWith('Last updated:')).length
).toBeGreaterThan(0);
expect(getAllByText('Search pipeline').length).toBeGreaterThan(0);
expect(getByText('Close')).toBeInTheDocument();
expect(getByText('Export')).toBeInTheDocument();
expect(getByText('Visual')).toBeInTheDocument();
Expand All @@ -93,10 +92,6 @@ describe('WorkflowDetail Page with create ingestion option', () => {
expect(getByRole('tab', { name: 'Errors' })).toBeInTheDocument();
expect(getByRole('tab', { name: 'Resources' })).toBeInTheDocument();

// "Run ingestion" button exists
const runIngestionButton = getByTestId('runIngestionButton');
expect(runIngestionButton).toBeInTheDocument();

// "Search pipeline" button should be disabled by default
const searchPipelineButton = getByTestId('searchPipelineButton');
expect(searchPipelineButton).toBeInTheDocument();
Expand All @@ -119,7 +114,7 @@ describe('WorkflowDetail Page Functionality (Custom Workflow)', () => {
// Export button opens the export component
userEvent.click(getByTestId('exportButton'));
await waitFor(() => {
expect(getByText(`Export ${workflowName}`)).toBeInTheDocument();
expect(getByText(`Export '${workflowName}'`)).toBeInTheDocument();
});

// Close the export component
Expand Down Expand Up @@ -179,8 +174,7 @@ describe('WorkflowDetail Page with skip ingestion option (Hybrid Search Workflow
);

// Defining a new ingest pipeline & index is enabled by default
const enabledCheckbox = getByTestId('checkbox-ingest.enabled');
expect(enabledCheckbox).toBeChecked();
const enabledCheckbox = getByTestId('switch-ingest.enabled');

// Skipping ingest pipeline and navigating to search
userEvent.click(enabledCheckbox);
Expand All @@ -190,7 +184,7 @@ describe('WorkflowDetail Page with skip ingestion option (Hybrid Search Workflow

// Search pipeline
await waitFor(() => {
expect(getAllByText('Define search pipeline').length).toBeGreaterThan(0);
expect(getAllByText('Define search flow').length).toBeGreaterThan(0);
});
expect(getAllByText('Configure query').length).toBeGreaterThan(0);

Expand Down Expand Up @@ -224,7 +218,6 @@ describe('WorkflowDetail Page with skip ingestion option (Hybrid Search Workflow
});

// Build and Run query, Back buttons are present
expect(getByTestId('runQueryButton')).toBeInTheDocument();
const searchPipelineBackButton = getByTestId('searchPipelineBackButton');
userEvent.click(searchPipelineBackButton);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function ConfigFieldList(props: ConfigFieldListProps) {
<BooleanField
label={camelCaseToTitleString(field.id)}
fieldPath={fieldPath}
type="Checkbox"
/>
<EuiSpacer size={CONFIG_FIELD_SPACER_SIZE} />
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,27 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiIconTip,
EuiSwitch,
EuiText,
} from '@elastic/eui';

interface BooleanFieldProps {
fieldPath: string; // the full path in string-form to the field (e.g., 'ingest.enrich.processors.text_embedding_processor.inputField')
label: string;
type: ComponentType;
helpText?: string;
}

type ComponentType = 'Checkbox' | 'Switch';

/**
* An input field for a boolean value. Implemented as an EuiCompressedRadioGroup with 2 mutually exclusive options.
*/
export function BooleanField(props: BooleanFieldProps) {
return (
<Field name={props.fieldPath}>
{({ field, form }: FieldProps) => {
return (
return props.type === 'Checkbox' ? (
<EuiCompressedCheckbox
data-testid={`checkbox-${field.name}`}
id={`checkbox-${field.name}`}
Expand All @@ -53,6 +57,33 @@ export function BooleanField(props: BooleanFieldProps) {
form.setFieldTouched(field.name, true);
}}
/>
) : (
<EuiSwitch
data-testid={`switch-${field.name}`}
id={`switch-${field.name}`}
label={
<>
<EuiFlexGroup direction="row">
<EuiFlexItem grow={false}>
<EuiText size="s">{props.label}</EuiText>
</EuiFlexItem>
{props.helpText && (
<EuiFlexItem
grow={false}
style={{ marginLeft: '-8px', marginTop: '10px' }}
>
<EuiIconTip content={props.helpText} position="right" />
</EuiFlexItem>
)}
</EuiFlexGroup>
</>
}
checked={field.value === undefined || field.value === true}
onChange={() => {
form.setFieldValue(field.name, !field.value);
form.setFieldTouched(field.name, true);
}}
/>
);
}}
</Field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ import { WorkflowFormValues } from '../../../../../common';
import { AppState } from '../../../../store';
import { EditQueryModal } from './edit_query_modal';

interface ConfigureSearchRequestProps {
setQuery: (query: string) => void;
setQueryResponse: (queryResponse: string) => void;
}
interface ConfigureSearchRequestProps {}

/**
* Input component for configuring a search request
Expand Down Expand Up @@ -55,14 +52,6 @@ export function ConfigureSearchRequest(props: ConfigureSearchRequestProps) {
// Edit modal state
const [isEditModalOpen, setIsEditModalOpen] = useState<boolean>(false);

// Hook to listen when the query form value changes.
// Try to set the query request if possible
useEffect(() => {
if (values?.search?.request) {
props.setQuery(values.search.request);
}
}, [values?.search?.request]);

return (
<>
{isEditModalOpen && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import { getDataSourceId } from '../../../../utils';
interface SearchInputsProps {
uiConfig: WorkflowConfig;
setUiConfig: (uiConfig: WorkflowConfig) => void;
setQuery: (query: string) => void;
setQueryResponse: (queryResponse: string) => void;
}

/**
Expand All @@ -38,10 +36,7 @@ export function SearchInputs(props: SearchInputsProps) {
return (
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<ConfigureSearchRequest
setQuery={props.setQuery}
setQueryResponse={props.setQueryResponse}
/>
<ConfigureSearchRequest />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiHorizontalRule margin="none" />
Expand Down
Loading

0 comments on commit 138fe60

Please sign in to comment.