Skip to content

Commit

Permalink
add new uniflow external storage output/input payload to UI (#281)
Browse files Browse the repository at this point in the history
  • Loading branch information
Paulooze authored Nov 12, 2021
1 parent d3c1203 commit 92147e5
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 39 deletions.
5 changes: 5 additions & 0 deletions packages/frinx-dashboard/src/api/uniflow/uniflow-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,8 @@ export async function deleteWorkflowInstance(workflowId: string): Promise<string

return workflowIdRes as string;
}

export async function getExternalStorage(path: string): Promise<Record<string, string>> {
const data = await sendGetRequest(`/external/postgres/${path}`);
return data as Record<string, string>;
}
2 changes: 2 additions & 0 deletions packages/frinx-dashboard/src/uniflow-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
deleteSchedule,
getSchedule,
registerSchedule,
getExternalStorage,
} from './api/uniflow/uniflow-api';

const callbacks = {
Expand Down Expand Up @@ -58,6 +59,7 @@ const callbacks = {
deleteSchedule,
getSchedule,
registerSchedule,
getExternalStorage,
};

type UniflowComponents = Omit<typeof import('@frinx/workflow-ui'), 'getUniflowApiProvider'> & {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @flow
import {
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
Textarea,
} from '@chakra-ui/react';
import React, { VoidFunctionComponent, useState, useEffect } from 'react';
import callbackUtils from '../../../utils/callback-utils';

type Props = {
storagePath: string;
isOpen: boolean;
onClose: () => void;
title: string;
};

const ExternalStorageModal: VoidFunctionComponent<Props> = ({ isOpen, onClose, storagePath, title }) => {
const [payload, setPayload] = useState<string | null>(null);

useEffect(() => {
const getExternalStorage = callbackUtils.getExternalStorageCallback();
getExternalStorage(storagePath).then((res) => {
setPayload(JSON.stringify(res, null, 2));
});
}, [storagePath]);

return (
<Modal size="5xl" isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>{title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
{payload != null && <Textarea value={payload} isReadOnly={true} id="storage" variant="filled" minH={450} />}
</ModalBody>
</ModalContent>
</Modal>
);
};

export default ExternalStorageModal;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC } from 'react';
import React, { VoidFunctionComponent, useState } from 'react';
import { IconButton, Button, SimpleGrid, Box, Stack, Textarea, Text } from '@chakra-ui/react';
import { CopyIcon } from '@chakra-ui/icons';
import ExternalStorageModal from './external-storage-modal';

type Props = {
isEscaped: boolean;
Expand All @@ -9,48 +10,98 @@ type Props = {
copyToClipBoard: (value: Record<string, string>) => void;
getUnescapedJSON: (value: Record<string, string>) => string;
onEscapeChange: (isEscaped: boolean) => void;
externalInputPayloadStoragePath?: string;
externalOutputPayloadStoragePath?: string;
};

const InputOutputTab: FC<Props> = ({ isEscaped, input, output, getUnescapedJSON, copyToClipBoard, onEscapeChange }) => {
const InputOutputTab: VoidFunctionComponent<Props> = ({
isEscaped,
input,
output,
getUnescapedJSON,
copyToClipBoard,
onEscapeChange,
externalInputPayloadStoragePath,
externalOutputPayloadStoragePath,
}) => {
const [payload, setPayload] = useState<{ type: 'Input' | 'Output'; data: string } | null>(null);
return (
<SimpleGrid columns={2} spacing={4}>
<Box>
<Stack direction="row" spacing={2} align="center" mb={2}>
<Text as="b" fontSize="sm">
Workflow Input
</Text>
<IconButton
aria-label="copy"
icon={<CopyIcon />}
size="sm"
className="clp"
onClick={() => copyToClipBoard(input)}
<>
{payload && (
<ExternalStorageModal
title={payload.type}
isOpen={payload != null}
onClose={() => {
setPayload(null);
}}
storagePath={payload.data}
/>
)}
<SimpleGrid columns={2} spacing={4}>
<Box>
<Stack direction="row" spacing={2} align="center" mb={2}>
<Text as="b" fontSize="sm">
Workflow Input
</Text>
<IconButton
aria-label="copy"
icon={<CopyIcon />}
size="sm"
className="clp"
onClick={() => copyToClipBoard(input)}
/>
<Button size="sm" onClick={() => onEscapeChange(!isEscaped)}>
{isEscaped ? 'Unescape' : 'Escape'}
</Button>
{externalInputPayloadStoragePath && (
<Button
size="sm"
onClick={() => {
setPayload({ type: 'Input', data: externalInputPayloadStoragePath });
}}
>
External storage input
</Button>
)}
</Stack>
<Textarea value={getUnescapedJSON(input)} isReadOnly={true} id="workflowInput" variant="filled" minH={200} />
</Box>
<Box>
<Stack direction="row" spacing={2} align="center" mb={2}>
<Text as="b" fontSize="sm">
Workflow Output
</Text>
<IconButton
aria-label="copy"
icon={<CopyIcon />}
size="sm"
className="clp"
onClick={() => copyToClipBoard(output)}
/>
<Button size="sm" onClick={() => onEscapeChange(!isEscaped)}>
{isEscaped ? 'Unescape' : 'Escape'}
</Button>
{externalOutputPayloadStoragePath && (
<Button
size="sm"
onClick={() => {
setPayload({ type: 'Output', data: externalOutputPayloadStoragePath });
}}
>
External storage output
</Button>
)}
</Stack>
<Textarea
value={getUnescapedJSON(output)}
isReadOnly={true}
id="workflowOutput"
variant="filled"
minH={200}
/>
<Button size="sm" onClick={() => onEscapeChange(!isEscaped)}>
{isEscaped ? 'Unescape' : 'Escape'}
</Button>
</Stack>
<Textarea value={getUnescapedJSON(input)} isReadOnly={true} id="workflowInput" variant="filled" minH={200} />
</Box>
<Box>
<Stack direction="row" spacing={2} align="center" mb={2}>
<Text as="b" fontSize="sm">
Workflow Output
</Text>
<IconButton
aria-label="copy"
icon={<CopyIcon />}
size="sm"
className="clp"
onClick={() => copyToClipBoard(output)}
/>
<Button size="sm" onClick={() => onEscapeChange(!isEscaped)}>
{isEscaped ? 'Unescape' : 'Escape'}
</Button>
</Stack>
<Textarea value={getUnescapedJSON(output)} isReadOnly={true} id="workflowOutput" variant="filled" minH={200} />
</Box>
</SimpleGrid>
</Box>
</SimpleGrid>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export type ExecutedWorkflowDetailResult = {
endTime: Date | number | string;
input: Record<string, string>;
output: Record<string, string>;
externalInputPayloadStoragePath?: string;
externalOutputPayloadStoragePath?: string;
};

const DetailsModal: FC<Props> = ({ workflowId, onWorkflowIdClick, onExecutedOperation }) => {
Expand Down Expand Up @@ -215,6 +217,8 @@ const DetailsModal: FC<Props> = ({ workflowId, onWorkflowIdClick, onExecutedOper
output={result.output}
onEscapeChange={() => setIsEscaped(!isEscaped)}
getUnescapedJSON={getUnescapedJSON}
externalInputPayloadStoragePath={details.result?.externalInputPayloadStoragePath}
externalOutputPayloadStoragePath={details.result?.externalOutputPayloadStoragePath}
/>
)}
</TabPanel>
Expand Down
2 changes: 2 additions & 0 deletions packages/frinx-workflow-ui/src/types/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ export type Task = {
subWorkflowId: string;
startTime: number;
endTime: number;
externalOutputPayloadStoragePath?: string;
externalInputPayloadStoragePath?: string;
};
12 changes: 12 additions & 0 deletions packages/frinx-workflow-ui/src/utils/callback-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export type Callbacks = {
version: string,
schedule: Partial<ScheduledWorkflow>,
) => Promise<{ message: string }>;
getExternalStorage: (path: string) => Promise<Record<string, string>>;
};

class CallbackUtils {
Expand Down Expand Up @@ -87,6 +88,7 @@ class CallbackUtils {
private registerSchedule:
| ((name: string, version: string, schedule: Partial<ScheduledWorkflow>) => Promise<{ message: string }>)
| null = null;
private getExternalStorage: (path: string) => Promise<Record<string, string>>;

setCallbacks(callbacks: Callbacks) {
if (this.getWorkflows == null) {
Expand Down Expand Up @@ -192,6 +194,9 @@ class CallbackUtils {
if (this.registerSchedule == null) {
this.registerSchedule = callbacks.registerSchedule;
}
if (this.getExternalStorage == null) {
this.getExternalStorage = callbacks.getExternalStorage;
}
}

getWorkflowsCallback() {
Expand Down Expand Up @@ -375,6 +380,13 @@ class CallbackUtils {
}
return this.registerSchedule;
}

getExternalStorageCallback() {
if (this.getExternalStorage == null) {
throw new Error('getExternalStorage is missing');
}
return this.getExternalStorage;
}
}

export default new CallbackUtils();

0 comments on commit 92147e5

Please sign in to comment.