Skip to content

Commit

Permalink
👻 Target api updates (#1239)
Browse files Browse the repository at this point in the history
UI changes relating to konveyor/tackle2-hub#464

- Rename setting for ruleset/target order to match api changes
- Change TS model for Ruleset to match api changes. Ruleset is now a
field on the target model and can be appended to directly / read from
directly when performing CRUD operations against a custom target.
- Drive target card selection from label rather than ruleset/target
since we no longer need to store the entire ruleset/target state in the
wizard. This is because the analyzer no longer requires it to be passed
in the TaskData. We are now only passing labels. This simplifies the
wizard state & allows tracking of individual ruleset selection/ source
selection/ target selection to be removed.
- Now we can drive the select targets / select sources dropdowns on the
set-options analysis wizard form from labels rather than tracking
specific state for either of those.
- Changes format of default sources/targets to match new hub api label
format

---------

Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 authored Aug 7, 2023
1 parent 1ff5686 commit 54ecd36
Show file tree
Hide file tree
Showing 22 changed files with 823 additions and 829 deletions.
1 change: 0 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
"react-dom": "^17.0.2",
"react-hook-form": "^7.43.1",
"react-i18next": "^11.8.5",
"react-image-file-resizer": "^0.4.8",
"react-markdown": "^8.0.7",
"react-measure": "^2.5.2",
"react-monaco-editor": "0.51.0",
Expand Down
32 changes: 24 additions & 8 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ export type SettingTypes = {
"mvn.insecure.enabled": boolean;
"review.assessment.required": boolean;
"svn.insecure.enabled": boolean;
"ui.ruleset.order": number[];
"ui.target.order": number[];
};

export type Setting<K extends keyof SettingTypes> = {
Expand Down Expand Up @@ -404,7 +404,6 @@ export interface TaskData {
tags: {
excluded: string[];
};
rulesets: Ref[];
repository?: Repository;
identity?: Ref;
labels: {
Expand Down Expand Up @@ -463,18 +462,29 @@ export enum RulesetKind {
}

export interface Ruleset {
createTime?: string;
createUser?: string;
description?: string;
id?: number;
image?: RulesetImage;
kind?: RulesetKind;
name: string;
name?: string;
description?: string;
rules: Rule[];
custom?: boolean;
repository?: Repository;
identity?: Ref;
}
export interface TargetLabel {
name: string;
label: string;
}
export interface Target {
id?: number;
name: string;
description?: string;
choice?: boolean;
custom?: boolean;
labels?: TargetLabel[];
image?: RulesetImage;
ruleset: Ruleset;
}

export interface Metadata {
target: string;
source?: string;
Expand Down Expand Up @@ -688,3 +698,9 @@ export type Fact = {
//TODO: Address this when moving to structured facts api
data: any;
};

export type HubFile = {
id: number;
name: string;
path: string;
};
26 changes: 12 additions & 14 deletions client/src/app/api/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
JobFunction,
Proxy,
Review,
Ruleset,
Setting,
SettingTypes,
Stakeholder,
Expand All @@ -49,6 +48,8 @@ import {
AnalysisAppDependency,
AnalysisAppReport,
Rule,
Target,
HubFile,
} from "./models";
import { QueryKey } from "@tanstack/react-query";
import { serializeRequestParamsForHub } from "@app/shared/hooks/table-controls";
Expand Down Expand Up @@ -84,7 +85,7 @@ export const TRACKER_PROJECT_ISSUETYPES = "issuetypes";
export const TICKETS = HUB + "/tickets";
export const FACTS = HUB + "/facts";

export const RULESETS = HUB + "/rulesets";
export const TARGETS = HUB + "/targets";
export const FILES = HUB + "/files";
export const CACHE = HUB + "/cache/m2";

Expand Down Expand Up @@ -440,20 +441,17 @@ export const deleteAllMigrationWaves = (
.catch((error) => error);
};

export const updateRuleset = (obj: Ruleset): Promise<Ruleset> =>
axios.put(`${RULESETS}/${obj.id}`, obj);
export const updateTarget = (obj: Target): Promise<Target> =>
axios.put(`${TARGETS}/${obj.id}`, obj);

export const createRuleset = (obj: Ruleset): Promise<Ruleset> =>
axios.post(RULESETS, obj);
export const createTarget = (obj: Target): Promise<Target> =>
axios.post(TARGETS, obj);

export const deleteRuleset = (id: number): Promise<Ruleset> =>
axios.delete(`${RULESETS}/${id}`);
export const deleteTarget = (id: number): Promise<Target> =>
axios.delete(`${TARGETS}/${id}`);

export const getRulesets = (): Promise<Ruleset[]> =>
axios.get(RULESETS).then((response) => response.data);

export const getFileByID = (id: number): Promise<Ruleset[]> =>
axios.get(FILES).then((response) => response.data);
export const getTargets = (): Promise<Target[]> =>
axios.get(TARGETS).then((response) => response.data);

export const createFile = ({
formData,
Expand All @@ -463,7 +461,7 @@ export const createFile = ({
file: IReadFile;
}) =>
axios
.post<Ruleset>(`${FILES}/${file.fileName}`, formData, fileHeaders)
.post<HubFile>(`${FILES}/${file.fileName}`, formData, fileHeaders)
.then((response) => {
return response.data;
});
Expand Down
8 changes: 1 addition & 7 deletions client/src/app/common/CustomRules/rules-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IReadFile, ParsedRule, Rule, Ruleset } from "@app/api/models";
import { IReadFile, ParsedRule } from "@app/api/models";
import yaml from "js-yaml";

type RuleFileType = "YAML" | "XML" | null;
Expand Down Expand Up @@ -136,9 +136,3 @@ export const getLabels = (labels: string[]) =>
},
{ sourceLabel: "", targetLabel: "", otherLabels: [], allLabels: [] }
);

export const getRulesetTargetList = (ruleset: Ruleset) => {
return ruleset.rules.reduce((acc: string[], rule) => {
return [...acc, rule?.metadata?.target || ""];
}, []);
};
2 changes: 1 addition & 1 deletion client/src/app/common/CustomRules/useRuleFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NotificationsContext } from "@app/shared/notifications-context";
import { AxiosError } from "axios";
import { useUploadFileMutation } from "@app/queries/taskgroups";
import { getAxiosErrorMessage } from "@app/utils/utils";
import { useCreateFileMutation } from "@app/queries/rulesets";
import { useCreateFileMutation } from "@app/queries/targets";
import { CustomTargetFormValues } from "@app/pages/migration-targets/components/custom-target-form";
import { UseFormReturn } from "react-hook-form";
import { XMLValidator } from "fast-xml-parser";
Expand Down
4 changes: 4 additions & 0 deletions client/src/app/components/target-card.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.panel-style {
background: none;
}

.select-card__component__empty-state {
padding: 0 !important;
}
Expand Down
109 changes: 60 additions & 49 deletions client/src/app/components/target-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
ButtonVariant,
Label,
CardHeader,
PanelMain,
PanelMainBody,
Panel,
} from "@patternfly/react-core";
import { DropdownItem } from "@patternfly/react-core/deprecated";
import {
Expand All @@ -28,31 +31,34 @@ import { KebabDropdown } from "@app/shared/components";
import { useTranslation } from "react-i18next";
import "./target-card.css";
import DefaultRulesetIcon from "@app/images/Icon-Red_Hat-Virtual_server_stack-A-Black-RGB.svg";
import { Ruleset } from "@app/api/models";
import { getParsedLabel } from "@app/common/CustomRules/rules-utils";
import { Target, TargetLabel } from "@app/api/models";

export interface TargetCardProps {
item: Ruleset;
item: Target;
cardSelected?: boolean;
isEditable?: boolean;
onCardClick?: (isSelecting: boolean, value: string) => void;
onCardClick?: (
isSelecting: boolean,
targetLabelName: string,
target: Target
) => void;
onSelectedCardTargetChange?: (value: string) => void;
formTargets?: string[];
formLabels?: TargetLabel[];
handleProps?: any;
readOnly?: boolean;
onEdit?: () => void;
onDelete?: () => void;
}

// Force display dropdown box even though there only one option available.
// This is a business rule to guarantee that option is alwyas present.
// This is a business rule to guarantee that option is always present.
const forceSelect = ["Azure"];

export const TargetCard: React.FC<TargetCardProps> = ({
item,
item: target,
readOnly,
cardSelected,
formTargets,
formLabels,
onCardClick,
onSelectedCardTargetChange,
handleProps,
Expand All @@ -62,19 +68,18 @@ export const TargetCard: React.FC<TargetCardProps> = ({
const { t } = useTranslation();
const [isCardSelected, setCardSelected] = React.useState(cardSelected);

const prevSelectedTarget = formTargets?.find(
(target) =>
item.rules.map((ruleset) => ruleset?.metadata?.target).indexOf(target) !==
-1
);
const prevSelectedLabel =
formLabels?.find((formLabel) => {
const labelNames = target?.labels?.map((label) => label.name);
return labelNames?.includes(formLabel.name);
})?.name || "";

const [isRuleTargetSelectOpen, setRuleTargetSelectOpen] =
React.useState(false);
const [isLabelSelectOpen, setLabelSelectOpen] = React.useState(false);

const [selectedRuleTarget, setSelectedRuleTarget] = React.useState(
prevSelectedTarget ||
item.rules[0]?.metadata?.target ||
`${item.name}-Empty`
const [selectedLabelName, setSelectedLabelName] = React.useState<string>(
prevSelectedLabel ||
target?.labels?.[0]?.name ||
`${target?.name || "target"}-Empty`
);

const handleCardClick = (event: React.MouseEvent) => {
Expand All @@ -84,30 +89,28 @@ export const TargetCard: React.FC<TargetCardProps> = ({

setCardSelected(!isCardSelected);
onCardClick &&
selectedRuleTarget &&
onCardClick(!isCardSelected, selectedRuleTarget);
selectedLabelName &&
onCardClick(!isCardSelected, selectedLabelName, target);
};

const handleRuleTargetSelection = (
const handleLabelSelection = (
event: React.MouseEvent | React.ChangeEvent,
selection: string | SelectOptionObject
) => {
event.stopPropagation();
setRuleTargetSelectOpen(false);
setSelectedRuleTarget(selection as string);

//update the formTargets if this card is selected
setLabelSelectOpen(false);
setSelectedLabelName(selection as string);
if (isCardSelected && onSelectedCardTargetChange) {
onSelectedCardTargetChange(selection as string);
}
};

const getImage = (): React.ComponentType => {
let result: React.ComponentType<any> = CubesIcon;
const imagePath = item?.image?.id
? `/hub/files/${item.image.id}`
const imagePath = target?.image?.id
? `/hub/files/${target?.image.id}`
: DefaultRulesetIcon;
if (item.image) {
if (target.image) {
result = () => (
<img
src={imagePath}
Expand All @@ -129,7 +132,7 @@ export const TargetCard: React.FC<TargetCardProps> = ({
>
<CardHeader
selectableActions={{
selectableActionId: "" + item.id,
selectableActionId: "" + target.id,
isChecked: isCardSelected,
}}
/>
Expand All @@ -151,10 +154,10 @@ export const TargetCard: React.FC<TargetCardProps> = ({
)}
</FlexItem>
<FlexItem className={spacing.mlAuto}>
{readOnly && item.custom ? (
{readOnly && target.custom ? (
<Label color="grey">Custom</Label>
) : (
item.custom && (
target.custom && (
<KebabDropdown
dropdownItems={[
<DropdownItem key="edit-custom-card" onClick={onEdit}>
Expand All @@ -175,32 +178,40 @@ export const TargetCard: React.FC<TargetCardProps> = ({
>
<EmptyStateIcon icon={getImage()} />
<Title headingLevel="h4" size="md">
{item.name}
{target.name}
</Title>
{item.kind === "category" &&
(item.rules.length > 1 || forceSelect.includes(item.name)) ? (
{target.choice &&
((!!target?.labels?.length && target?.labels?.length > 1) ||
forceSelect.includes(target.name)) ? (
<Select
toggleId={`${item.name}-toggle`}
className={spacing.mtSm}
toggleId={`${target.name}-toggle`}
variant={SelectVariant.single}
aria-label="Select Input"
onToggle={(_, isExpanded) => setRuleTargetSelectOpen(isExpanded)}
onSelect={handleRuleTargetSelection}
selections={selectedRuleTarget}
isOpen={isRuleTargetSelectOpen}
aria-label="Select Label"
onToggle={(_, isExpanded) => setLabelSelectOpen(isExpanded)}
onSelect={handleLabelSelection}
selections={selectedLabelName}
isOpen={isLabelSelectOpen}
width={250}
>
{item.rules.map((rule) => (
<SelectOption key={rule.name} value={rule?.metadata?.target}>
{rule?.metadata?.target
? getParsedLabel(rule.metadata.target)?.labelValue
: "Empty"}
{target?.labels?.map((label) => (
<SelectOption key={label.name} value={label.name}>
{label.name ? label.name : "Empty"}
</SelectOption>
))}
</Select>
) : null}
<Text className={`${spacing.pMd} pf-v5-u-text-align-left`}>
{item.description}
</Text>
{target.description ? (
<Panel isScrollable className="panel-style">
<PanelMain maxHeight={target.choice ? "9em" : "12em"}>
<PanelMainBody>
<Text className={`${spacing.pMd} pf-v5-u-text-align-left`}>
{target.description}
</Text>
</PanelMainBody>
</PanelMain>
</Panel>
) : null}
</EmptyState>
</CardBody>
</Card>
Expand Down
Loading

0 comments on commit 54ecd36

Please sign in to comment.