Skip to content

Commit

Permalink
feat: support flyte decks (#504)
Browse files Browse the repository at this point in the history
* feat: support flyte deck #none

Signed-off-by: James <[email protected]>

* fix: rebase with master #none

Signed-off-by: James <[email protected]>

* fix: fix iframe height and api response type; #none

Signed-off-by: James <[email protected]>

* fix: modal style; #none;

Signed-off-by: James <[email protected]>

* fix: use env variable for server ssl config #none;

Signed-off-by: James <[email protected]>

* fix: use h2 instead of h3 for future migration #none

Signed-off-by: James <[email protected]>
  • Loading branch information
james-union authored Jun 13, 2022
1 parent 1013deb commit 32686cc
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 20 deletions.
2 changes: 1 addition & 1 deletion packages/zapp/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@date-io/moment": "1.3.9",
"@flyteorg/flyteidl": "1.1.0",
"@flyteorg/flyteidl": "1.1.4",
"@material-ui/core": "^4.0.0",
"@material-ui/icons": "^4.0.0",
"@material-ui/pickers": "^3.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,78 @@
import { Button } from '@material-ui/core';
import { Button, Dialog, IconButton } from '@material-ui/core';
import * as React from 'react';
import { ResourceIdentifier, Identifier, Variable } from 'models/Common/types';
import { makeStyles, Theme } from '@material-ui/core/styles';
import { getTask } from 'models/Task/api';
import { LaunchFormDialog } from 'components/Launch/LaunchForm/LaunchFormDialog';
import { NodeExecutionIdentifier } from 'models/Execution/types';
import { useNodeExecutionData } from 'components/hooks/useNodeExecution';
import { useNodeExecution, useNodeExecutionData } from 'components/hooks/useNodeExecution';
import { literalsToLiteralValueMap } from 'components/Launch/LaunchForm/utils';
import { TaskInitialLaunchParameters } from 'components/Launch/LaunchForm/types';
import { NodeExecutionPhase } from 'models/Execution/enums';
import Close from '@material-ui/icons/Close';
import { NodeExecutionDetails } from '../types';
import t from './strings';
import { ExecutionNodeDeck } from './ExecutionNodeDeck';

const useStyles = makeStyles((theme: Theme) => {
return {
actionsContainer: {
borderTop: `1px solid ${theme.palette.divider}`,
marginTop: theme.spacing(2),
paddingTop: theme.spacing(2),
'& button': {
marginRight: theme.spacing(1),
},
},
dialog: {
maxWidth: `calc(100% - ${theme.spacing(12)}px)`,
maxHeight: `calc(100% - ${theme.spacing(12)}px)`,
height: theme.spacing(90),
width: theme.spacing(110),
'& iframe': {
border: 'none',
},
},
dialogTitle: {
display: 'flex',
alignItems: 'center',
padding: theme.spacing(2),
paddingBottom: theme.spacing(0),
fontFamily: 'Open sans',
},
deckTitle: {
flexGrow: 1,
textAlign: 'center',
fontSize: '24px',
lineHeight: '32px',
marginBlock: 0,
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
},
close: {
position: 'absolute',
right: theme.spacing(2),
},
};
});

interface ExecutionDetailsActionsProps {
className?: string;
details: NodeExecutionDetails;
nodeExecutionId: NodeExecutionIdentifier;
phase?: NodeExecutionPhase;
}

export const ExecutionDetailsActions = (props: ExecutionDetailsActionsProps): JSX.Element => {
const { className, details, nodeExecutionId } = props;
const { details, nodeExecutionId, phase } = props;
const styles = useStyles();

const [showLaunchForm, setShowLaunchForm] = React.useState<boolean>(false);
const [taskInputsTypes, setTaskInputsTypes] = React.useState<
Record<string, Variable> | undefined
>();

const executionData = useNodeExecutionData(nodeExecutionId);
const execution = useNodeExecution(nodeExecutionId);

const id = details.taskTemplate?.id as ResourceIdentifier | undefined;

Expand All @@ -36,6 +84,9 @@ export const ExecutionDetailsActions = (props: ExecutionDetailsActionsProps): JS
if (id) fetchTask();
}, [id]);

const [showDeck, setShowDeck] = React.useState(false);
const onCloseDeck = () => setShowDeck(false);

if (!id) {
return <></>;
}
Expand All @@ -54,7 +105,17 @@ export const ExecutionDetailsActions = (props: ExecutionDetailsActionsProps): JS

return (
<>
<div className={className}>
<div className={styles.actionsContainer}>
{execution?.value?.closure?.deckUri && (
<Button
variant="outlined"
color="primary"
onClick={() => setShowDeck(true)}
disabled={phase !== NodeExecutionPhase.SUCCEEDED}
>
{t('flyteDeck')}
</Button>
)}
<Button variant="outlined" color="primary" onClick={rerunOnClick}>
{t('rerun')}
</Button>
Expand All @@ -65,6 +126,17 @@ export const ExecutionDetailsActions = (props: ExecutionDetailsActionsProps): JS
showLaunchForm={showLaunchForm}
setShowLaunchForm={setShowLaunchForm}
/>
{execution?.value?.closure?.deckUri ? (
<Dialog PaperProps={{ className: styles.dialog }} maxWidth={false} open={showDeck}>
<div className={styles.dialogTitle}>
<h2 className={styles.deckTitle}>{t('flyteDeck')}</h2>
<IconButton aria-label="close" onClick={onCloseDeck} className={styles.close}>
<Close />
</IconButton>
</div>
<ExecutionNodeDeck deckUri={execution.value.closure.deckUri} />
</Dialog>
) : null}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useDownloadLocation } from 'components/hooks/useDataProxy';
import { WaitForData } from 'components/common/WaitForData';
import * as React from 'react';

/** Fetches and renders the deck data for a given `deckUri` */
export const ExecutionNodeDeck: React.FC<{ deckUri: string }> = ({ deckUri }) => {
const downloadLocation = useDownloadLocation(deckUri);

return (
<WaitForData {...downloadLocation}>
<iframe title="deck" height="100%" src={downloadLocation.value.signedUrl} />
</WaitForData>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,6 @@ const useStyles = makeStyles((theme: Theme) => {
marginTop: theme.spacing(2),
paddingTop: theme.spacing(2),
},
actionsContainer: {
borderTop: `1px solid ${theme.palette.divider}`,
marginTop: theme.spacing(2),
paddingTop: theme.spacing(2),
},
nodeTypeContent: {
minWidth: theme.spacing(9),
},
Expand Down Expand Up @@ -403,9 +398,9 @@ export const NodeExecutionDetailsPanelContent: React.FC<NodeExecutionDetailsProp
{!dag && detailsContent}
{details && (
<ExecutionDetailsActions
className={styles.actionsContainer}
details={details}
nodeExecutionId={nodeExecutionId}
phase={nodeExecution?.closure.phase}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createLocalizedString } from '@flyteconsole/locale';

const str = {
rerun: 'RERUN',
flyteDeck: 'Flyte Deck',
};

export { patternKey } from '@flyteconsole/locale';
Expand Down
17 changes: 17 additions & 0 deletions packages/zapp/console/src/components/hooks/useDataProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useAPIContext } from 'components/data/apiContext';
import { DownloadLocation } from 'models/Execution/types';
import { FetchableData } from './types';
import { useFetchableData } from './useFetchableData';

/** A hook for fetching a NodeExecution */
export function useDownloadLocation(nativeUrl: string): FetchableData<DownloadLocation> {
const { getDownloadLocation } = useAPIContext();
return useFetchableData<DownloadLocation, string>(
{
debugName: 'CreateDownloadLocation',
defaultValue: {} as DownloadLocation,
doFetch: (nativeUrl) => getDownloadLocation(nativeUrl),
},
nativeUrl,
);
}
1 change: 1 addition & 0 deletions packages/zapp/console/src/models/Common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const endpointPrefixes = {
taskExecution: '/task_executions',
taskExecutionChildren: '/children/task_executions',
workflow: '/workflows',
dataProxyArtifactUrn: '/dataproxy/artifact_urn',
};

export const identifierPrefixes: { [k in ResourceType]: string } = {
Expand Down
14 changes: 13 additions & 1 deletion packages/zapp/console/src/models/Execution/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Admin, Core, Protobuf } from 'flyteidl';
import { Admin, Core, Protobuf, Service } from 'flyteidl';
import { getAdminEntity, postAdminEntity } from 'models/AdminEntity/AdminEntity';
import {
defaultListExecutionChildrenConfig,
Expand All @@ -11,6 +11,7 @@ import { makeIdentifierPath } from 'models/Common/utils';
import { defaultExecutionPrincipal } from './constants';
import { ExecutionState } from './enums';
import {
DownloadLocation,
Execution,
ExecutionData,
ExecutionMetadata,
Expand All @@ -22,6 +23,7 @@ import {
} from './types';
import {
executionListTransformer,
makeCreateDownloadLocationPath,
makeExecutionPath,
makeNodeExecutionListPath,
makeNodeExecutionPath,
Expand Down Expand Up @@ -56,6 +58,16 @@ export const getExecution = (id: WorkflowExecutionIdentifier, config?: RequestCo
config,
);

/** Fetches a signed url of the native url */
export const getDownloadLocation = (nativeUrl: string, config?: RequestConfig) =>
getAdminEntity<Service.CreateDownloadLocationResponse, DownloadLocation>(
{
path: makeCreateDownloadLocationPath(nativeUrl),
messageType: Service.CreateDownloadLocationResponse,
},
config,
);

const emptyExecutionData: ExecutionData = {
inputs: {},
outputs: {},
Expand Down
9 changes: 8 additions & 1 deletion packages/zapp/console/src/models/Execution/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Admin, Core, Event, Protobuf } from 'flyteidl';
import { Admin, Core, Event, Protobuf, Service } from 'flyteidl';
import { Identifier, LiteralMap, LiteralMapBlob, TaskLog, UrlBlob } from 'models/Common/types';
import { CompiledWorkflow } from 'models/Workflow/types';
import {
Expand Down Expand Up @@ -55,6 +55,11 @@ export interface Execution extends Admin.IExecution {
spec: ExecutionSpec;
}

export interface DownloadLocation extends Service.CreateDownloadLocationResponse {
signedUrl: string;
expiresAt: Protobuf.ITimestamp;
}

/** Node executions */
export interface WorkflowNodeMetadata {
executionId: WorkflowExecutionIdentifier;
Expand Down Expand Up @@ -102,6 +107,7 @@ export interface NodeExecutionClosure extends Admin.INodeExecutionClosure {
startedAt?: Protobuf.ITimestamp;
taskNodeMetadata?: TaskNodeMetadata;
workflowNodeMetadata?: WorkflowNodeMetadata;
deckUri?: string;
}

/** Task executions */
Expand Down Expand Up @@ -138,5 +144,6 @@ export interface ExecutionData {
outputs?: UrlBlob; // TODO FC#393: this field was deprecated use fullOutputs instead - check for usage and remove
fullInputs: LiteralMap | null;
fullOutputs: LiteralMap | null;
deckUri?: string;
dynamicWorkflow?: CompiledWorkflow;
}
4 changes: 4 additions & 0 deletions packages/zapp/console/src/models/Execution/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export const makeTaskExecutionPath = ({
retryAttempt,
].join('/');

/** Generates the API endpoint for the CreateDownloadLocation request */
export const makeCreateDownloadLocationPath = (nativeUrl: string) =>
`${endpointPrefixes.dataProxyArtifactUrn}?native_url=${nativeUrl}`;

/** Transformer to coerce an `Admin.ExecutionList` into a standard shape */
export const executionListTransformer = createPaginationTransformer<Execution, Admin.ExecutionList>(
'executions',
Expand Down
4 changes: 2 additions & 2 deletions packages/zapp/console/webpack.dev.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as webpack from 'webpack';
import * as HTMLWebpackPlugin from 'html-webpack-plugin';
import * as path from 'path';
import chalk from 'chalk';
import { LOCAL_DEV_HOST, CERTIFICATE_PATH } from './env';
import { LOCAL_DEV_HOST, CERTIFICATE_PATH, ADMIN_API_USE_SSL } from './env';

const { merge } = require('webpack-merge');
const fs = require('fs');
Expand Down Expand Up @@ -42,7 +42,7 @@ export const clientConfig: webpack.Configuration = merge(common.default.clientCo
host: LOCAL_DEV_HOST,
historyApiFallback: true,
server: {
type: 'https',
type: ADMIN_API_USE_SSL,
options: {
key: fs.readFileSync(`${CERTIFICATE_PATH}/server.key`),
cert: fs.readFileSync(`${CERTIFICATE_PATH}/server.crt`),
Expand Down
23 changes: 19 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1640,10 +1640,25 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"

"@flyteorg/[email protected]":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@flyteorg/flyteidl/-/flyteidl-1.1.0.tgz#9fcf06d878616439939e932c5a35357d3d7eea04"
integrity sha512-p07Vd6rxmASKJvfF56ArVyuZLjxTJPnAQsTs3rDJL74gd9Ixs4cEDa/A4+iMYSNl42iTVPvAkM4movXDD1Hmgg==
"@eslint/eslintrc@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^9.3.2"
globals "^13.15.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"

"@flyteorg/[email protected]":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@flyteorg/flyteidl/-/flyteidl-1.1.4.tgz#7a02d80e22c623817b6061f1f5e88ec243041cf1"
integrity sha512-CmO/H3vbjluV/G4J9TFnSo3HiefOQ8f46BbpordSlVA2CANWQZaNc6Csz7JTGdotyZ2DdUXJkBcPRiA/r9H3lQ==

"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3":
version "1.1.3"
Expand Down

0 comments on commit 32686cc

Please sign in to comment.