Skip to content

Commit d9e697c

Browse files
authored
Add interfaces & types; fetch reactflow state from workflow redux store (#45)
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 8980cb2 commit d9e697c

21 files changed

+176
-134
lines changed

common/helpers.ts

-74
This file was deleted.

common/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@
55

66
export * from './constants';
77
export * from './interfaces';
8-
export * from './helpers';
98
export { IComponent } from '../public/component_types';

common/interfaces.ts

+68-10
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,77 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
/**
7-
* Interfaces here are primarily used for standardizing the data across
8-
* server & client side
9-
*/
6+
import { Node, Edge } from 'reactflow';
7+
import { IComponent as IComponentData } from '../public/component_types';
108

11-
export interface IIndex {
9+
export type Index = {
1210
name: string;
1311
health: 'green' | 'yellow' | 'red';
14-
}
12+
};
1513

16-
// TODO: this will grow as more fields are defined and what frontend reqts there will be
17-
export interface IWorkflow {
18-
name: string;
14+
/**
15+
********** REACTFLOW TYPES/INTERFACES **********
16+
*/
17+
18+
export type ReactFlowComponent = Node<IComponentData>;
19+
20+
// TODO: we may not need this re-defined type here at all, if we don't add
21+
// any special fields/configuration for an edge. Currently this
22+
// is the same as the default Edge type.
23+
export type ReactFlowEdge = Edge<{}> & {};
24+
25+
type ReactFlowViewport = {
26+
x: number;
27+
y: number;
28+
zoom: number;
29+
};
30+
31+
export type ReactFlowState = {
32+
nodes: ReactFlowComponent[];
33+
edges: ReactFlowEdge[];
34+
viewport?: ReactFlowViewport;
35+
};
36+
37+
/**
38+
********** USE CASE TEMPLATE TYPES/INTERFACES **********
39+
*/
40+
41+
type TemplateNode = {
1942
id: string;
43+
inputs: {};
44+
};
45+
46+
type TemplateEdge = {
47+
source: string;
48+
target: string;
49+
};
50+
51+
type TemplateFlow = {
52+
userParams: {};
53+
nodes: TemplateNode[];
54+
edges: TemplateEdge[];
55+
};
56+
57+
type TemplateFlows = {
58+
provision: TemplateFlow;
59+
ingest: TemplateFlow;
60+
query: TemplateFlow;
61+
};
62+
63+
export type UseCaseTemplate = {
64+
type: string;
65+
name: string;
2066
description: string;
21-
}
67+
userInputs: {};
68+
workflows: TemplateFlows;
69+
};
70+
71+
export type Workflow = {
72+
id: string;
73+
name: string;
74+
description?: string;
75+
// ReactFlow state may not exist if a workflow is created via API/backend-only.
76+
reactFlowState?: ReactFlowState;
77+
template: UseCaseTemplate;
78+
lastUpdated: number;
79+
};

eslintrc.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"rules": {
3+
"@typescript-eslint/consistent-type-definitions": "off",
4+
"@typescript-eslint/no-empty-interface": "off",
5+
"react-hooks/exhaustive-deps": "off"
6+
}
7+
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"plugin-helpers": "../../scripts/use_node ../../scripts/plugin_helpers",
1313
"osd": "../../scripts/use_node ../../scripts/osd",
1414
"opensearch": "../../scripts/use_node ../../scripts/opensearch",
15-
"lint:es": "../../scripts/use_node ../../scripts/eslint",
15+
"lint:es": "../../scripts/use_node ../../scripts/eslint -c eslintrc.json",
1616
"lint:es:precommit": "yarn lint:es common/* public/* server/*",
1717
"build": "yarn plugin-helpers build && echo Renaming artifact to $npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip && mv ./build/$npm_package_config_plugin_name*.zip ./build/$npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip"
1818
},

public/app.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
WorkflowDetailRouterProps,
1616
} from './pages';
1717

18-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
1918
interface Props extends RouteComponentProps {}
2019

2120
export const AiFlowDashboardsApp = (props: Props) => {

public/component_types/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
export * from './base_interfaces';
6+
export * from './interfaces';
77
export * from './processors';
88
export * from './indices';

public/component_types/indices/knn_index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
IComponentOutput,
1212
UIFlow,
1313
BaseClass,
14-
} from '../base_interfaces';
14+
} from '../interfaces';
1515

1616
/**
1717
* A k-NN index UI component
File renamed without changes.

public/component_types/processors/text_embedding_processor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
IComponentOutput,
1212
UIFlow,
1313
BaseClass,
14-
} from '../base_interfaces';
14+
} from '../interfaces';
1515

1616
/**
1717
* A text embedding processor UI component

public/pages/workflow_detail/components/header.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
import React from 'react';
77
import { EuiPageHeader, EuiButton } from '@elastic/eui';
8-
import { IWorkflow } from '../../../../common';
8+
import { Workflow } from '../../../../common';
99

1010
interface WorkflowDetailHeaderProps {
11-
workflow: IWorkflow | undefined;
11+
workflow?: Workflow;
1212
}
1313

1414
export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {

public/pages/workflow_detail/workflow_detail.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export interface WorkflowDetailRouterProps {
1717
workflowId: string;
1818
}
1919

20-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
2120
interface WorkflowDetailProps
2221
extends RouteComponentProps<WorkflowDetailRouterProps> {}
2322

@@ -41,7 +40,7 @@ export function WorkflowDetail(props: WorkflowDetailProps) {
4140
<div>
4241
<WorkflowDetailHeader workflow={workflow} />
4342
<EuiSpacer size="l" />
44-
<Workspace />
43+
<Workspace workflow={workflow} />
4544
</div>
4645
);
4746
}

public/pages/workflow_detail/workspace/workspace.tsx

+22-20
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,25 @@ import ReactFlow, {
1111
useEdgesState,
1212
addEdge,
1313
} from 'reactflow';
14-
import { useSelector } from 'react-redux';
1514
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
16-
import { AppState, rfContext } from '../../../store';
17-
import { convertToReactFlowData } from '../../../../common';
15+
import { rfContext } from '../../../store';
16+
import { Workflow } from '../../../../common';
17+
import { getCore } from '../../../services';
1818

1919
// styling
2020
import 'reactflow/dist/style.css';
2121
import './reactflow-styles.scss';
2222

23-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
24-
interface WorkspaceProps {}
23+
interface WorkspaceProps {
24+
workflow?: Workflow;
25+
}
2526

2627
export function Workspace(props: WorkspaceProps) {
2728
const reactFlowWrapper = useRef(null);
2829
const { reactFlowInstance, setReactFlowInstance } = useContext(rfContext);
2930

30-
// Fetching workspace state to populate the initial nodes/edges.
31-
// Where/how the low-level ReactFlow JSON will be persisted is TBD.
32-
// TODO: update when that design is finalized
33-
const storedComponents = useSelector(
34-
(state: AppState) => state.workspace.components
35-
);
36-
const { rfNodes, rfEdges } = convertToReactFlowData(storedComponents);
37-
const [nodes, setNodes, onNodesChange] = useNodesState(rfNodes);
38-
const [edges, setEdges, onEdgesChange] = useEdgesState(rfEdges);
31+
const [nodes, setNodes, onNodesChange] = useNodesState([]);
32+
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
3933

4034
const onConnect = useCallback(
4135
(params) => {
@@ -88,16 +82,24 @@ export function Workspace(props: WorkspaceProps) {
8882

8983
setNodes((nds) => nds.concat(newNode));
9084
},
91-
// eslint-disable-next-line react-hooks/exhaustive-deps
9285
[reactFlowInstance]
9386
);
9487

95-
// Initialization hook
88+
// Initialization. Set the nodes and edges to an existing workflow,
89+
// if applicable.
9690
useEffect(() => {
97-
// TODO: fetch the nodes/edges dynamically (loading existing flow,
98-
// creating fresh from template, creating blank template, etc.)
99-
// Will involve populating and/or fetching from redux store
100-
}, []);
91+
const workflow = props.workflow;
92+
if (workflow) {
93+
if (workflow.reactFlowState) {
94+
setNodes(workflow.reactFlowState.nodes);
95+
setEdges(workflow.reactFlowState.edges);
96+
} else {
97+
getCore().notifications.toasts.addWarning(
98+
`There is no configured UI flow for workflow: ${workflow.name}`
99+
);
100+
}
101+
}
102+
}, [props.workflow]);
101103

102104
return (
103105
<EuiFlexItem grow={true}>

public/pages/workflow_detail/workspace_component/workspace_component.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ interface WorkspaceComponentProps {
2020
}
2121

2222
/**
23-
* TODO: This will be the ReactFlow node in the drag-and-drop workspace. It will take in a component
24-
* from the global workflow state and render it appropriately (inputs / params / outputs / etc.)
23+
* TODO: This will be the ReactFlow node in the drag-and-drop workspace. It will take in the data passed
24+
* to it from the workspace and render it appropriately (inputs / params / outputs / etc.)
2525
* Similar to Flowise's CanvasNode - see
2626
* https://github.com/FlowiseAI/Flowise/blob/main/packages/ui/src/views/canvas/CanvasNode.js
2727
*/

public/pages/workflows/components/columns.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
import React from 'react';
77
import { EuiLink } from '@elastic/eui';
8-
import { PLUGIN_ID, IWorkflow } from '../../../../common';
8+
import { PLUGIN_ID, Workflow } from '../../../../common';
99

1010
export const columns = [
1111
{
1212
field: 'name',
1313
name: 'Name',
1414
sortable: true,
15-
render: (name: string, workflow: IWorkflow) => (
15+
render: (name: string, workflow: Workflow) => (
1616
<EuiLink href={`${PLUGIN_ID}#/workflows/${workflow.id}`}>{name}</EuiLink>
1717
),
1818
},

public/pages/workflows/components/workflow_list.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import React from 'react';
77
import { useSelector } from 'react-redux';
88
import { EuiInMemoryTable, Direction } from '@elastic/eui';
99
import { AppState } from '../../../store';
10-
import { IWorkflow } from '../../../../common';
10+
import { Workflow } from '../../../../common';
1111
import { columns } from './columns';
1212

13-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
1413
interface WorkflowListProps {}
1514

1615
export function WorkflowList(props: WorkflowListProps) {
@@ -24,7 +23,7 @@ export function WorkflowList(props: WorkflowListProps) {
2423
};
2524

2625
return (
27-
<EuiInMemoryTable<IWorkflow>
26+
<EuiInMemoryTable<Workflow>
2827
items={workflows}
2928
rowHeader="name"
3029
columns={columns}

public/store/reducers/opensearch_reducer.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
77
import { getRouteService } from '../../services';
8-
import { IIndex } from '../../../common';
8+
import { Index } from '../../../common';
99

1010
const initialState = {
1111
loading: false,
1212
errorMessage: '',
13-
indices: {} as { [key: string]: IIndex },
13+
indices: {} as { [key: string]: Index },
1414
};
1515

1616
const OPENSEARCH_PREFIX = 'opensearch';
@@ -36,8 +36,8 @@ const opensearchSlice = createSlice({
3636
state.loading = true;
3737
})
3838
.addCase(fetchIndices.fulfilled, (state, action) => {
39-
const indicesMap = new Map<string, IIndex>();
40-
action.payload.forEach((index: IIndex) => {
39+
const indicesMap = new Map<string, Index>();
40+
action.payload.forEach((index: Index) => {
4141
indicesMap.set(index.name, index);
4242
});
4343
state.indices = Object.fromEntries(indicesMap.entries());

0 commit comments

Comments
 (0)