Skip to content

Commit

Permalink
Merge pull request #29 from mareklibra/FLPATH-53.select.persist
Browse files Browse the repository at this point in the history
FLPATH-53: Execute workflow
  • Loading branch information
RichardW98 authored Feb 28, 2023
2 parents c62e73f + ab60712 commit c415fd8
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 121 deletions.
27 changes: 19 additions & 8 deletions plugins/orion/src/components/ParodosPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ import { useBackendUrl } from './api';
export const pluginRoutePrefix = '/parodos';

export const navigationMap = [
{ label: 'Projects', route: '/project-overview', icon: <ProjectsIcon /> },
{ label: 'Assessment', route: '/workflow', icon: <AssessmentIcon /> },
{ label: 'Deploy', route: '/Deploy', icon: <DeployIcon /> },
{ label: 'Notification', route: '/notification', icon: <NotificationIcon /> },
{ label: 'Training', route: '/training', icon: <TrainingIcon /> },
{ label: 'Metrics', route: '/metrics', icon: <MetricsIcon /> },
{ label: 'Projects', routes: ['/project-overview'], icon: <ProjectsIcon /> },
{
label: 'Assessment',
routes: ['/workflow', '/onboarding/'],
icon: <AssessmentIcon />,
},

{ label: 'Deploy', routes: ['/Deploy'], icon: <DeployIcon /> },
{
label: 'Notification',
routes: ['/notification'],
icon: <NotificationIcon />,
},
{ label: 'Training', routes: ['/training'], icon: <TrainingIcon /> },
{ label: 'Metrics', routes: ['/metrics'], icon: <MetricsIcon /> },
];

const useStyles = makeStyles({
Expand Down Expand Up @@ -74,13 +83,15 @@ export const ParodosPage: React.FC = ({ children }) => {

React.useEffect(() => {
const index =
navigationMap.findIndex(({ route }) => pathname.includes(route)) || 0;
navigationMap.findIndex(({ routes }) =>
routes.find(route => pathname.includes(route)),
) || 0;
setSelectedTab(index);
}, [pathname]);

const onChangeTab = (index: number) => {
setSelectedTab(index);
window.location.href = `${pluginRoutePrefix}${navigationMap[index].route}`;
window.location.href = `${pluginRoutePrefix}${navigationMap[index].routes[0]}`;
};

return (
Expand Down
5 changes: 4 additions & 1 deletion plugins/orion/src/components/PluginRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export const PluginRouter = () => (
<Route path="/notification" element={<Notification />} />
<Route path="/training" element={<Training />} />
<Route path="/metrics" element={<Metrics />} />
<Route path="/onboarding/:appId/new/" element={<Onboarding isNew />} />
<Route
path="/onboarding/:projectId/:workflowId/new/"
element={<Onboarding isNew />}
/>
<Route
path="/onboarding/:executionId/workflow-detail"
element={<WorkFlowDetail isNew />}
Expand Down
44 changes: 33 additions & 11 deletions plugins/orion/src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ export type ProjectType = {
status?: ProjectStatusType;
};

export type ApplicationType = {
id: string;
name: string;
subtitle: string;
description: string;
};

export type WorkFlowTaskParameterType = {
key: string;
description: string;
Expand All @@ -33,24 +26,53 @@ export type WorkFlowTaskParameterType = {
| 'DATE'
| 'NUMBER'
| 'URL'
| 'MOCK-SELECT';
| 'MOCK-SELECT' /* TODO: swagger is missing this type */;
options?: {
// for MOCK-SELECT
// TODO: swagger is missing this type
key: string;
value: string;
}[];
};

export type WorkFlowTaskDefinitionType = {
id: string;
name: string;
parameters: WorkFlowTaskParameterType[];
outputs: ('EXCEPTION' | 'HTTP2XX' | 'NO_EXCEPTION' | 'OTHER')[];
workFlowChecker: string;
nextWorkFlow: string;
workFlowChecker?: string;
nextWorkFlow?: string;
};

export type WorkflowDefinitionType = {
id: string;
name: string;
type: string; // TODO: enum
type: string; // TODO: should be enum
author: string;
createDate: string;
modifyDate: string;
tasks: WorkFlowTaskDefinitionType[];

description?: string; // TODO: this is missing in swagger, so mocking it
};

export type WorkflowTaskArgumentType = {
key: string;
value: string;
};

export type WorkflowType = {
projectId: string;
workFlowName: string;
workFlowTasks: {
name: string;
arguments: WorkflowTaskArgumentType[];
}[];
};

export type WorkflowExecuteResponseType = {
workFlowExecutionId: 'string';
workFlowOptions: {
/* TODO */
};
};
133 changes: 82 additions & 51 deletions plugins/orion/src/components/workflow/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ import { Button, ButtonGroup, Chip, Grid, Typography } from '@material-ui/core';
import { useNavigate, useParams } from 'react-router-dom';
import { ParodosPage } from '../ParodosPage';
import {
ApplicationType,
WorkflowDefinitionType,
WorkflowExecuteResponseType,
WorkflowTaskArgumentType,
WorkFlowTaskParameterType,
WorkflowType,
} from '../types';
import { mockApplications, mockWorkflowParams } from './mockData';
import { useBackendUrl } from '../api';
import { WorkflowParameterComponent } from './WorkflowParameterComponent';

// TODO: use WorkflowStepper component after http://161.156.17.167:8080/swagger-ui/index.html#/Workflow/execute
import {
WorkflowParametersContext,
WorkflowParametersContextProvider,
} from '../../context/WorkflowParametersContext';
import { mockAndromedaWorkflowDefinition } from './mockData';

const getAllFlattenedParameters = (
allWorkflowDefinitions: WorkflowDefinitionType[],
Expand Down Expand Up @@ -78,31 +82,23 @@ const getWorkflowParameters = (
return filteredParameters;
};

export const Onboarding: React.FC<{ isNew?: boolean }> = ({ isNew }) => {
const { appId } = useParams();
type OnboardingProps = {
isNew?: boolean;
};

export const OnboardingImpl: React.FC<OnboardingProps> = ({ isNew }) => {
const { workflowId, projectId } = useParams();
const backendUrl = useBackendUrl();
const navigate = useNavigate();
const [application, setApplication] = React.useState<ApplicationType>();
const { getParamValue } = React.useContext(WorkflowParametersContext);
const [error, setError] = React.useState<string>();
const [isStartDisabled, setIsStartDisabled] = React.useState<boolean>(false);
const [workflow, setWorkflow] = React.useState<WorkflowDefinitionType>();
const [workflowParameters, setWorkflowParameters] = React.useState<
WorkFlowTaskParameterType[]
>([]);
// TODO: provide inra for storing dynamic parameters

// TODO: use real data
const applications: ApplicationType[] = mockApplications;
>([]); // parameters from whole chain of tasks - nextWorkflow

React.useEffect(() => {
const app = applications.find(a => a.id === appId);
if (!app) {
setError('Could not find application');
}
setApplication(app);
}, [appId, applications]);

React.useEffect(() => {
if (!application) {
if (!workflowId) {
return;
}

Expand All @@ -112,66 +108,95 @@ export const Onboarding: React.FC<{ isNew?: boolean }> = ({ isNew }) => {
const response = await fetch(
`${backendUrl}/api/proxy/parodos/workflowdefinitions`,
);
const allWorkflowDefinitions =
let allWorkflowDefinitions =
(await response.json()) as WorkflowDefinitionType[];

// find the right workflow for the selected application type
// append mock
allWorkflowDefinitions = [
mockAndromedaWorkflowDefinition,
...allWorkflowDefinitions,
];

// find the requested workflow definition
const workflowDefinition = allWorkflowDefinitions.find(def => {
// TODO: so far mock only - we do not know how to match the App to a workflow definition
return def.name === 'onboardingWorkFlow_INFRASTRUCTURE_WORKFLOW';
return def.id === workflowId;
});
if (!workflowDefinition) {
setError('Could not find workflow definition for the application.');
setError('Could not find workflow definition.');
return;
}
setWorkflow(workflowDefinition);

let params = getWorkflowParameters(
const params = getWorkflowParameters(
allWorkflowDefinitions,
workflowDefinition,
);
// eslint-disable-next-line no-console
console.log(
'So far using mocks, but once API provides data, we can use dynamically retrieved parameters to render: ',
params,
);

// Since we do not have data so far, let's use mock instead for now
params = mockWorkflowParams;

setWorkflowParameters(params);
} catch (e) {
setError('Failed to fetch workflow definitions');
}
};
doItAsync();
}, [application, backendUrl]);

const onStart = () => {
setIsStartDisabled(true);

// eslint-disable-next-line no-console
console.log('TODO: implement onStart');
// TODO: call HTTP POST to /workflow/execute
const executionId = 'responded-execution-id';
}, [workflowId, backendUrl]);

const onStart = async () => {
const body: WorkflowType = {
projectId: projectId || 'missing',
workFlowName: workflow?.name || 'missing',
workFlowTasks:
workflow?.tasks.map(task => {
const args: WorkflowTaskArgumentType[] = [];
task.parameters?.forEach(param => {
const value = getParamValue(param.key);
if (value) {
args.push({ key: param.key, value });
}
});

return {
name: task.name,
arguments: args,
};
}) || [],
};

// navigate to workflow Detail page after start
navigate(`/parodos/onboarding/${executionId}/workflow-detail`, {
state: { isNew: isNew },
});
try {
const data = await fetch(`${backendUrl}/api/proxy/parodos/workflows`, {
method: 'POST',
body: JSON.stringify(body),
});
const response = (await data.json()) as WorkflowExecuteResponseType;
const executionId = response.workFlowExecutionId;

// navigate to workflow Detail page after start
navigate(`/parodos/onboarding/${executionId}/workflow-detail`, {
state: { isNew: isNew },
});
} catch (e) {
setError('Failed to start workflow');
// eslint-disable-next-line no-console
console.error('Failed to start workflow: ', e);
}
};

const isStartDisabled = !workflowParameters.every(param => {
// Simple check for Required fields
return param.optional || !!getParamValue(param.key);
});

return (
<ParodosPage>
{error && <Typography>{error}</Typography>}
{!error && isNew && <Chip label="New application" color="secondary" />}

{!error && (
<ContentHeader title={`${application?.name || '...'}`}>
<ContentHeader title={`${workflow?.name || '...'}`}>
<SupportButton title="Need help?">Lorem Ipsum</SupportButton>
</ContentHeader>
)}
<Typography paragraph>
You are onboarding {application?.id || '...'}.
You are onboarding {workflow?.id || '...'}.
</Typography>
<Typography paragraph>
Please provide additional information related to your project.
Expand Down Expand Up @@ -201,3 +226,9 @@ export const Onboarding: React.FC<{ isNew?: boolean }> = ({ isNew }) => {
</ParodosPage>
);
};

export const Onboarding: React.FC<OnboardingProps> = props => (
<WorkflowParametersContextProvider>
<OnboardingImpl {...props} />
</WorkflowParametersContextProvider>
);
Loading

0 comments on commit c415fd8

Please sign in to comment.