Skip to content

Commit

Permalink
feat: Add Select All checkbox to workflow dag filter options
Browse files Browse the repository at this point in the history
Fixes argoproj#11129

- [x] also fixed bug when click some labels of checkboxes, they would change state of other same-named checkboxes. This was due to non-unique IDs on the checkboxes.

Signed-off-by: jmeridth <jmeridth@gmail.com>
Signed-off-by: Ben Compton <3343482+bencompton@users.noreply.github.com>
Co-Authored-by: Steven Johnson <steven.johnson@procore.com>
  • Loading branch information
jmeridth and stevenbjohnson committed May 25, 2023
1 parent 04d527c commit e273819
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 29 deletions.
4 changes: 2 additions & 2 deletions ui/src/app/shared/components/filter-drop-down.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export const FilterDropDown = (props: FilterDropDownProps) => {
.map(([label, checked]) => (
<li key={label} className={classNames('top-bar__filter-item')}>
<React.Fragment>
<Checkbox id={`filter__${label}`} checked={checked} onChange={v => item.onChange(label, v)} />
<label htmlFor={`filter__${label}`}>{label}</label>
<Checkbox id={`filter__${i}_${label}`} checked={checked} onChange={v => item.onChange(label, v)} />
<label htmlFor={`filter__${i}_${label}`}>{label}</label>
</React.Fragment>
</li>
))}
Expand Down
82 changes: 55 additions & 27 deletions ui/src/app/shared/components/graph/graph-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,21 @@ require('./graph-panel.scss');

type IconShape = 'rect' | 'circle';

interface NodeGenres {
interface NodeProps {
[type: string]: boolean;
}

interface NodeClassNames {
[type: string]: boolean;
}

interface NodeTags {
[key: string]: boolean;
}

interface Props {
graph: Graph;
storageScope: string; // the scope of storage, similar graphs should use the same vaulue
options?: React.ReactNode; // add to the option panel
classNames?: string;
nodeGenresTitle: string;
nodeGenres: NodeGenres;
nodeGenres: NodeProps;
nodeClassNamesTitle?: string;
nodeClassNames?: NodeClassNames;
nodeClassNames?: NodeProps;
nodeTagsTitle?: string;
nodeTags?: NodeTags;
nodeTags?: NodeProps;
nodeSize?: number; // default "64"
horizontal?: boolean; // default "false"
hideNodeTypes?: boolean; // default "false"
Expand All @@ -53,9 +45,10 @@ export const GraphPanel = (props: Props) => {
const [nodeSize, setNodeSize] = React.useState<number>(storage.getItem('nodeSize', props.nodeSize));
const [horizontal, setHorizontal] = React.useState<boolean>(storage.getItem('horizontal', !!props.horizontal));
const [fast, setFast] = React.useState<boolean>(storage.getItem('fast', false));
const [nodeGenres, setNodeGenres] = React.useState<NodeGenres>(storage.getItem('nodeGenres', props.nodeGenres));
const [nodeClassNames, setNodeClassNames] = React.useState<NodeClassNames>(storage.getItem('nodeClassNames', props.nodeClassNames));
const [nodeTags, setNodeTags] = React.useState<NodeTags>(props.nodeTags);
const [nodeGenres, setNodeGenres] = React.useState<NodeProps>(storage.getItem('nodeGenres', props.nodeGenres));
const [nodeClassNames, setNodeClassNames] = React.useState<NodeProps>(storage.getItem('nodeClassNames', props.nodeClassNames));
const [nodeTags, setNodeTags] = React.useState<NodeProps>(props.nodeTags);
const [checkAll, setCheckAll] = React.useState<boolean>(true);
const [nodeSearchKeyword, setNodeSearchKeyword] = React.useState<string>('');

useEffect(() => storage.setItem('nodeSize', nodeSize, props.nodeSize), [nodeSize]);
Expand All @@ -70,6 +63,24 @@ export const GraphPanel = (props: Props) => {
useEffect(() => setNodeClassNames(merge(nodeClassNames, props.nodeClassNames)), [props.nodeClassNames]);
useEffect(() => setNodeTags(merge(nodeTags, props.nodeTags)), [props.nodeTags]);

useEffect(() => {
// check if any checkboxes are unchecked, then uncheck 'Check All'
const checkboxes = [nodeGenres, nodeClassNames, nodeTags];
let uncheckedFound = false;
checkboxes.forEach(prop => {
Object.keys(prop).forEach(key => {
if (!prop[key]) {
setCheckAll(false);
uncheckedFound = true;
}
});
});
// if no checkboxes are unchecked, check 'Check All'
if (!uncheckedFound) {
setCheckAll(true);
}
}, [nodeGenres, nodeClassNames, nodeTags]);

const visible = (id: Node) => {
const label = props.graph.nodes.get(id);
// If the node matches the search string, return without considering filters
Expand All @@ -91,6 +102,24 @@ export const GraphPanel = (props: Props) => {
return true;
};

const check = () => {
const items = [nodeGenres, nodeClassNames, nodeTags];
items.forEach(item => {
Object.keys(item).forEach(key => {
item[key] = !checkAll;
});
});
};

const checkBoxHandler = (callback: React.Dispatch<React.SetStateAction<NodeProps>>, label: string, checked: boolean) => {
callback(v => {
return {
...v,
[label]: checked
};
});
};

layout(props.graph, nodeSize, horizontal, id => !visible(id), fast);
const width = props.graph.width;
const height = props.graph.height;
Expand All @@ -101,34 +130,33 @@ export const GraphPanel = (props: Props) => {
<div className='graph-options-panel'>
<FilterDropDown
sections={[
{
title: '',
values: {'Check All': checkAll},
onChange: (_, checked) => {
setCheckAll(checked);
check();
}
},
{
title: props.nodeGenresTitle,
values: nodeGenres,
onChange: (label, checked) => {
setNodeGenres(v => {
v[label] = checked;
return Object.assign({}, v);
});
checkBoxHandler(setNodeGenres, label, checked);
}
},
{
title: props.nodeClassNamesTitle,
values: nodeClassNames,
onChange: (label, checked) => {
setNodeClassNames(v => {
v[label] = checked;
return Object.assign({}, v);
});
checkBoxHandler(setNodeClassNames, label, checked);
}
},
{
title: props.nodeTagsTitle,
values: nodeTags,
onChange: (label, checked) => {
setNodeTags(v => {
v[label] = checked;
return Object.assign({}, v);
});
checkBoxHandler(setNodeTags, label, checked);
}
}
]}
Expand Down

0 comments on commit e273819

Please sign in to comment.