Skip to content

Commit

Permalink
✨ Identified risks enhancements (#1573)
Browse files Browse the repository at this point in the history
Resolves: 
https://issues.redhat.com/browse/MTA-1723 
https://issues.redhat.com/browse/MTA-1749
https://issues.redhat.com/browse/MTA-1754
https://issues.redhat.com/browse/MTA-1762

Resolves: #1568 
Resolves: #1570
Resolves: #1569

  - New query to collate all apps that are inheriting a specific
    assessment based on underlying archetype inheritance. Use this new data
    to fix the applications column in the identified risks table to
    accurately reflect which applications have a specific risk level for a
    given answer.
  - Adds the ability to filter the applications table by the applications
    shown within the identified risks column.
  - Adds expandable functionality for rationale and mitigation text
  - Adds risk column for answer risk level
  - Link to risk filtered app inventory from landscape in reports page

---------

Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 committed Nov 30, 2023
1 parent f620e0a commit 85ac7b4
Show file tree
Hide file tree
Showing 23 changed files with 697 additions and 668 deletions.
2 changes: 2 additions & 0 deletions client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
"noDataStateBody": "Create a new {{what}} to start seeing data here.",
"noDataStateTitle": "No {{what}} available",
"Nquestions": "{{n}} questions",
"ofTotalApplications": "Of {{count}} application",
"ofTotalApplications_plural": "Of {{count}} applications",
"ofTotalAssessments": "Of {{count}} assessment",
"ofTotalAssessments_plural": "Of {{count}} assessments",
"selectMany": "Select {{what}}",
Expand Down
8 changes: 8 additions & 0 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export interface Ref {
id: number;
name: string;
}
export interface IdRef {
id: number;
}

export interface JobFunction {
id: number;
Expand Down Expand Up @@ -773,3 +776,8 @@ export interface SectionWithQuestionOrder extends Section {
export interface AssessmentWithSectionOrder extends Assessment {
sections: SectionWithQuestionOrder[];
}

export interface AssessmentWithArchetypeApplications
extends AssessmentWithSectionOrder {
archetypeApplications: Ref[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@ export const MultiselectFilterControl = <TItem,>({
const input = textInput?.toLowerCase();

return renderSelectOptions((optionProps, groupName) => {
if (!input) return false;

// TODO: Checking for a filter match against the key or the value may not be desirable.
return (
groupName?.toLowerCase().includes(input) ||
Expand Down
16 changes: 2 additions & 14 deletions client/src/app/components/answer-table/answer-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { IconedStatus } from "@app/components/IconedStatus";
import { TimesCircleIcon } from "@patternfly/react-icons";
import { WarningTriangleIcon } from "@patternfly/react-icons";
import { List, ListItem } from "@patternfly/react-core";
import RiskIcon from "../risk-icon/risk-icon";

export interface IAnswerTableProps {
answers: Answer[];
Expand Down Expand Up @@ -45,19 +46,6 @@ const AnswerTable: React.FC<IAnswerTableProps> = ({
propHelpers: { tableProps, getThProps, getTrProps, getTdProps },
} = tableControls;

const getIconByRisk = (risk: string): React.ReactElement => {
switch (risk) {
case "green":
return <IconedStatus preset="Ok" />;
case "red":
return <IconedStatus icon={<TimesCircleIcon />} status="danger" />;
case "yellow":
return <IconedStatus icon={<WarningTriangleIcon />} status="warning" />;
default:
return <IconedStatus preset="Unknown" />;
}
};

return (
<>
<Table {...tableProps} aria-label={`Answer table for question`}>
Expand Down Expand Up @@ -126,7 +114,7 @@ const AnswerTable: React.FC<IAnswerTableProps> = ({
{answer.text}
</Td>
<Td width={20} {...getTdProps({ columnKey: "choice" })}>
{getIconByRisk(answer.risk)}
<RiskIcon risk={answer.risk} />
</Td>
</TableRowContentWithControls>
</Tr>
Expand Down
22 changes: 22 additions & 0 deletions client/src/app/components/risk-icon/risk-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import { TimesCircleIcon, WarningTriangleIcon } from "@patternfly/react-icons";
import { IconedStatus } from "@app/components/IconedStatus";

interface RiskIconProps {
risk: string;
}

const RiskIcon: React.FC<RiskIconProps> = ({ risk }) => {
switch (risk) {
case "green":
return <IconedStatus preset="Ok" />;
case "red":
return <IconedStatus icon={<TimesCircleIcon />} status="danger" />;
case "yellow":
return <IconedStatus icon={<WarningTriangleIcon />} status="warning" />;
default:
return <IconedStatus preset="Unknown" />;
}
};

export default RiskIcon;
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type IFilterStateArgs<
* Definitions of the filters to be used (must include `getItemValue` functions for each category when performing filtering locally)
*/
filterCategories: FilterCategory<TItem, TFilterCategoryKey>[];
initialFilterValues?: IFilterValues<TFilterCategoryKey>;
}
>;

Expand All @@ -63,6 +64,10 @@ export const useFilterState = <
): IFilterState<TFilterCategoryKey> => {
const { isFilterEnabled, persistTo = "state", persistenceKeyPrefix } = args;

const initialFilterValues: IFilterValues<TFilterCategoryKey> = isFilterEnabled
? args?.initialFilterValues ?? {}
: {};

// We won't need to pass the latter two type params here if TS adds support for partial inference.
// See https://github.com/konveyor/tackle2-ui/issues/1456
const [filterValues, setFilterValues] = usePersistentState<
Expand All @@ -71,7 +76,7 @@ export const useFilterState = <
"filters"
>({
isEnabled: !!isFilterEnabled,
defaultValue: {},
defaultValue: initialFilterValues,
persistenceKeyPrefix,
// Note: For the discriminated union here to work without TypeScript getting confused
// (e.g. require the urlParams-specific options when persistTo === "urlParams"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ import WarningTriangleIcon from "@patternfly/react-icons/dist/esm/icons/warning-

// Hooks
import { useQueryClient } from "@tanstack/react-query";
import { useLocalTableControls } from "@app/hooks/table-controls";
import {
deserializeFilterUrlParams,
useLocalTableControls,
} from "@app/hooks/table-controls";

// Queries
import { Application, Assessment, Ref, Task } from "@app/api/models";
Expand Down Expand Up @@ -303,6 +306,11 @@ export const ApplicationsTable: React.FC = () => {
}
};

const urlParams = new URLSearchParams(window.location.search);
const filters = urlParams.get("filters");

const deserializedFilterValues = deserializeFilterUrlParams({ filters });

const tableControls = useLocalTableControls({
idProperty: "id",
items: applications || [],
Expand All @@ -321,6 +329,7 @@ export const ApplicationsTable: React.FC = () => {
isActiveItemEnabled: true,
sortableColumns: ["name", "businessService", "tags", "effort"],
initialSort: { columnKey: "name", direction: "asc" },
initialFilterValues: deserializedFilterValues,
getSortValues: (app) => ({
name: app.name,
businessService: app.businessService?.name || "",
Expand All @@ -331,12 +340,17 @@ export const ApplicationsTable: React.FC = () => {
{
key: "name",
title: t("terms.name"),
type: FilterType.search,
type: FilterType.multiselect,
placeholderText:
t("actions.filterBy", {
what: t("terms.name").toLowerCase(),
}) + "...",
getItemValue: (item) => item?.name || "",
selectOptions: [
...new Set(
applications.map((application) => application.name).filter(Boolean)
),
].map((name) => ({ key: name, value: name })),
},
{
key: "archetypes",
Expand Down Expand Up @@ -468,6 +482,22 @@ export const ApplicationsTable: React.FC = () => {
return matchString;
},
},
{
key: "risk",
title: t("terms.risk"),
type: FilterType.multiselect,
placeholderText:
t("actions.filterBy", {
what: t("terms.risk").toLowerCase(),
}) + "...",
selectOptions: [
{ key: "green", value: "Low" },
{ key: "yellow", value: "Medium" },
{ key: "red", value: "High" },
{ key: "unknown", value: "Unknown" },
],
getItemValue: (item) => item.risk || "",
},
],
initialItemsPerPage: 10,
hasActionsColumn: true,
Expand Down Expand Up @@ -690,7 +720,9 @@ export const ApplicationsTable: React.FC = () => {

return (
<ConditionalRender
when={isFetchingApplications && !(applications || applicationsFetchError)}
when={
!!isFetchingApplications && !(applications || applicationsFetchError)
}
then={<AppPlaceholder />}
>
<div
Expand Down
Loading

0 comments on commit 85ac7b4

Please sign in to comment.