Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: task observability #720

Merged
merged 13 commits into from
Mar 22, 2023
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"explorer.autoReveal": "focusNoScroll",
"explorer.autoReveal": true,
"explorer.enableUndo": true,
"explorer.excludeGitIgnore": false,

Expand Down
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ build_prod:

.PHONY: pack
pack:
yarn workspaces focus --production --all
yarn run build:pack
yarn run build:pack

.PHONY: types
types:
Expand Down
16 changes: 10 additions & 6 deletions packages/console/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@flyteorg/console",
"version": "0.0.15",
"version": "0.0.16",
"description": "Flyteconsole main app module",
"main": "./dist/index.js",
"module": "./lib/index.js",
Expand All @@ -20,7 +20,8 @@
"README.md",
"dist",
"lib",
"node_modules"
"node_modules",
"src"
],
"keywords": [
"flyteorg",
Expand All @@ -31,9 +32,11 @@
"scripts": {
"debug": "NM_DEBUG_LEVEL=2 yarn",
"clean": "rm -rf dist && rm -rf lib && rm -rf **.tsbuildinfo || true",
"build:watch": "run -T tsc-watch --noClear -p ./tsconfig.build.es.json --onSuccess \"yarn build\"",
"build:watch": "run -T tsc-watch --noClear --signalEmittedFiles -p ./tsconfig.build.es.json --onSuccess \"yarn build:watch:success\"",
"build:watch:success": "yarn build:esm:alias && yalc push",
"build": "yarn clean && yarn build:esm && yarn build:cjs",
"build:esm": "mkdir lib && cp -R src/assets ./lib && run -T tsc --module esnext --project ./tsconfig.build.es.json && run -T tsc-alias -p ./tsconfig.build.es.json",
"build:esm": "mkdir lib && cp -R src/assets ./lib && run -T tsc --module esnext --project ./tsconfig.build.es.json && yarn build:esm:alias",
"build:esm:alias": "run -T tsc-alias -p ./tsconfig.build.es.json",
"build:cjs": "mkdir dist && cp -R src/assets ./dist && run -T wait-on ./dist/assets && run -T tsc --project ./tsconfig.build.json && run -T tsc-alias -p ./tsconfig.build.json",
"build:types": "run -T tsc --module esnext --project ./tsconfig.build.es.json --emitDeclarationOnly && run -T tsc-alias -p ./tsconfig.build.es.json",
"test": "NODE_ENV=test jest"
Expand Down Expand Up @@ -79,7 +82,7 @@
"dagre": "0.8.5",
"dagre-d3": "^0.6.4",
"debug": "2.6.9",
"dom-helpers": "^3.4.0",
"dom-helpers": "5.2.1",
"fuzzysort": "^1.1.1",
"intersection-observer": "^0.7.0",
"js-yaml": "^3.13.1",
Expand Down Expand Up @@ -109,7 +112,7 @@
},
"devDependencies": {
"@types/debug": "^0.0.30",
"@types/dom-helpers": "^3.4.1",
"@types/dom-helpers": "^5.0.1",
"@types/js-yaml": "^3.10.1",
"@types/linkify-it": "^2.1.0",
"@types/lodash": "^4.14.68",
Expand All @@ -129,6 +132,7 @@
},
"resolutions": {
"react": "^16.13.1",
"dom-helpers": "5.2.1",
"react-dom": "^16.13.1",
"micromatch": "^4.0.0",
"@types/react": "^16.9.34",
Expand Down
5 changes: 5 additions & 0 deletions packages/console/src/basics/ExternalConfigHoc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as React from 'react';

export const ExternalConfigHoc = ({ ChildComponent, data }): any => {
return <ChildComponent data={data} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { PropsWithChildren, useContext } from 'react';
import { AppConfig } from '@flyteorg/common';

export interface ExternalConfigurationProviderProps {
registry?: {
nav?: React.FC<any>;
taskExecutionAttemps?: React.FC<any>;
additionalRoutes?: any;
};
env?: any;
config?: AppConfig;
}

export const ExternalConfigurationContext =
React.createContext<ExternalConfigurationProviderProps>({});

export const ExternalConfigurationProvider = ({
children,
config,
env,
registry,
}: PropsWithChildren<ExternalConfigurationProviderProps>) => {
return (
<ExternalConfigurationContext.Provider value={{ config, env, registry }}>
{children}
</ExternalConfigurationContext.Provider>
);
};

export const useExternalConfigurationContext = () =>
useContext(ExternalConfigurationContext);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ExternalConfigurationProvider';
4 changes: 4 additions & 0 deletions packages/console/src/basics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
type ExternalConfigurationProviderProps,
ExternalConfigurationProvider,
} from './ExternalConfigurationProvider';
4 changes: 4 additions & 0 deletions packages/console/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { navbarGridHeight } from './layout';
export { unknownValueString } from './constants';
export { dateWithFromNow, protobufDurationToHMS } from './formatters';
export { timestampToDate } from './utils';
31 changes: 15 additions & 16 deletions packages/console/src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ThemeProvider } from '@material-ui/styles';
import { FlyteApiProvider } from '@flyteorg/flyte-api';
import { SnackbarProvider } from 'notistack';
import { FeatureFlagsProvider } from 'basics/FeatureFlags';
import { env, updateEnv, AppConfig } from '@flyteorg/common';
import { env, updateEnv } from '@flyteorg/common';
import { debug, debugPrefix } from 'common/log';
import { ErrorBoundary } from 'components/common/ErrorBoundary';
import { APIContext, useAPIState } from 'components/data/apiContext';
Expand All @@ -31,17 +31,14 @@ import { ApplicationRouter } from 'routes/ApplicationRouter';
import { history } from 'routes/history';
import { NavBarRouter } from 'routes/NavBarRouter';
import { LocalCacheProvider } from 'basics/LocalCache/ContextProvider';
import {
ExternalConfigurationProvider,
ExternalConfigurationProviderProps,
} from 'basics/ExternalConfigurationProvider';

const queryClient = createQueryClient();

interface AppComponentProps {
registry?: {
nav?: React.FC<any>;
};
env?: any;
config?: AppConfig;
}
export type AppComponentProps = ExternalConfigurationProviderProps;

const queryClient = createQueryClient();
let overrided = false;

export const AppComponent: React.FC<AppComponentProps> = (
Expand Down Expand Up @@ -82,12 +79,14 @@ export const AppComponent: React.FC<AppComponentProps> = (
highlightColor={skeletonHighlightColor}
>
<CssBaseline />
<Router history={history}>
<ErrorBoundary fixed={true}>
<NavBarRouter registry={props?.registry} />
<ApplicationRouter />
</ErrorBoundary>
</Router>
<ExternalConfigurationProvider {...props}>
<Router history={history}>
<ErrorBoundary fixed={true}>
<NavBarRouter />
<ApplicationRouter />
</ErrorBoundary>
</Router>
</ExternalConfigurationProvider>
<SystemStatusBanner />
</SkeletonTheme>
</APIContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { TaskInitialLaunchParameters } from 'components/Launch/LaunchForm/types'
import { NodeExecutionPhase } from 'models/Execution/enums';
import Close from '@material-ui/icons/Close';
import { useEffect, useState } from 'react';
import classnames from 'classnames';
import { NodeExecutionDetails } from '../types';
import t from './strings';
import { ExecutionNodeDeck } from './ExecutionNodeDeck';
Expand Down Expand Up @@ -62,15 +63,23 @@ const useStyles = makeStyles((theme: Theme) => {
});

interface ExecutionDetailsActionsProps {
className?: string;
details?: NodeExecutionDetails;
nodeExecutionId: NodeExecutionIdentifier;
phase: NodeExecutionPhase;
text?: {
flyteDeckText?: string;
rerunText?: string;
resumeText?: string;
};
}

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

Expand Down Expand Up @@ -128,25 +137,25 @@ export const ExecutionDetailsActions = ({

return (
<>
<div className={styles.actionsContainer}>
<div className={classnames(styles.actionsContainer, className)}>
{execution?.value?.closure?.deckUri && (
<Button
variant="outlined"
color="primary"
onClick={() => setShowDeck(true)}
disabled={phase !== NodeExecutionPhase.SUCCEEDED}
>
{t('flyteDeck')}
{text?.flyteDeckText || t('flyteDeck')}
</Button>
)}
{id && initialParameters && details && (
<Button variant="outlined" color="primary" onClick={rerunOnClick}>
{t('rerun')}
{text?.rerunText || t('rerun')}
</Button>
)}
{phase === NodeExecutionPhase.PAUSED && (
<Button variant="outlined" color="primary" onClick={onResumeClick}>
{t('resume')}
{text?.resumeText || t('resume')}
</Button>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,19 @@ export function getPhaseConstants(
* a badge with the proper text and styling to indicate the status (succeeded/
* failed etc.)
*/
export const ExecutionStatusBadge: React.FC<ExecutionStatusBadgeProps> = ({
export const ExecutionStatusBadge: React.FC<
ExecutionStatusBadgeProps &
React.DetailedHTMLProps<
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
>
> = ({
phase,
type,
variant = 'default',
disabled = false,
className,
...htmlProps
}) => {
const styles = useStyles();
const style: React.CSSProperties = {};
Expand All @@ -102,7 +110,11 @@ export const ExecutionStatusBadge: React.FC<ExecutionStatusBadgeProps> = ({
}

return (
<div className={classnames(styles.root, styles[variant])} style={style}>
<div
className={classnames(styles.root, styles[variant], className)}
style={style}
{...htmlProps}
>
{text}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import classnames from 'classnames';
import { getCacheKey } from 'components/Cache/utils';
import { useCommonStyles } from 'components/common/styles';
import scrollbarSize from 'dom-helpers/util/scrollbarSize';
import scrollbarSize from 'dom-helpers/scrollbarSize';
import { NodeExecution } from 'models/Execution/types';
import { dNode } from 'models/Graph/types';
import { NodeExecutionPhase } from 'models/Execution/enums';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export const TaskLogList: React.FC<{ logs: Core.ITaskLog[] }> = ({ logs }) => {
</NewTargetLink>
) : (
// If there is no url, show item a a name string only, as it's not really clickable
<div className={styles.logName}>{name}</div>
<div key={name} className={styles.logName}>
{name}
</div>
),
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useCommonStyles } from 'components/common/styles';
import { TaskExecutionPhase } from 'models/Execution/enums';
import { TaskExecution } from 'models/Execution/types';
import { Core } from '@flyteorg/flyteidl-types';
import { ExternalConfigHoc } from 'basics/ExternalConfigHoc';
import { useExternalConfigurationContext } from 'basics/ExternalConfigurationProvider';
import { ExecutionStatusBadge } from '../ExecutionStatusBadge';
import { TaskExecutionDetails } from './TaskExecutionDetails';
import { TaskExecutionError } from './TaskExecutionError';
Expand All @@ -20,6 +22,10 @@ const useStyles = makeStyles((theme: Theme) => ({
},
title: {
marginBottom: theme.spacing(1),

'& > svg': {
verticalAlign: 'middle',
},
},
showDetailsButton: {
marginTop: theme.spacing(1),
Expand All @@ -36,30 +42,40 @@ interface TaskExecutionLogsCardProps {
logs: Core.ITaskLog[];
}

export const TaskExecutionLogsCard: React.FC<TaskExecutionLogsCardProps> = ({
taskExecution,
headerText,
phase,
logs,
}) => {
export const TaskExecutionLogsCard: React.FC<
TaskExecutionLogsCardProps
> = props => {
const { taskExecution, headerText, phase, logs } = props;
const commonStyles = useCommonStyles();
const styles = useStyles();
const { registry } = useExternalConfigurationContext();

const {
closure: { error, startedAt, updatedAt, duration },
} = taskExecution;
const taskHasStarted = phase >= TaskExecutionPhase.QUEUED;

const taskHasStarted = phase >= TaskExecutionPhase.QUEUED;
const externalProps = { ...props, styles, commonStyles };
return (
<>
<section className={styles.section}>
<header className={styles.header}>
<Typography
variant="h6"
className={classnames(styles.title, commonStyles.textWrapped)}
>
{headerText}
</Typography>
{registry?.taskExecutionAttemps ? (
// Alternate path

<ExternalConfigHoc
ChildComponent={registry.taskExecutionAttemps}
data={externalProps}
/>
) : (
// default path
<Typography
variant="h6"
className={classnames(styles.title, commonStyles.textWrapped)}
>
{headerText}
</Typography>
)}
</header>
<ExecutionStatusBadge phase={phase} type="task" variant="text" />
</section>
Expand Down
4 changes: 3 additions & 1 deletion packages/console/src/components/Navigation/NavBarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import * as React from 'react';
import ReactDOM from 'react-dom';

/** Complements NavBar, allowing pages to inject custom content. */
export const NavBarContent: React.FC<{}> = ({ children }) => {
export const NavBarContent: React.FC<React.PropsWithChildren<{}>> = ({
children,
}) => {
const navBar = document.getElementById(navBarContentId);
if (navBar == null) {
log.warn(`
Expand Down
5 changes: 5 additions & 0 deletions packages/console/src/components/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { useCommonStyles } from './styles';
export { withRouteParams } from './withRouteParams';
export { WaitForData } from './WaitForData';
export { WaitForQuery } from './WaitForQuery';
export { DetailsGroup } from './DetailsGroup';
Loading