Skip to content

Commit 569b500

Browse files
committed
Get working with flow framework API
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent cc381ad commit 569b500

File tree

8 files changed

+111
-48
lines changed

8 files changed

+111
-48
lines changed

public/pages/workflow_detail/workflow_detail.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ function replaceActiveTab(activeTab: string, props: WorkflowDetailProps) {
4949
export function WorkflowDetail(props: WorkflowDetailProps) {
5050
const { workflows } = useSelector((state: AppState) => state.workflows);
5151

52-
const workflow = workflows.find(
53-
(wf) => wf.id === props.match?.params?.workflowId
54-
);
52+
const workflow = workflows[props.match?.params?.workflowId];
5553
const workflowName = workflow ? workflow.name : '';
5654

5755
const tabFromUrl = queryString.parse(useLocation().search)[

public/pages/workflows/workflow_list/workflow_list.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const sorting = {
3434
*/
3535
export function WorkflowList(props: WorkflowListProps) {
3636
const { workflows } = useSelector((state: AppState) => state.workflows);
37+
const workflowsAsList = Object.values(workflows);
3738

3839
// search bar state
3940
const [searchQuery, setSearchQuery] = useState<string>('');
@@ -46,13 +47,13 @@ export function WorkflowList(props: WorkflowListProps) {
4647
getStateOptions()
4748
);
4849
const [filteredWorkflows, setFilteredWorkflows] = useState<Workflow[]>(
49-
workflows || []
50+
workflowsAsList || []
5051
);
5152

5253
// When a filter selection or search query changes, update the list
5354
useEffect(() => {
5455
setFilteredWorkflows(
55-
fetchFilteredWorkflows(workflows, selectedStates, searchQuery)
56+
fetchFilteredWorkflows(workflowsAsList, selectedStates, searchQuery)
5657
);
5758
}, [selectedStates, searchQuery]);
5859

public/pages/workflows/workflows.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import {
1414
EuiSpacer,
1515
} from '@elastic/eui';
1616
import queryString from 'query-string';
17-
import { useSelector } from 'react-redux';
17+
import { useDispatch, useSelector } from 'react-redux';
1818
import { BREADCRUMBS } from '../../utils';
1919
import { getCore } from '../../services';
2020
import { WorkflowList } from './workflow_list';
2121
import { NewWorkflow } from './new_workflow';
22-
import { AppState } from '../../store';
22+
import { AppState, getWorkflow } from '../../store';
2323

2424
export interface WorkflowsRouterProps {}
2525

@@ -47,6 +47,7 @@ function replaceActiveTab(activeTab: string, props: WorkflowsProps) {
4747
* to get started on a new workflow.
4848
*/
4949
export function Workflows(props: WorkflowsProps) {
50+
const dispatch = useDispatch();
5051
const { workflows } = useSelector((state: AppState) => state.workflows);
5152

5253
const tabFromUrl = queryString.parse(useLocation().search)[
@@ -61,7 +62,7 @@ export function Workflows(props: WorkflowsProps) {
6162
!selectedTabId ||
6263
!Object.values(WORKFLOWS_TAB).includes(selectedTabId)
6364
) {
64-
if (workflows?.length > 0) {
65+
if (Object.keys(workflows).length > 0) {
6566
setSelectedTabId(WORKFLOWS_TAB.MANAGE);
6667
replaceActiveTab(WORKFLOWS_TAB.MANAGE, props);
6768
} else {
@@ -78,6 +79,10 @@ export function Workflows(props: WorkflowsProps) {
7879
]);
7980
});
8081

82+
useEffect(() => {
83+
dispatch(getWorkflow('dummy-id'));
84+
}, []);
85+
8186
return (
8287
<EuiPage>
8388
<EuiPageBody>

public/route_service.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,30 @@
44
*/
55

66
import { CoreStart, HttpFetchError } from '../../../src/core/public';
7-
import { FETCH_INDICES_PATH, SEARCH_INDICES_PATH } from '../common';
7+
import {
8+
FETCH_INDICES_PATH,
9+
GET_WORKFLOW_PATH,
10+
SEARCH_INDICES_PATH,
11+
} from '../common';
812

913
export interface RouteService {
14+
getWorkflow: (workflowId: string) => Promise<any | HttpFetchError>;
1015
searchIndex: (indexName: string, body: {}) => Promise<any | HttpFetchError>;
1116
fetchIndices: (pattern: string) => Promise<any | HttpFetchError>;
1217
}
1318

1419
export function configureRoutes(core: CoreStart): RouteService {
1520
return {
21+
getWorkflow: async (workflowId: string) => {
22+
try {
23+
const response = await core.http.get<{ respString: string }>(
24+
`${GET_WORKFLOW_PATH}/${workflowId}`
25+
);
26+
return response;
27+
} catch (e: any) {
28+
return e as HttpFetchError;
29+
}
30+
},
1631
searchIndex: async (indexName: string, body: {}) => {
1732
try {
1833
const response = await core.http.get<{ respString: string }>(

public/store/reducers/opensearch_reducer.ts

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const opensearchSlice = createSlice({
4343
builder
4444
.addCase(fetchIndices.pending, (state, action) => {
4545
state.loading = true;
46+
state.errorMessage = '';
4647
})
4748
.addCase(fetchIndices.fulfilled, (state, action) => {
4849
const indicesMap = new Map<string, Index>();
@@ -51,6 +52,7 @@ const opensearchSlice = createSlice({
5152
});
5253
state.indices = Object.fromEntries(indicesMap.entries());
5354
state.loading = false;
55+
state.errorMessage = '';
5456
})
5557
.addCase(fetchIndices.rejected, (state, action) => {
5658
state.errorMessage = action.payload as string;

public/store/reducers/workflows_reducer.ts

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

6-
import { createSlice } from '@reduxjs/toolkit';
6+
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
77
import {
88
Workflow,
99
ReactFlowComponent,
@@ -14,8 +14,10 @@ import {
1414
initComponentData,
1515
WORKFLOW_STATE,
1616
} from '../../../common';
17+
import { HttpFetchError } from '../../../../../src/core/public';
18+
import { getRouteService } from '../../services';
1719

18-
// TODO: remove after fetching from server-side
20+
// TODO: remove hardcoded initial state below after fetching from server side
1921
const id1 = generateId('text_embedding_processor');
2022
const id2 = generateId('text_embedding_processor');
2123
const id3 = generateId('knn_index');
@@ -40,47 +42,86 @@ const dummyNodes = [
4042
},
4143
] as ReactFlowComponent[];
4244

45+
let workflows = {} as { [workflowId: string]: Workflow };
46+
workflows['workflow-1-id'] = {
47+
name: 'Workflow-1',
48+
id: 'workflow-1-id',
49+
description: 'description for workflow 1',
50+
state: WORKFLOW_STATE.SUCCEEDED,
51+
workspaceFlowState: {
52+
nodes: dummyNodes,
53+
edges: [] as ReactFlowEdge[],
54+
},
55+
template: {},
56+
} as Workflow;
57+
workflows['workflow-2-id'] = {
58+
name: 'Workflow-2',
59+
id: 'workflow-2-id',
60+
description: 'description for workflow 2',
61+
state: WORKFLOW_STATE.FAILED,
62+
workspaceFlowState: {
63+
nodes: dummyNodes,
64+
edges: [] as ReactFlowEdge[],
65+
},
66+
template: {},
67+
} as Workflow;
68+
4369
const initialState = {
44-
// TODO: fetch from server-side later
45-
workflows: [
46-
{
47-
name: 'Workflow-1',
48-
id: 'workflow-1-id',
49-
description: 'description for workflow 1',
50-
state: WORKFLOW_STATE.SUCCEEDED,
51-
workspaceFlowState: {
52-
nodes: dummyNodes,
53-
edges: [] as ReactFlowEdge[],
54-
},
55-
template: {},
56-
},
57-
{
58-
name: 'Workflow-2',
59-
id: 'workflow-2-id',
60-
description: 'description for workflow 2',
61-
state: WORKFLOW_STATE.FAILED,
62-
workspaceFlowState: {
63-
nodes: dummyNodes,
64-
edges: [] as ReactFlowEdge[],
65-
},
66-
template: {},
67-
},
68-
] as Workflow[],
6970
loading: false,
71+
errorMessage: '',
72+
workflows,
7073
};
7174

75+
// TODO: uncomment when workflow fetching is working
76+
// const initialState = {
77+
// loading: false,
78+
// errorMessage: '',
79+
// workflows: {} as { [workflowId: string]: Workflow },
80+
// };
81+
82+
const WORKFLOWS_PREFIX = 'workflows';
83+
const GET_WORKFLOW_ACTION = `${WORKFLOWS_PREFIX}/getWorkflow`;
84+
85+
export const getWorkflow = createAsyncThunk(
86+
GET_WORKFLOW_ACTION,
87+
async (workflowId: string, { rejectWithValue }) => {
88+
const response: any | HttpFetchError = await getRouteService().getWorkflow(
89+
workflowId
90+
);
91+
if (response instanceof HttpFetchError) {
92+
return rejectWithValue(
93+
'Error getting workflow: ' + response.body.message
94+
);
95+
} else {
96+
return response;
97+
}
98+
}
99+
);
100+
72101
const workflowsSlice = createSlice({
73102
name: 'workflows',
74103
initialState,
75-
reducers: {
76-
setWorkflows(state, action) {
77-
state.workflows = action.payload;
78-
},
79-
setLoading(state, action) {
80-
state.loading = action.payload;
81-
},
104+
reducers: {},
105+
extraReducers: (builder) => {
106+
builder
107+
.addCase(getWorkflow.pending, (state, action) => {
108+
state.loading = true;
109+
state.errorMessage = '';
110+
})
111+
.addCase(getWorkflow.fulfilled, (state, action) => {
112+
const workflow = action.payload;
113+
state.workflows = {
114+
...state.workflows,
115+
[workflow.id]: workflow,
116+
};
117+
state.loading = false;
118+
state.errorMessage = '';
119+
})
120+
.addCase(getWorkflow.rejected, (state, action) => {
121+
state.errorMessage = action.payload as string;
122+
state.loading = false;
123+
});
82124
},
83125
});
84126

85127
export const workflowsReducer = workflowsSlice.reducer;
86-
export const { setWorkflows, setLoading } = workflowsSlice.actions;

server/cluster/flow_framework_plugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function flowFrameworkPlugin(Client: any, config: any, components: any) {
1111
Client.prototype.flowFramework = components.clientAction.namespaceFactory();
1212
const flowFramework = Client.prototype.flowFramework.prototype;
1313

14-
flowFramework.deleteDetector = ca({
14+
flowFramework.getWorkflow = ca({
1515
url: {
1616
fmt: `${FLOW_FRAMEWORK_WORKFLOW_ROUTE_PREFIX}/<%=workflow_id%>`,
1717
req: {

server/routes/flow_framework_routes_service.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ export function registerFlowFrameworkRoutes(
1818
router: IRouter,
1919
flowFrameworkRoutesService: FlowFrameworkRoutesService
2020
): void {
21-
router.post(
21+
router.get(
2222
{
2323
path: `${GET_WORKFLOW_PATH}/{workflow_id}`,
2424
validate: {
2525
params: schema.object({
26-
index_name: schema.string(),
26+
workflow_id: schema.string(),
2727
}),
28-
body: schema.any(),
2928
},
3029
},
3130
flowFrameworkRoutesService.getWorkflow
@@ -46,8 +45,10 @@ export class FlowFrameworkRoutesService {
4645
): Promise<IOpenSearchDashboardsResponse<any>> => {
4746
// eslint-disable-next-line @typescript-eslint/naming-convention
4847
const { workflow_id } = req.params;
48+
console.log('workflow ID: ', workflow_id);
4949

5050
try {
51+
console.log('making rquest...');
5152
const response = await this.client
5253
.asScoped(req)
5354
.callAsCurrentUser('flowFramework.getWorkflow', { workflow_id });

0 commit comments

Comments
 (0)