diff --git a/public/pages/workflows/workflow_list/columns.tsx b/public/pages/workflows/workflow_list/columns.tsx index 6de07fb6..f4079893 100644 --- a/public/pages/workflows/workflow_list/columns.tsx +++ b/public/pages/workflows/workflow_list/columns.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiLink } from '@elastic/eui'; import { PLUGIN_ID, Workflow } from '../../../../common'; -export const columns = [ +export const columns = (actions: any[]) => [ { field: 'name', name: 'Name', @@ -36,4 +36,8 @@ export const columns = [ name: 'Last launched', sortable: true, }, + { + name: 'Actions', + actions, + }, ]; diff --git a/public/pages/workflows/workflow_list/workflow_list.tsx b/public/pages/workflows/workflow_list/workflow_list.tsx index 26a48477..0f6c3fa0 100644 --- a/public/pages/workflows/workflow_list/workflow_list.tsx +++ b/public/pages/workflows/workflow_list/workflow_list.tsx @@ -4,7 +4,7 @@ */ import React, { useState, useEffect } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { debounce } from 'lodash'; import { EuiInMemoryTable, @@ -13,8 +13,9 @@ import { EuiFlexItem, EuiFilterSelectItem, EuiFieldSearch, + EuiLoadingSpinner, } from '@elastic/eui'; -import { AppState } from '../../../store'; +import { AppState, deleteWorkflow } from '../../../store'; import { Workflow } from '../../../../common'; import { columns } from './columns'; import { MultiSelectFilter } from '../../../general_components'; @@ -33,7 +34,10 @@ const sorting = { * The searchable list of created workflows. */ export function WorkflowList(props: WorkflowListProps) { - const { workflows } = useSelector((state: AppState) => state.workflows); + const dispatch = useDispatch(); + const { workflows, loading } = useSelector( + (state: AppState) => state.workflows + ); // search bar state const [searchQuery, setSearchQuery] = useState(''); @@ -58,6 +62,19 @@ export function WorkflowList(props: WorkflowListProps) { ); }, [selectedStates, searchQuery, workflows]); + const tableActions = [ + { + name: 'Delete', + description: 'Delete this workflow', + type: 'icon', + icon: 'trash', + color: 'danger', + onClick: (item: Workflow) => { + dispatch(deleteWorkflow(item.id)); + }, + }, + ]; + return ( @@ -80,10 +97,18 @@ export function WorkflowList(props: WorkflowListProps) { items={filteredWorkflows} rowHeader="name" - columns={columns} + // @ts-ignore + columns={columns(tableActions)} sorting={sorting} pagination={true} - message={'No existing workflows found'} + message={ + loading === true ? ( + + ) : ( + 'No existing workflows found' + ) + } + hasActions={true} /> diff --git a/public/pages/workflows/workflows.tsx b/public/pages/workflows/workflows.tsx index f05573ab..92d7535f 100644 --- a/public/pages/workflows/workflows.tsx +++ b/public/pages/workflows/workflows.tsx @@ -72,6 +72,13 @@ export function Workflows(props: WorkflowsProps) { } }, [selectedTabId, workflows]); + // If the user navigates back to the manage tab, re-fetch workflows + useEffect(() => { + if (selectedTabId === WORKFLOWS_TAB.MANAGE) { + dispatch(searchWorkflows({ query: { match_all: {} } })); + } + }, [selectedTabId]); + useEffect(() => { getCore().chrome.setBreadcrumbs([ BREADCRUMBS.FLOW_FRAMEWORK, diff --git a/public/store/reducers/workflows_reducer.ts b/public/store/reducers/workflows_reducer.ts index 40c80c70..93f22e89 100644 --- a/public/store/reducers/workflows_reducer.ts +++ b/public/store/reducers/workflows_reducer.ts @@ -233,12 +233,8 @@ const workflowsSlice = createSlice({ state.errorMessage = ''; }) .addCase(deleteWorkflow.fulfilled, (state, action) => { - // TODO: add logic to mutate state - // const workflow = action.payload; - // state.workflows = { - // ...state.workflows, - // [workflow.id]: workflow, - // }; + const workflowId = action.payload.id; + delete state.workflows[workflowId]; state.loading = false; state.errorMessage = ''; }) diff --git a/server/routes/flow_framework_routes_service.ts b/server/routes/flow_framework_routes_service.ts index 149997d5..afcda1fc 100644 --- a/server/routes/flow_framework_routes_service.ts +++ b/server/routes/flow_framework_routes_service.ts @@ -172,15 +172,12 @@ export class FlowFrameworkRoutesService { const response = await this.client .asScoped(req) .callAsCurrentUser('flowFramework.createWorkflow', { body }); - console.log('response from create workflow: ', response); - // TODO: format response - return res.ok({ body: response }); + return res.ok({ body: { id: response._id } }); } catch (err: any) { return generateCustomError(res, err); } }; - // TODO: test e2e deleteWorkflow = async ( context: RequestHandlerContext, req: OpenSearchDashboardsRequest, @@ -191,9 +188,7 @@ export class FlowFrameworkRoutesService { const response = await this.client .asScoped(req) .callAsCurrentUser('flowFramework.deleteWorkflow', { workflow_id }); - console.log('response from delete workflow: ', response); - // TODO: format response - return res.ok({ body: response }); + return res.ok({ body: { id: response._id } }); } catch (err: any) { return generateCustomError(res, err); } diff --git a/server/routes/helpers.ts b/server/routes/helpers.ts index 9a47fb82..49283de3 100644 --- a/server/routes/helpers.ts +++ b/server/routes/helpers.ts @@ -50,16 +50,18 @@ export function getWorkflowsFromResponses( const workflowStateHit = workflowStateHits.find( (workflowStateHit) => workflowStateHit._id === workflowHit._id ); - const workflowState = workflowStateHit._source - .state as typeof WORKFLOW_STATE; - workflowDict[workflowHit._id] = { - ...workflowDict[workflowHit._id], - // @ts-ignore - state: WORKFLOW_STATE[workflowState], - // TODO: this needs to be persisted by backend. Tracking issue: - // https://github.com/opensearch-project/flow-framework/issues/548 - lastLaunched: 1234, - }; + if (workflowStateHit) { + const workflowState = workflowStateHit._source + .state as typeof WORKFLOW_STATE; + workflowDict[workflowHit._id] = { + ...workflowDict[workflowHit._id], + // @ts-ignore + state: WORKFLOW_STATE[workflowState], + // TODO: this needs to be persisted by backend. Tracking issue: + // https://github.com/opensearch-project/flow-framework/issues/548 + lastLaunched: 1234, + }; + } }); return workflowDict; }