Skip to content

Commit

Permalink
Add invalid workflow state; support JSON doc uploads (#200)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler committed Jun 28, 2024
1 parent 47e5c33 commit 2ef7e05
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 20 deletions.
58 changes: 42 additions & 16 deletions public/pages/workflow_detail/resizable_workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,28 @@

import React, { useRef, useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { Form, Formik } from 'formik';
import * as yup from 'yup';
import { EuiFlexGroup, EuiFlexItem, EuiResizableContainer } from '@elastic/eui';
import { getCore } from '../../services';
import {
EuiCodeBlock,
EuiEmptyPrompt,
EuiFlexGroup,
EuiFlexItem,
EuiResizableContainer,
EuiText,
} from '@elastic/eui';

import {
Workflow,
WorkflowConfig,
WorkflowFormValues,
WorkflowSchema,
} from '../../../common';
import { APP_PATH, uiConfigToFormik, uiConfigToSchema } from '../../utils';
import {
reduceToTemplate,
uiConfigToFormik,
uiConfigToSchema,
} from '../../utils';
import { AppState, setDirty, useAppDispatch } from '../../store';
import { WorkflowInputs } from './workflow_inputs';
import { Workspace } from './workspace';
Expand All @@ -40,7 +49,6 @@ const TOOLS_PANEL_ID = 'tools_panel_id';
*/
export function ResizableWorkspace(props: ResizableWorkspaceProps) {
const dispatch = useAppDispatch();
const history = useHistory();

// Overall workspace state
const { isDirty } = useSelector((state: AppState) => state.workspace);
Expand Down Expand Up @@ -97,20 +105,15 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
setIsToolsPanelOpen(!isToolsPanelOpen);
};

// Hook to update some default values for the workflow, if applicable.
// We need to handle different scenarios:
// 1. Rendering backend-only-created workflow / an existing workflow with no ui_metadata.
// In this case, we revert to the home page with a warn toast that we don't support it, for now.
// 2. Rendering a created workflow with ui_metadata.
// In these cases, just render what is persisted, no action needed.
// workflow state
const [isValidWorkflow, setIsValidWorkflow] = useState<boolean>(true);

// Hook to check if the workflow is valid or not
useEffect(() => {
const missingUiFlow =
props.workflow && !props.workflow?.ui_metadata?.config;
if (missingUiFlow) {
history.replace(APP_PATH.WORKFLOWS);
getCore().notifications.toasts.addWarning(
`There is no ui_metadata for workflow: ${props.workflow?.name}`
);
setIsValidWorkflow(false);
} else {
setWorkflow(props.workflow);
}
Expand Down Expand Up @@ -143,7 +146,7 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
}
}

return (
return isValidWorkflow ? (
<Formik
enableReinitialize={true}
initialValues={formValues}
Expand Down Expand Up @@ -282,5 +285,28 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
</Form>
)}
</Formik>
) : (
<>
<EuiEmptyPrompt
iconType={'cross'}
title={<h2>Unable to view workflow details</h2>}
titleSize="s"
body={
<>
<EuiText>
Only valid workflows created from this OpenSearch Dashboards
application are editable and viewable.
</EuiText>
</>
}
/>
<EuiCodeBlock language="json" fontSize="m" isCopyable={false}>
{JSON.stringify(
reduceToTemplate(props.workflow as Workflow),
undefined,
2
)}
</EuiCodeBlock>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ interface IngestInputsProps {
* The base component containing all of the ingest-related inputs
*/
export function IngestInputs(props: IngestInputsProps) {
// TODO: add some toggle to enable/disable ingest altogether.
// UX not finalized on where that will live currently
return (
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

import React, { useEffect } from 'react';
import { useFormikContext } from 'formik';
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import {
EuiFilePicker,
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
} from '@elastic/eui';
import { JsonField } from '../input_fields';
import { IConfigField, WorkspaceFormValues } from '../../../../../common';

Expand All @@ -18,7 +23,15 @@ interface SourceDataProps {
* Input component for configuring the source data for ingest.
*/
export function SourceData(props: SourceDataProps) {
const { values } = useFormikContext<WorkspaceFormValues>();
const { values, setFieldValue } = useFormikContext<WorkspaceFormValues>();

// files state. when a file is read, update the form value.
const fileReader = new FileReader();
fileReader.onload = (e) => {
if (e.target) {
setFieldValue('ingest.docs', e.target.result);
}
};

// Hook to listen when the docs form value changes.
// Try to set the ingestDocs if possible
Expand All @@ -35,6 +48,19 @@ export function SourceData(props: SourceDataProps) {
<h2>Source data</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFilePicker
accept="application/json"
multiple={false}
initialPromptText="Select a JSON file containing documents"
onChange={(files) => {
if (files && files.length > 0) {
fileReader.readAsText(files[0]);
}
}}
display="default"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<JsonField
// We want to integrate docs into the form, but not persist in the config.
Expand Down

0 comments on commit 2ef7e05

Please sign in to comment.