Skip to content

Commit

Permalink
Pull out the field components
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler committed Sep 20, 2023
1 parent 02c8453 commit a1c3925
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 26 deletions.
6 changes: 2 additions & 4 deletions public/component_types/base_interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import { COMPONENT_CATEGORY } from '../utils';
* ************ Types **************************
*/

// TODO: may change to enums later
// TODO: may change some/all of these to enums later
export type BaseClass = string;
export type UIFlow = string;

// will expand later on
export type FieldType = 'string' | 'json';
export type FieldType = 'string' | 'json' | 'select';

/**
* ************ Base interfaces ****************
Expand Down
14 changes: 9 additions & 5 deletions public/component_types/indices/knn_index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
BaseClass,
} from '../base_interfaces';

/**
* A k-NN index UI component
*/
export class KnnIndex implements IComponent {
id: string;
type: BaseClass;
Expand All @@ -25,7 +28,7 @@ export class KnnIndex implements IComponent {
baseClasses: BaseClass[];
inputs: IComponentInput[];
fields: IComponentField[];
inputFields: IComponentField[];
createFields: IComponentField[];
outputs: IComponentOutput[];

constructor() {
Expand All @@ -44,15 +47,15 @@ export class KnnIndex implements IComponent {
this.inputs = [];
this.fields = [
{
label: 'Name',
type: 'string',
label: 'Index Name',
type: 'select',
optional: false,
advanced: false,
},
];
this.inputFields = [
this.createFields = [
{
label: 'Name',
label: 'Index Name',
type: 'string',
optional: false,
advanced: false,
Expand All @@ -64,6 +67,7 @@ export class KnnIndex implements IComponent {
{
label: 'Mappings',
type: 'json',
placeholder: 'Enter an index mappings JSON blob...',
optional: false,
advanced: false,
},
Expand Down
3 changes: 3 additions & 0 deletions public/component_types/processors/text_embedding_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
BaseClass,
} from '../base_interfaces';

/**
* A text embedding processor UI component
*/
export class TextEmbeddingProcessor implements IComponent {
id: string;
type: BaseClass;
Expand Down
8 changes: 8 additions & 0 deletions public/pages/workflow_builder/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export { TextField } from './text_field';
export { JsonField } from './json_field';
export { SelectField } from './select_field';
27 changes: 27 additions & 0 deletions public/pages/workflow_builder/components/json_field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { EuiText, EuiTextArea } from '@elastic/eui';

interface JsonFieldProps {
label: string;
placeholder: string;
}

/**
* An input field for a component where users select manually enter
* in some custom JSON
*/
export function JsonField(props: JsonFieldProps) {
return (
<>
<EuiText size="s" className="eui-textLeft">
{props.label}
</EuiText>
<EuiTextArea placeholder={props.placeholder} />
</>
);
}
46 changes: 46 additions & 0 deletions public/pages/workflow_builder/components/select_field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useState } from 'react';
import { EuiSuperSelect, EuiSuperSelectOption, EuiText } from '@elastic/eui';

// TODO: Should be fetched from global state.
// Need to have a way to determine where to fetch this dynamic data.
const existingIndices = [
{
value: 'index-1',
inputDisplay: <EuiText>my-index-1</EuiText>,
disabled: false,
},
{
value: 'index-2',
inputDisplay: <EuiText>my-index-2</EuiText>,
disabled: false,
},
] as Array<EuiSuperSelectOption<string>>;

/**
* An input field for a component where users select from a list of available
* options.
*/
export function SelectField() {
const options = existingIndices;

const [selectedOption, setSelectedOption] = useState<string>(
options[0].value
);

const onChange = (option: string) => {
setSelectedOption(option);
};

return (
<EuiSuperSelect
options={options}
valueOfSelected={selectedOption}
onChange={(option) => onChange(option)}
/>
);
}
25 changes: 25 additions & 0 deletions public/pages/workflow_builder/components/text_field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { EuiFieldText } from '@elastic/eui';

interface TextFieldProps {
label: string;
placeholder: string;
}

/**
* An input field for a component where users input plaintext
*/
export function TextField(props: TextFieldProps) {
return (
<EuiFieldText
prepend={props.label}
compressed={false}
placeholder={props.placeholder || ''}
/>
);
}
2 changes: 1 addition & 1 deletion public/pages/workflow_builder/workflow_builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
EuiText,
EuiSpacer,
} from '@elastic/eui';
import { BREADCRUMBS } from '../../utils';
Expand All @@ -29,6 +28,7 @@ export function WorkflowBuilder() {
]);
});

// TODO: Should be fetched from global state. Using some defaults for testing purposes
const curComponents = [
new TextEmbeddingProcessor(),
new KnnIndex(),
Expand Down
92 changes: 76 additions & 16 deletions public/pages/workflow_builder/workflow_component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,112 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import React, { useState } from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiFieldText,
EuiText,
EuiSpacer,
EuiCard,
EuiTab,
EuiTabs,
} from '@elastic/eui';
import { IComponent } from '../../component_types';
import { JsonField, SelectField, TextField } from './components';

interface WorkflowComponentProps {
component: IComponent;
}

const inputTabs = [
{
id: 'existing',
name: 'Existing',
disabled: false,
},
{
id: 'new',
name: 'New',
disabled: false,
},
];

/**
* This will be the ReactFlow node in the drag-and-drop workspace. It will take in a component
* TODO: This will be the ReactFlow node in the drag-and-drop workspace. It will take in a component
* from the global workflow state and render it appropriately (inputs / params / outputs / etc.)
* Similar to Flowise's CanvasNode - see
* https://github.com/FlowiseAI/Flowise/blob/main/packages/ui/src/views/canvas/CanvasNode.js
*/
export function WorkflowComponent(props: WorkflowComponentProps) {
const { component } = props;

interface WorkflowComponentProps {
component: IComponent;
}
const [selectedTabId, setSelectedTabId] = useState<string>('existing');

// TODO: convert this to a ReactFlow node
export const WorkflowComponent = (props: WorkflowComponentProps) => {
const { component } = props;
const onSelectedTabChanged = (id: string) => {
setSelectedTabId(id);
};

const isCreatingNew = component.allowsCreation && selectedTabId === 'new';
const fieldsToDisplay = isCreatingNew
? component.createFields
: component.fields;

return (
<EuiCard title={component.label} style={{ maxWidth: '40vh' }}>
<EuiFlexGroup direction="column">
<EuiFlexItem grow={8}>
{component.fields?.map((field, idx) => {
<EuiFlexItem>
{component.allowsCreation ? (
<EuiTabs size="s" expand={true}>
{inputTabs.map((tab, idx) => {
return (
<EuiTab
onClick={() => onSelectedTabChanged(tab.id)}
isSelected={tab.id === selectedTabId}
disabled={tab.disabled}
key={idx}
>
{tab.name}
</EuiTab>
);
})}
</EuiTabs>
) : undefined}
</EuiFlexItem>
<EuiFlexItem>
{fieldsToDisplay?.map((field, idx) => {
if (field.type === 'string') {
return (
<EuiFlexItem key={idx}>
<EuiFieldText
prepend={field.label}
compressed={false}
<TextField
label={field.label}
placeholder={field.placeholder || ''}
/>
<EuiSpacer size="s" />
</EuiFlexItem>
);
} else if (field.type === 'json') {
return (
<EuiFlexItem key={idx}>
<JsonField
label={field.label}
placeholder={field.placeholder || ''}
/>
</EuiFlexItem>
);
} else if (field.type === 'select') {
return (
<EuiFlexItem key={idx}>
<SelectField />
</EuiFlexItem>
);
}
})}
</EuiFlexItem>
<EuiFlexItem grow={2}>
{/**
* Hardcoding the interfaced inputs/outputs for readability
* TODO: remove when moving this into the context of a ReactFlow node with Handles.
*/}
<EuiFlexItem>
<>
<EuiText>
<b>Inputs:</b>
Expand All @@ -68,4 +128,4 @@ export const WorkflowComponent = (props: WorkflowComponentProps) => {
</EuiFlexGroup>
</EuiCard>
);
};
}

0 comments on commit a1c3925

Please sign in to comment.