diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 5ccabc81c5..a280166494 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -184,6 +184,8 @@ "duplicateWave": "The migration wave could not be created due to a conflict with an existing wave. Make sure the name and start/end dates are unique and try again.", "importErrorCheckDocumentation": "For status Error imports, check the documentation to ensure your file is structured correctly.", "insecureTracker": "Insecure mode deactivates certificate verification. Use insecure mode for instances that have self-signed certificates.", + "inheritedReviewTooltip_singular": "This application is inheriting a review from an archetype.", + "inheritedReviewTooltip_plural": "This application is inheriting reviews from {{count}} archetypes.", "jiraInstanceNotConnected": "Jira instance {{name}} is not connected.", "manageDependenciesInstructions": "Add northbound and southbound dependencies for the selected application here. Note that any selections made will be saved automatically. To undo any changes, you must manually delete the applications from the dropdowns.", "noDataAvailableBody": "No data available to be shown here.", @@ -328,6 +330,7 @@ "inProgress": "In-progress", "instanceType": "Instance type", "instance": "Instance", + "inherited": "Inherited", "issueType": "Issue type", "jiraConfig": "Jira configuration", "issue": "Issue", diff --git a/client/src/app/components/IconedStatus.tsx b/client/src/app/components/IconedStatus.tsx index 665d4b0581..88faac58da 100644 --- a/client/src/app/components/IconedStatus.tsx +++ b/client/src/app/components/IconedStatus.tsx @@ -1,13 +1,15 @@ import React from "react"; -import { Flex, FlexItem, Icon } from "@patternfly/react-core"; +import { Flex, FlexItem, Icon, Tooltip } from "@patternfly/react-core"; import { useTranslation } from "react-i18next"; import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon"; import TimesCircleIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon"; import InProgressIcon from "@patternfly/react-icons/dist/esm/icons/in-progress-icon"; import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon"; import UnknownIcon from "@patternfly/react-icons/dist/esm/icons/unknown-icon"; +import QuestionCircleIcon from "@patternfly/react-icons/dist/esm/icons/question-circle-icon"; export type IconedStatusPreset = + | "Inherited" | "Canceled" | "Completed" | "Error" @@ -35,6 +37,8 @@ export interface IIconedStatusProps { icon?: React.ReactNode; className?: string; label?: React.ReactNode | string; + tooltipMessage?: string; + tooltipCount?: number; } export const IconedStatus: React.FC = ({ @@ -43,9 +47,18 @@ export const IconedStatus: React.FC = ({ icon, className = "", label, + tooltipCount = 0, }: IIconedStatusProps) => { const { t } = useTranslation(); const presets: IconedStatusPresetType = { + Inherited: { + icon: , + status: "info", + label: t("terms.inherited"), + tooltipMessage: t("message.inheritedReviewTooltip", { + count: tooltipCount, + }), + }, Canceled: { icon: , status: "info", @@ -90,15 +103,26 @@ export const IconedStatus: React.FC = ({ }; const presetProps = preset && presets[preset]; + const IconWithOptionalTooltip: React.FC<{ children: React.ReactElement }> = ({ + children, + }) => + presetProps?.tooltipMessage ? ( + {children} + ) : ( + <>{children} + ); + return ( - - {icon || presetProps?.icon || } - + + + {icon || presetProps?.icon || } + + {label || presetProps?.label} diff --git a/client/src/app/pages/applications/applications-table/applications-table.tsx b/client/src/app/pages/applications/applications-table/applications-table.tsx index 2189169a08..a8b72b646b 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -44,7 +44,6 @@ import { ConditionalTableBody, TableRowContentWithControls, } from "@app/components/TableControls"; -import { IconedStatus } from "@app/components/IconedStatus"; import { ToolbarBulkSelector } from "@app/components/ToolbarBulkSelector"; import { ConfirmDialog } from "@app/components/ConfirmDialog"; import { NotificationsContext } from "@app/components/NotificationsContext"; @@ -116,6 +115,7 @@ import { SimpleDocumentViewerModal } from "@app/components/SimpleDocumentViewer" import { AnalysisWizard } from "../analysis-wizard/analysis-wizard"; import { TaskGroupProvider } from "../analysis-wizard/components/TaskGroupContext"; import { ApplicationIdentityForm } from "../components/application-identity-form/application-identity-form"; +import { ApplicationReviewStatus } from "../components/application-review-status/application-review-status"; export const ApplicationsTable: React.FC = () => { const { t } = useTranslation(); @@ -870,7 +870,6 @@ export const ApplicationsTable: React.FC = () => { > {currentPageItems?.map((application, rowIndex) => { - const isAppReviewed = !!application.review; const applicationArchetypes = application.archetypes?.map( (archetypeRef) => { return archetypes.find( @@ -879,10 +878,6 @@ export const ApplicationsTable: React.FC = () => { } ); - const hasReviewedArchetype = applicationArchetypes?.some( - (archetype) => !!archetype?.review - ); - const hasAssessedArchetype = applicationArchetypes?.some( (archetype) => !!archetype?.assessments?.length ); @@ -943,7 +938,12 @@ export const ApplicationsTable: React.FC = () => { modifier="truncate" {...getTdProps({ columnKey: "review" })} > - + + + {/* { ) : null} - + */} = ({ application, archetypes, isLoading = false }) => { + const { t } = useTranslation(); + const isAppReviewed = !!application.review; + + const applicationArchetypes = application.archetypes?.map((archetypeRef) => { + return archetypes?.find((archetype) => archetype.id === archetypeRef.id); + }); + + const reviewedArchetypeCount = + applicationArchetypes?.filter((archetype) => !!archetype?.review).length || + 0; + + let statusPreset: IconedStatusPreset; + let tooltipCount = 0; + + if (isAppReviewed) { + statusPreset = "Completed"; + } else if (reviewedArchetypeCount > 0) { + statusPreset = "Inherited"; + tooltipCount = reviewedArchetypeCount; + } else { + statusPreset = "NotStarted"; + } + + if (isLoading) { + return ; + } + + if (!applicationArchetypes || applicationArchetypes.length === 0) { + return ; + } + + return ; +};