diff --git a/src/components/Entities/EntityDetails.tsx b/src/components/Entities/EntityDetails.tsx index d464827c0..d8cb199e2 100644 --- a/src/components/Entities/EntityDetails.tsx +++ b/src/components/Entities/EntityDetails.tsx @@ -4,6 +4,7 @@ import { contentMarginGridUnits } from 'common/layout'; import { WaitForData } from 'components/common/WaitForData'; import { EntityDescription } from 'components/Entities/EntityDescription'; import { useProject } from 'components/hooks/useProjects'; +import { useChartState } from 'components/hooks/useChartState'; import { LaunchForm } from 'components/Launch/LaunchForm/LaunchForm'; import { ResourceIdentifier, ResourceType } from 'models/Common/types'; import * as React from 'react'; @@ -82,6 +83,7 @@ export const EntityDetails: React.FC = ({ const [showLaunchForm, setShowLaunchForm] = React.useState(false); const onLaunch = () => setShowLaunchForm(true); const onCancelLaunch = () => setShowLaunchForm(false); + const { chartIds, onToggle, clearCharts } = useChartState(); return ( @@ -120,10 +122,20 @@ export const EntityDetails: React.FC = ({ ) : null} - {!versionView && } + {!versionView && ( + + )} {sections.executions && !versionView ? (
- +
) : null} {sections.launch ? ( diff --git a/src/components/Entities/EntityExecutions.tsx b/src/components/Entities/EntityExecutions.tsx index 77a52a048..d4012388b 100644 --- a/src/components/Entities/EntityExecutions.tsx +++ b/src/components/Entities/EntityExecutions.tsx @@ -25,10 +25,16 @@ const useStyles = makeStyles((theme: Theme) => ({ export interface EntityExecutionsProps { id: ResourceIdentifier; + chartIds: string[]; + clearCharts: () => void; } /** The tab/page content for viewing a workflow's executions */ -export const EntityExecutions: React.FC = ({ id }) => { +export const EntityExecutions: React.FC = ({ + id, + chartIds, + clearCharts +}) => { const { domain, project, resourceType } = id; const styles = useStyles(); const filtersState = useWorkflowExecutionFiltersState(); @@ -50,6 +56,10 @@ export const EntityExecutions: React.FC = ({ id }) => { } ); + if (chartIds.length > 0) + executions.value = executions.value.filter(item => + chartIds.includes(item.id.name) + ); /** Don't render component until finish fetching user profile */ if (filtersState.filters[4].status !== 'LOADED') { return null; @@ -61,7 +71,11 @@ export const EntityExecutions: React.FC = ({ id }) => { All Executions in the Workflow
- +
({ export interface EntityExecutionsBarChartProps { id: ResourceIdentifier; + onToggle: (id: string) => void; + chartIds: string[]; } const getExecutionTimeData = (executions: Execution[], fillSize = 100) => { @@ -88,7 +90,9 @@ const getStartExecutionTime = (executions: Execution[]) => { * @constructor */ export const EntityExecutionsBarChart: React.FC = ({ - id + id, + onToggle, + chartIds }) => { const styles = useStyles(); const { domain, project, resourceType } = id; @@ -116,6 +120,7 @@ export const EntityExecutionsBarChart: React.FC = const handleClickItem = React.useCallback(item => { if (item.metadata) { + onToggle(item.metadata.name); // const executionId = item.metadata as WorkflowExecutionIdentifier; // history.push(Routes.ExecutionDetails.makeUrl(executionId)); } @@ -133,6 +138,7 @@ export const EntityExecutionsBarChart: React.FC =
= ({ filter }) => { */ export const ExecutionFilters: React.FC<{ filters: (FilterState | BooleanFilterState)[]; -}> = ({ filters }) => { + chartIds?: string[]; + clearCharts?: () => void; +}> = ({ filters, chartIds, clearCharts }) => { const styles = useStyles(); + filters = filters.map(filter => { + const onChangeFunc = filter.onChange; + filter.onChange = value => { + if (clearCharts) clearCharts(); + if (onChangeFunc) onChangeFunc(value); + }; + return filter; + }); + return (
{filters.map((filter: any) => { @@ -102,6 +113,17 @@ export const ExecutionFilters: React.FC<{ /> ); })} + {chartIds && chartIds.length > 0 && ( + <>} + className={styles.filterButton} + buttonText="Clear Manually Selected Executions" + onReset={clearCharts} + key="charts" + /> + )}
); }; diff --git a/src/components/Executions/filters/types.ts b/src/components/Executions/filters/types.ts index 9cac7f27c..c57799553 100644 --- a/src/components/Executions/filters/types.ts +++ b/src/components/Executions/filters/types.ts @@ -31,6 +31,7 @@ export interface FilterState { status?: string; getFilter: () => FilterOperation[]; onReset: () => void; + onChange?: (value) => void; } export interface SingleFilterState diff --git a/src/components/Executions/filters/useSingleFilterState.ts b/src/components/Executions/filters/useSingleFilterState.ts index be1ab1d33..ca2255839 100644 --- a/src/components/Executions/filters/useSingleFilterState.ts +++ b/src/components/Executions/filters/useSingleFilterState.ts @@ -61,7 +61,7 @@ export function useSingleFilterState({ useEffect(() => { const { value } = selectedOption; - const queryValue = value === defaultValue.value ? undefined : value; + const queryValue = value; setQueryStateValue(queryStateKey, queryValue); }, [selectedOption, queryStateKey]); diff --git a/src/components/common/BarChart.tsx b/src/components/common/BarChart.tsx index e1cfc3c87..e7cc956c4 100644 --- a/src/components/common/BarChart.tsx +++ b/src/components/common/BarChart.tsx @@ -27,7 +27,8 @@ const useStyles = makeStyles((theme: Theme) => ({ item: { flex: 1, display: 'flex', - alignItems: 'flex-end', + flexDirection: 'column', + alignItems: 'center', '&:last-child': { marginRight: 0 } @@ -37,7 +38,9 @@ const useStyles = makeStyles((theme: Theme) => ({ flex: 1, marginRight: theme.spacing(0.25), minHeight: theme.spacing(0.75), - cursor: 'pointer' + cursor: 'pointer', + width: '80%', + marginLeft: '10%' } })); @@ -50,12 +53,14 @@ interface BarChartData { interface BarChartItemProps extends BarChartData { onClick?: () => void; + isSelected: boolean; } interface BarChartProps { data: BarChartData[]; startDate?: string; onClickItem?: (item: any) => void; + chartIds: string[]; } /** @@ -67,6 +72,7 @@ interface BarChartProps { const BarChartItem: React.FC = ({ value, color, + isSelected, tooltip, onClick }) => { @@ -74,11 +80,17 @@ const BarChartItem: React.FC = ({ const [position, setPosition] = React.useState({ x: 0, y: 0 }); const content = ( -
+ <> +
+ ); return ( @@ -121,6 +133,7 @@ const BarChartItem: React.FC = ({ * @constructor */ export const BarChart: React.FC = ({ + chartIds, data, startDate, onClickItem @@ -154,6 +167,12 @@ export const BarChart: React.FC = ({ tooltip={item.tooltip} onClick={handleClickItem(item)} key={`bar-chart-item-${index}`} + isSelected={ + chartIds.length === 0 + ? true + : item.metadata && + chartIds.includes(item.metadata.name) + } /> ))}
diff --git a/src/components/hooks/useChartState.ts b/src/components/hooks/useChartState.ts new file mode 100644 index 000000000..c59b29366 --- /dev/null +++ b/src/components/hooks/useChartState.ts @@ -0,0 +1,27 @@ +import { useState } from 'react'; + +export function useChartState() { + const [chartIds, setChartIds] = useState([]); + const onToggle = (id: string) => { + setChartIds(curIds => { + const newChartIds = [...curIds]; + if (newChartIds.includes(id)) { + const index = newChartIds.indexOf(id); + newChartIds.splice(index, 1); + } else { + newChartIds.push(id); + } + return newChartIds; + }); + }; + + const clearCharts = () => { + setChartIds([]); + }; + + return { + onToggle, + clearCharts, + chartIds + }; +}