diff --git a/public/component_types/base_interfaces.ts b/public/component_types/base_interfaces.ts
index 5f761c42..76127dd1 100644
--- a/public/component_types/base_interfaces.ts
+++ b/public/component_types/base_interfaces.ts
@@ -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 ****************
diff --git a/public/component_types/indices/knn_index.ts b/public/component_types/indices/knn_index.ts
index 8b239180..70978071 100644
--- a/public/component_types/indices/knn_index.ts
+++ b/public/component_types/indices/knn_index.ts
@@ -13,6 +13,9 @@ import {
BaseClass,
} from '../base_interfaces';
+/**
+ * A k-NN index UI component
+ */
export class KnnIndex implements IComponent {
id: string;
type: BaseClass;
@@ -25,7 +28,7 @@ export class KnnIndex implements IComponent {
baseClasses: BaseClass[];
inputs: IComponentInput[];
fields: IComponentField[];
- inputFields: IComponentField[];
+ createFields: IComponentField[];
outputs: IComponentOutput[];
constructor() {
@@ -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,
@@ -64,6 +67,7 @@ export class KnnIndex implements IComponent {
{
label: 'Mappings',
type: 'json',
+ placeholder: 'Enter an index mappings JSON blob...',
optional: false,
advanced: false,
},
diff --git a/public/component_types/processors/text_embedding_processor.ts b/public/component_types/processors/text_embedding_processor.ts
index 939b0efa..1000bdbe 100644
--- a/public/component_types/processors/text_embedding_processor.ts
+++ b/public/component_types/processors/text_embedding_processor.ts
@@ -13,6 +13,9 @@ import {
BaseClass,
} from '../base_interfaces';
+/**
+ * A text embedding processor UI component
+ */
export class TextEmbeddingProcessor implements IComponent {
id: string;
type: BaseClass;
diff --git a/public/pages/workflow_builder/components/index.ts b/public/pages/workflow_builder/components/index.ts
new file mode 100644
index 00000000..e2edf8bd
--- /dev/null
+++ b/public/pages/workflow_builder/components/index.ts
@@ -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';
diff --git a/public/pages/workflow_builder/components/json_field.tsx b/public/pages/workflow_builder/components/json_field.tsx
new file mode 100644
index 00000000..1ff51305
--- /dev/null
+++ b/public/pages/workflow_builder/components/json_field.tsx
@@ -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 (
+ <>
+
+ {props.label}
+
+
+ >
+ );
+}
diff --git a/public/pages/workflow_builder/components/select_field.tsx b/public/pages/workflow_builder/components/select_field.tsx
new file mode 100644
index 00000000..eaec1c0f
--- /dev/null
+++ b/public/pages/workflow_builder/components/select_field.tsx
@@ -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: my-index-1,
+ disabled: false,
+ },
+ {
+ value: 'index-2',
+ inputDisplay: my-index-2,
+ disabled: false,
+ },
+] as Array>;
+
+/**
+ * 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(
+ options[0].value
+ );
+
+ const onChange = (option: string) => {
+ setSelectedOption(option);
+ };
+
+ return (
+ onChange(option)}
+ />
+ );
+}
diff --git a/public/pages/workflow_builder/components/text_field.tsx b/public/pages/workflow_builder/components/text_field.tsx
new file mode 100644
index 00000000..b22635db
--- /dev/null
+++ b/public/pages/workflow_builder/components/text_field.tsx
@@ -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 (
+
+ );
+}
diff --git a/public/pages/workflow_builder/workflow_builder.tsx b/public/pages/workflow_builder/workflow_builder.tsx
index 22f97225..645f9129 100644
--- a/public/pages/workflow_builder/workflow_builder.tsx
+++ b/public/pages/workflow_builder/workflow_builder.tsx
@@ -9,7 +9,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
- EuiText,
EuiSpacer,
} from '@elastic/eui';
import { BREADCRUMBS } from '../../utils';
@@ -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(),
diff --git a/public/pages/workflow_builder/workflow_component.tsx b/public/pages/workflow_builder/workflow_component.tsx
index cdffe13b..11cb5e20 100644
--- a/public/pages/workflow_builder/workflow_component.tsx
+++ b/public/pages/workflow_builder/workflow_component.tsx
@@ -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('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 (
-
- {component.fields?.map((field, idx) => {
+
+ {component.allowsCreation ? (
+
+ {inputTabs.map((tab, idx) => {
+ return (
+ onSelectedTabChanged(tab.id)}
+ isSelected={tab.id === selectedTabId}
+ disabled={tab.disabled}
+ key={idx}
+ >
+ {tab.name}
+
+ );
+ })}
+
+ ) : undefined}
+
+
+ {fieldsToDisplay?.map((field, idx) => {
if (field.type === 'string') {
return (
-
);
+ } else if (field.type === 'json') {
+ return (
+
+
+
+ );
+ } else if (field.type === 'select') {
+ return (
+
+
+
+ );
}
})}
-
+ {/**
+ * Hardcoding the interfaced inputs/outputs for readability
+ * TODO: remove when moving this into the context of a ReactFlow node with Handles.
+ */}
+
<>
Inputs:
@@ -68,4 +128,4 @@ export const WorkflowComponent = (props: WorkflowComponentProps) => {
);
-};
+}