Skip to content

Commit

Permalink
Add interfaces & types; fetch reactflow state from workflow redux sto…
Browse files Browse the repository at this point in the history
…re (#45) (#46)

Signed-off-by: Tyler Ohlsen <[email protected]>
(cherry picked from commit d9e697c)

Co-authored-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
opensearch-trigger-bot[bot] and ohltyler committed Oct 2, 2023
1 parent 4d61bf4 commit 8867465
Show file tree
Hide file tree
Showing 21 changed files with 176 additions and 134 deletions.
74 changes: 0 additions & 74 deletions common/helpers.ts

This file was deleted.

1 change: 0 additions & 1 deletion common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@

export * from './constants';
export * from './interfaces';
export * from './helpers';
export { IComponent } from '../public/component_types';
78 changes: 68 additions & 10 deletions common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,77 @@
* SPDX-License-Identifier: Apache-2.0
*/

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

export interface IIndex {
export type Index = {
name: string;
health: 'green' | 'yellow' | 'red';
}
};

// TODO: this will grow as more fields are defined and what frontend reqts there will be
export interface IWorkflow {
name: string;
/**
********** REACTFLOW TYPES/INTERFACES **********
*/

export type ReactFlowComponent = Node<IComponentData>;

// TODO: we may not need this re-defined type here at all, if we don't add
// any special fields/configuration for an edge. Currently this
// is the same as the default Edge type.
export type ReactFlowEdge = Edge<{}> & {};

type ReactFlowViewport = {
x: number;
y: number;
zoom: number;
};

export type ReactFlowState = {
nodes: ReactFlowComponent[];
edges: ReactFlowEdge[];
viewport?: ReactFlowViewport;
};

/**
********** USE CASE TEMPLATE TYPES/INTERFACES **********
*/

type TemplateNode = {
id: string;
inputs: {};
};

type TemplateEdge = {
source: string;
target: string;
};

type TemplateFlow = {
userParams: {};
nodes: TemplateNode[];
edges: TemplateEdge[];
};

type TemplateFlows = {
provision: TemplateFlow;
ingest: TemplateFlow;
query: TemplateFlow;
};

export type UseCaseTemplate = {
type: string;
name: string;
description: string;
}
userInputs: {};
workflows: TemplateFlows;
};

export type Workflow = {
id: string;
name: string;
description?: string;
// ReactFlow state may not exist if a workflow is created via API/backend-only.
reactFlowState?: ReactFlowState;
template: UseCaseTemplate;
lastUpdated: number;
};
7 changes: 7 additions & 0 deletions eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"rules": {
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/no-empty-interface": "off",
"react-hooks/exhaustive-deps": "off"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"plugin-helpers": "../../scripts/use_node ../../scripts/plugin_helpers",
"osd": "../../scripts/use_node ../../scripts/osd",
"opensearch": "../../scripts/use_node ../../scripts/opensearch",
"lint:es": "../../scripts/use_node ../../scripts/eslint",
"lint:es": "../../scripts/use_node ../../scripts/eslint -c eslintrc.json",
"lint:es:precommit": "yarn lint:es common/* public/* server/*",
"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"
},
Expand Down
1 change: 0 additions & 1 deletion public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
WorkflowDetailRouterProps,
} from './pages';

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

export const AiFlowDashboardsApp = (props: Props) => {
Expand Down
2 changes: 1 addition & 1 deletion public/component_types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

export * from './base_interfaces';
export * from './interfaces';
export * from './processors';
export * from './indices';
2 changes: 1 addition & 1 deletion public/component_types/indices/knn_index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
IComponentOutput,
UIFlow,
BaseClass,
} from '../base_interfaces';
} from '../interfaces';

/**
* A k-NN index UI component
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
IComponentOutput,
UIFlow,
BaseClass,
} from '../base_interfaces';
} from '../interfaces';

/**
* A text embedding processor UI component
Expand Down
4 changes: 2 additions & 2 deletions public/pages/workflow_detail/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

import React from 'react';
import { EuiPageHeader, EuiButton } from '@elastic/eui';
import { IWorkflow } from '../../../../common';
import { Workflow } from '../../../../common';

interface WorkflowDetailHeaderProps {
workflow: IWorkflow | undefined;
workflow?: Workflow;
}

export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
Expand Down
3 changes: 1 addition & 2 deletions public/pages/workflow_detail/workflow_detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export interface WorkflowDetailRouterProps {
workflowId: string;
}

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

Expand All @@ -41,7 +40,7 @@ export function WorkflowDetail(props: WorkflowDetailProps) {
<div>
<WorkflowDetailHeader workflow={workflow} />
<EuiSpacer size="l" />
<Workspace />
<Workspace workflow={workflow} />
</div>
);
}
42 changes: 22 additions & 20 deletions public/pages/workflow_detail/workspace/workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,25 @@ import ReactFlow, {
useEdgesState,
addEdge,
} from 'reactflow';
import { useSelector } from 'react-redux';
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
import { AppState, rfContext } from '../../../store';
import { convertToReactFlowData } from '../../../../common';
import { rfContext } from '../../../store';
import { Workflow } from '../../../../common';
import { getCore } from '../../../services';

// styling
import 'reactflow/dist/style.css';
import './reactflow-styles.scss';

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface WorkspaceProps {}
interface WorkspaceProps {
workflow?: Workflow;
}

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

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

const onConnect = useCallback(
(params) => {
Expand Down Expand Up @@ -88,16 +82,24 @@ export function Workspace(props: WorkspaceProps) {

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

// Initialization hook
// Initialization. Set the nodes and edges to an existing workflow,
// if applicable.
useEffect(() => {
// TODO: fetch the nodes/edges dynamically (loading existing flow,
// creating fresh from template, creating blank template, etc.)
// Will involve populating and/or fetching from redux store
}, []);
const workflow = props.workflow;
if (workflow) {
if (workflow.reactFlowState) {
setNodes(workflow.reactFlowState.nodes);
setEdges(workflow.reactFlowState.edges);
} else {
getCore().notifications.toasts.addWarning(
`There is no configured UI flow for workflow: ${workflow.name}`
);
}
}
}, [props.workflow]);

return (
<EuiFlexItem grow={true}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ interface WorkspaceComponentProps {
}

/**
* 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.)
* TODO: This will be the ReactFlow node in the drag-and-drop workspace. It will take in the data passed
* to it from the workspace 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
*/
Expand Down
4 changes: 2 additions & 2 deletions public/pages/workflows/components/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

import React from 'react';
import { EuiLink } from '@elastic/eui';
import { PLUGIN_ID, IWorkflow } from '../../../../common';
import { PLUGIN_ID, Workflow } from '../../../../common';

export const columns = [
{
field: 'name',
name: 'Name',
sortable: true,
render: (name: string, workflow: IWorkflow) => (
render: (name: string, workflow: Workflow) => (
<EuiLink href={`${PLUGIN_ID}#/workflows/${workflow.id}`}>{name}</EuiLink>
),
},
Expand Down
5 changes: 2 additions & 3 deletions public/pages/workflows/components/workflow_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { EuiInMemoryTable, Direction } from '@elastic/eui';
import { AppState } from '../../../store';
import { IWorkflow } from '../../../../common';
import { Workflow } from '../../../../common';
import { columns } from './columns';

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

export function WorkflowList(props: WorkflowListProps) {
Expand All @@ -24,7 +23,7 @@ export function WorkflowList(props: WorkflowListProps) {
};

return (
<EuiInMemoryTable<IWorkflow>
<EuiInMemoryTable<Workflow>
items={workflows}
rowHeader="name"
columns={columns}
Expand Down
8 changes: 4 additions & 4 deletions public/store/reducers/opensearch_reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { getRouteService } from '../../services';
import { IIndex } from '../../../common';
import { Index } from '../../../common';

const initialState = {
loading: false,
errorMessage: '',
indices: {} as { [key: string]: IIndex },
indices: {} as { [key: string]: Index },
};

const OPENSEARCH_PREFIX = 'opensearch';
Expand All @@ -36,8 +36,8 @@ const opensearchSlice = createSlice({
state.loading = true;
})
.addCase(fetchIndices.fulfilled, (state, action) => {
const indicesMap = new Map<string, IIndex>();
action.payload.forEach((index: IIndex) => {
const indicesMap = new Map<string, Index>();
action.payload.forEach((index: Index) => {
indicesMap.set(index.name, index);
});
state.indices = Object.fromEntries(indicesMap.entries());
Expand Down
Loading

0 comments on commit 8867465

Please sign in to comment.