Skip to content

Commit

Permalink
Add language options from providers & select by app tags
Browse files Browse the repository at this point in the history
Move to simple multi select menu in set targets step

Drive target selection options from targets list

Add kind support for tasks

Address missing checkbox on deselect

Add provider to target card header

Signed-off-by: Ian Bolton <[email protected]>
  • Loading branch information
ibolton336 committed Jun 12, 2024
1 parent 799ee18 commit 6c07c23
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 51 deletions.
8 changes: 5 additions & 3 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ export interface Task {
createTime?: string;
application: { id: number };
name: string;
addon: string;
kind?: string;
addon?: string;
data: TaskData;
error?: string;
image?: string;
Expand Down Expand Up @@ -377,7 +378,8 @@ export interface TaskgroupTask {
export interface Taskgroup {
id?: number;
name: string;
addon: string;
kind?: string;
addon?: string;
data: TaskData;
tasks: TaskgroupTask[];
}
Expand Down Expand Up @@ -425,7 +427,7 @@ export interface Target {
labels?: TargetLabel[];
image?: RulesetImage;
ruleset: Ruleset;
provider?: string;
provider?: string[];
}

export interface Metadata {
Expand Down
133 changes: 133 additions & 0 deletions client/src/app/components/SimpleSelectCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React from "react";
import {
Select,
SelectOption,
SelectList,
MenuToggle,
Badge,
SelectOptionProps,
MenuToggleElement,
} from "@patternfly/react-core";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";

export interface ISimpleSelectBasicProps {
onChange: (selection: string | string[]) => void;
options: SelectOptionProps[];
value?: string[];
placeholderText?: string;
id?: string;
toggleId?: string;
toggleAriaLabel?: string;
selectMultiple?: boolean;
width?: number;
noResultsFoundText?: string;
hideClearButton?: false;
}

export const SimpleSelectCheckbox: React.FC<ISimpleSelectBasicProps> = ({
onChange,
options,
value,
placeholderText = "Select...",
id,
toggleId,
toggleAriaLabel,
width,
}) => {
const [isOpen, setIsOpen] = React.useState(false);
const [selectedItems, setSelectedItems] = React.useState<string[]>([]);
const [selectOptions, setSelectOptions] = React.useState<SelectOptionProps[]>(
[
{ value: "select-all", label: "Select All", children: "Select All" },
...options,
]
);

React.useEffect(() => {
setSelectedItems(value || []);
}, [value]);

React.useEffect(() => {
const updatedOptions = [
{ value: "select-all", label: "Select All", children: "Select All" },
...options,
];
setSelectOptions(updatedOptions);
}, [options]);

const onToggleClick = () => {
setIsOpen(!isOpen);
};

const onSelect = (
_event: React.MouseEvent<Element, MouseEvent> | undefined,
selectionValue: string | number | undefined
) => {
const value = selectionValue as string;
if (value === "select-all") {
if (selectedItems.length === options.length) {
setSelectedItems([]);
onChange([]);
} else {
const allItemValues = options.map((option) => option.value as string);
setSelectedItems(allItemValues);
onChange(allItemValues);
}
} else {
if (selectedItems.includes(value)) {
const newSelections = selectedItems.filter((item) => item !== value);
setSelectedItems(newSelections);
onChange(newSelections);
} else {
const newSelections = [...selectedItems, value];
setSelectedItems(newSelections);
onChange(newSelections);
}
}
};

return (
<Select
role="menu"
id={id}
isOpen={isOpen}
selected={selectedItems}
onSelect={onSelect}
onOpenChange={setIsOpen}
toggle={(toggleref: React.Ref<MenuToggleElement>) => (
<MenuToggle
ref={toggleref}
onClick={onToggleClick}
style={{ width: width && width + "px" }}
isExpanded={isOpen}
id={toggleId}
>
<span className={spacing.mrSm}>{placeholderText}</span>
{selectedItems.length > 0 && (
<Badge isRead>{selectedItems.length}</Badge>
)}
</MenuToggle>
)}
aria-label={toggleAriaLabel}
>
<SelectList>
{selectOptions.map((option, index) => (
<SelectOption
hasCheckbox
key={option.value}
isFocused={index === 0}
onClick={() => onSelect(undefined, option.value)}
isSelected={
option.value === "select-all"
? selectedItems.length === options.length
: selectedItems.includes(option.value as string)
}
{...option}
>
{option.children || option.value}
</SelectOption>
))}
</SelectList>
</Select>
);
};
32 changes: 18 additions & 14 deletions client/src/app/components/SimpleSelectTypeahead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
export interface ISimpleSelectBasicProps {
onChange: (selection: string | string[]) => void;
options: SelectOptionProps[];
value?: string;
value?: string[];
placeholderText?: string;
id?: string;
toggleId?: string;
Expand All @@ -45,9 +45,10 @@ export const SimpleSelectTypeahead: React.FC<ISimpleSelectBasicProps> = ({
}) => {
const [isOpen, setIsOpen] = React.useState(false);
const [selected, setSelected] = React.useState<string | string[]>(
selectMultiple ? [] : ""
selectMultiple ? value || [] : value || ""
);
const [inputValue, setInputValue] = React.useState<string>(value || "");

const [inputValue, setInputValue] = React.useState<string>("");
const [filterValue, setFilterValue] = React.useState<string>("");
const [selectOptions, setSelectOptions] =
React.useState<SelectOptionProps[]>(options);
Expand All @@ -56,6 +57,7 @@ export const SimpleSelectTypeahead: React.FC<ISimpleSelectBasicProps> = ({
);
const [activeItem, setActiveItem] = React.useState<string | null>(null);
const textInputRef = React.useRef<HTMLInputElement>();

React.useEffect(() => {
let newSelectOptions: SelectOptionProps[] = options;

Expand Down Expand Up @@ -220,17 +222,19 @@ export const SimpleSelectTypeahead: React.FC<ISimpleSelectBasicProps> = ({
{selectMultiple && (
<ChipGroup aria-label="Current selections">
{(Array.isArray(selected) ? selected : [selected]).map(
(sel, index) => (
<Chip
key={index}
onClick={(ev) => {
ev.stopPropagation();
onSelect(undefined, sel);
}}
>
{sel}
</Chip>
)
(sel, index) => {
return (
<Chip
key={index}
onClick={(ev) => {
ev.stopPropagation();
onSelect(undefined, sel);
}}
>
{sel}
</Chip>
);
}
)}
</ChipGroup>
)}
Expand Down
16 changes: 13 additions & 3 deletions client/src/app/components/target-card/target-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
SelectVariant,
SelectOptionObject,
} from "@patternfly/react-core/deprecated";
import { GripVerticalIcon } from "@patternfly/react-icons";
import { GripVerticalIcon, InfoCircleIcon } from "@patternfly/react-icons";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { useTranslation } from "react-i18next";

Expand Down Expand Up @@ -86,6 +86,7 @@ export const TargetCard: React.FC<TargetCardProps> = ({

const handleCardClick = (event: React.MouseEvent) => {
// Stop 'select' event propagation
event.preventDefault();
const eventTarget: any = event.target;
if (eventTarget.type === "button") return;

Expand All @@ -110,16 +111,25 @@ export const TargetCard: React.FC<TargetCardProps> = ({
return (
<Card
onClick={handleCardClick}
isSelectable={!!cardSelected}
isSelectable
isSelected={isCardSelected}
className="pf-v5-l-stack pf-v5-l-stack__item pf-m-fill"
>
<CardHeader
selectableActions={{
selectableActionId: "" + target.id,
selectableActionAriaLabelledby: `${target.name}-selectable-action-label`,
isChecked: isCardSelected,
}}
/>
>
<Label
id={`${target.provider}-selectable-action-label`}
variant="outline"
icon={<InfoCircleIcon />}
>
{target.provider}
</Label>
</CardHeader>
<CardBody>
<Flex>
<FlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const defaultTaskData: TaskData = {

export const defaultTaskgroup: Taskgroup = {
name: `taskgroup.analyzer`,
addon: "analyzer",
kind: "analyzer",
data: {
...defaultTaskData,
},
Expand Down Expand Up @@ -359,7 +359,7 @@ export const AnalysisWizard: React.FC<IAnalysisWizard> = ({
isDisabled={!isStepEnabled(StepId.SetTargets)}
footer={{ isNextDisabled: !isStepEnabled(StepId.SetTargets + 1) }}
>
<SetTargets />
<SetTargets applications={applications} />
</WizardStep>,
<WizardStep
key={StepId.Scope}
Expand Down
Loading

0 comments on commit 6c07c23

Please sign in to comment.