Skip to content

Commit

Permalink
feat: Support for dynamic and nested workflows. (#326)
Browse files Browse the repository at this point in the history
Added support for nested graphs and dynamic workflows
  • Loading branch information
jsonporter authored Mar 14, 2022
1 parent 50b5ef5 commit 5cd1ca5
Show file tree
Hide file tree
Showing 29 changed files with 2,051 additions and 1,454 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"memory-fs": "^0.4.1",
"morgan": "^1.8.2",
"react-chartjs-2": "^4.0.0",
"react-flow-renderer": "^9.6.3",
"react-flow-renderer": "10.0.0-next.30",
"react-ga4": "^1.4.1",
"react-helmet": "^5.1.3",
"react-responsive": "^4.1.0",
Expand Down
30 changes: 15 additions & 15 deletions src/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@ import * as ReactDOM from 'react-dom';
import ReactGA from 'react-ga4';

const render = (Component: React.FC) => {
ReactDOM.render(<Component />, document.getElementById('react-app'));
ReactDOM.render(<Component />, document.getElementById('react-app'));
};

const initializeApp = () => {
const App = require('./components/App/App').App;
const App = require('./components/App/App').App;

const { ENABLE_GA, GA_TRACKING_ID } = env;
const { ENABLE_GA, GA_TRACKING_ID } = env;

if (ENABLE_GA != 'false') {
ReactGA.initialize(GA_TRACKING_ID as string);
}
if (ENABLE_GA != 'false') {
ReactGA.initialize(GA_TRACKING_ID as string);
}

if (env.NODE_ENV === 'development') {
// We use style-loader in dev mode, but it causes a FOUC and some initial styling issues
// so we'll give it time to add the styles before initial render.
setTimeout(() => render(App), 500);
} else {
render(App);
}
if (env.NODE_ENV === 'development') {
// We use style-loader in dev mode, but it causes a FOUC and some initial styling issues
// so we'll give it time to add the styles before initial render.
setTimeout(() => render(App), 500);
} else {
render(App);
}
};

if (document.body) {
initializeApp();
initializeApp();
} else {
window.addEventListener('DOMContentLoaded', initializeApp, false);
window.addEventListener('DOMContentLoaded', initializeApp, false);
}
128 changes: 58 additions & 70 deletions src/components/Entities/EntityDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,35 @@ import { EntityVersions } from './EntityVersions';
import { EntityExecutionsBarChart } from './EntityExecutionsBarChart';

const useStyles = makeStyles((theme: Theme) => ({
metadataContainer: {
display: 'flex',
marginBottom: theme.spacing(5),
marginTop: theme.spacing(2),
width: '100%'
},
descriptionContainer: {
flex: '2 1 auto',
marginRight: theme.spacing(2)
},
executionsContainer: {
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
margin: `0 -${theme.spacing(contentMarginGridUnits)}px`,
flexBasis: theme.spacing(80)
},
versionsContainer: {
display: 'flex',
flexDirection: 'column'
},
schedulesContainer: {
flex: '1 2 auto',
marginRight: theme.spacing(30)
}
metadataContainer: {
display: 'flex',
marginBottom: theme.spacing(5),
marginTop: theme.spacing(2),
width: '100%'
},
descriptionContainer: {
flex: '2 1 auto',
marginRight: theme.spacing(2)
},
executionsContainer: {
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
margin: `0 -${theme.spacing(contentMarginGridUnits)}px`,
flexBasis: theme.spacing(80)
},
versionsContainer: {
display: 'flex',
flexDirection: 'column'
},
schedulesContainer: {
flex: '1 2 auto',
marginRight: theme.spacing(30)
}
}));

interface EntityDetailsProps {
id: ResourceIdentifier;
id: ResourceIdentifier;
}

/**
Expand All @@ -52,53 +52,41 @@ interface EntityDetailsProps {
* @param id
*/
export const EntityDetails: React.FC<EntityDetailsProps> = ({ id }) => {
const sections = entitySections[id.resourceType];
const project = useProject(id.project);
const styles = useStyles();
const { chartIds, onToggle, clearCharts } = useChartState();
const sections = entitySections[id.resourceType];
const project = useProject(id.project);
const styles = useStyles();
const { chartIds, onToggle, clearCharts } = useChartState();

return (
<WaitForData {...project}>
<EntityDetailsHeader
project={project.value}
id={id}
launchable={!!sections.launch}
/>
return (
<WaitForData {...project}>
<EntityDetailsHeader project={project.value} id={id} launchable={!!sections.launch} />

<div className={styles.metadataContainer}>
{sections.description ? (
<div className={styles.descriptionContainer}>
<EntityDescription id={id} />
</div>
) : null}
{sections.schedules ? (
<div className={styles.schedulesContainer}>
<EntitySchedules id={id} />
</div>
) : null}
</div>
<div className={styles.metadataContainer}>
{sections.description ? (
<div className={styles.descriptionContainer}>
<EntityDescription id={id} />
</div>
) : null}
{sections.schedules ? (
<div className={styles.schedulesContainer}>
<EntitySchedules id={id} />
</div>
) : null}
</div>

{sections.versions ? (
<div className={styles.versionsContainer}>
<EntityVersions id={id} />
</div>
) : null}
{sections.versions ? (
<div className={styles.versionsContainer}>
<EntityVersions id={id} />
</div>
) : null}

<EntityExecutionsBarChart
onToggle={onToggle}
chartIds={chartIds}
id={id}
/>
<EntityExecutionsBarChart onToggle={onToggle} chartIds={chartIds} id={id} />

{sections.executions ? (
<div className={styles.executionsContainer}>
<EntityExecutions
chartIds={chartIds}
id={id}
clearCharts={clearCharts}
/>
</div>
) : null}
</WaitForData>
);
{sections.executions ? (
<div className={styles.executionsContainer}>
<EntityExecutions chartIds={chartIds} id={id} clearCharts={clearCharts} />
</div>
) : null}
</WaitForData>
);
};
175 changes: 76 additions & 99 deletions src/components/Entities/EntityVersions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,117 +19,94 @@ import { WorkflowVersionsTablePageSize } from './constants';
import t from './strings';

const useStyles = makeStyles((theme: Theme) => ({
headerContainer: {
display: 'flex'
},
collapseButton: {
marginTop: theme.spacing(-0.5)
},
header: {
flexGrow: 1,
marginBottom: theme.spacing(1),
marginRight: theme.spacing(1)
},
viewAll: {
color: interactiveTextColor,
cursor: 'pointer'
},
divider: {
borderBottom: `1px solid ${theme.palette.divider}`,
marginBottom: theme.spacing(1)
}
headerContainer: {
display: 'flex'
},
collapseButton: {
marginTop: theme.spacing(-0.5)
},
header: {
flexGrow: 1,
marginBottom: theme.spacing(1),
marginRight: theme.spacing(1)
},
viewAll: {
color: interactiveTextColor,
cursor: 'pointer'
},
divider: {
borderBottom: `1px solid ${theme.palette.divider}`,
marginBottom: theme.spacing(1)
}
}));

export interface EntityVersionsProps {
id: ResourceIdentifier;
showAll?: boolean;
id: ResourceIdentifier;
showAll?: boolean;
}

/**
* The tab/page content for viewing a workflow's versions.
* @param id
* @param showAll - shows all available entity versions
*/
export const EntityVersions: React.FC<EntityVersionsProps> = ({
id,
showAll = false
}) => {
const { domain, project, resourceType, name } = id;
const [showTable, setShowTable] = useLocalCache(
LocalCacheItem.ShowWorkflowVersions
);
const styles = useStyles();
const sort = {
key: executionSortFields.createdAt,
direction: SortDirection.DESCENDING
};
export const EntityVersions: React.FC<EntityVersionsProps> = ({ id, showAll = false }) => {
const { domain, project, resourceType, name } = id;
const [showTable, setShowTable] = useLocalCache(LocalCacheItem.ShowWorkflowVersions);
const styles = useStyles();
const sort = {
key: executionSortFields.createdAt,
direction: SortDirection.DESCENDING
};

const baseFilters = React.useMemo(
() => executionFilterGenerator[resourceType](id),
[id, resourceType]
);
const baseFilters = React.useMemo(() => executionFilterGenerator[resourceType](id), [id, resourceType]);

const versions = useWorkflowVersions(
{ domain, project },
{
sort,
filter: baseFilters,
limit: showAll ? 100 : WorkflowVersionsTablePageSize
}
);
const versions = useWorkflowVersions(
{ domain, project },
{
sort,
filter: baseFilters,
limit: showAll ? 100 : WorkflowVersionsTablePageSize
}
);

const preventDefault = e => e.preventDefault();
const handleViewAll = React.useCallback(() => {
history.push(
Routes.WorkflowVersionDetails.makeUrl(
project,
domain,
name,
versions.value[0].id.version ?? ''
)
);
}, [project, domain, name, versions]);
const preventDefault = e => e.preventDefault();
const handleViewAll = React.useCallback(() => {
history.push(Routes.WorkflowVersionDetails.makeUrl(project, domain, name, versions.value[0].id.version ?? ''));
}, [project, domain, name, versions]);

return (
<>
{!showAll && (
<div className={styles.headerContainer}>
<IconButton
className={styles.collapseButton}
edge="start"
disableRipple={true}
disableTouchRipple={true}
onClick={() => setShowTable(!showTable)}
onMouseDown={preventDefault}
size="small"
aria-label=""
title={t('collapseButton', showTable)}
>
{showTable ? <ExpandLess /> : <ExpandMore />}
</IconButton>
<Typography className={styles.header} variant="h6">
{t('workflowVersionsTitle')}
</Typography>
<Typography
className={styles.viewAll}
variant="body1"
onClick={handleViewAll}
>
{t('viewAll')}
</Typography>
</div>
)}
<WaitForData {...versions}>
{showTable || showAll ? (
<WorkflowVersionsTable
{...versions}
isFetching={isLoadingState(versions.state)}
versionView={showAll}
/>
) : (
<div className={styles.divider} />
)}
</WaitForData>
</>
);
return (
<>
{!showAll && (
<div className={styles.headerContainer}>
<IconButton
className={styles.collapseButton}
edge="start"
disableRipple={true}
disableTouchRipple={true}
onClick={() => setShowTable(!showTable)}
onMouseDown={preventDefault}
size="small"
aria-label=""
title={t('collapseButton', showTable)}
>
{showTable ? <ExpandLess /> : <ExpandMore />}
</IconButton>
<Typography className={styles.header} variant="h6">
{t('workflowVersionsTitle')}
</Typography>
<Typography className={styles.viewAll} variant="body1" onClick={handleViewAll}>
{t('viewAll')}
</Typography>
</div>
)}
<WaitForData {...versions}>
{showTable || showAll ? (
<WorkflowVersionsTable {...versions} isFetching={isLoadingState(versions.state)} versionView={showAll} />
) : (
<div className={styles.divider} />
)}
</WaitForData>
</>
);
};
Loading

0 comments on commit 5cd1ca5

Please sign in to comment.