Skip to content

Commit

Permalink
✨ Add handling for tasks "Succeeded with errors" in task and applicat…
Browse files Browse the repository at this point in the history
…ion tables (#2011)

### Summary
Resolves: #1997

When a task is succeeded but has attached errors, render task state,
application tasks state and application analysis state with a warning.

### Details of Changes
With this change, hub is not adding a new terminal state, but having a
new terminal state is an easy way to handle things. The task queries
will now evaluate the `state` and `errors` props to determine if
"Succeeded" should be "SucceededWithErrors". This synthetic task status
makes updating all of the UI component much simpler.

To function properly, HUB [Issue
725](konveyor/tackle2-hub#725) / [PR
720](konveyor/tackle2-hub#720) are required.

Changes have also been made to utilize the `/tasks/reports/dashboard`
endpoint to get a much smaller view of tasks when dealing with them in
aggregate.

The application details drawer was refactored to push data fetching
closer to actual use, and to break up a very large component into a
container component with a component dedicated to each tab.

### Screenshots
Application inventory page:
![screenshot-localhost_9000-2024 07
15-18_33_20](https://github.com/user-attachments/assets/b7015ebf-4305-4d6d-a670-5e4fe532981d)

Application tasks popover:
![image](https://github.com/user-attachments/assets/14d4d19e-eaca-4505-88be-d5016da1e70b)

Task Manager page:
![screenshot-localhost_9000-2024 07
15-18_35_15](https://github.com/user-attachments/assets/2547a46a-1fa6-456f-836c-4e59cc0fd074)

---------

Signed-off-by: Scott J Dickerson <[email protected]>
  • Loading branch information
sjd78 authored Jul 16, 2024
1 parent 4a41417 commit 4182243
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 421 deletions.
14 changes: 14 additions & 0 deletions client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@
"dependencies": "Dependencies",
"tasks": "Task Manager"
},
"taskState": {
"Canceled": "Canceled",
"Created": "Created",
"Failed": "Failed",
"NoTask": "No Task",
"Pending": "Pending",
"Postponed": "Postponed",
"QuotaBlocked": "Quota Blocked",
"Ready": "Ready",
"Running": "Running",
"Succeeded": "Succeeded",
"SucceededWithErrors": "Succeeded with Errors"
},
"terms": {
"accepted": "Accepted",
"acceptedAppsAndDeps": "Accepted applications and dependencies",
Expand Down Expand Up @@ -312,6 +325,7 @@
"comments": "Comments",
"commentsFromApplication": "Application comments",
"completed": "Completed",
"completedWithErrors": "Completed with Errors",
"confidence": "Confidence",
"connected": "Connected",
"contributors": "Contributors",
Expand Down
21 changes: 20 additions & 1 deletion client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ export type TaskState =
| "QuotaBlocked"
| "Ready"
| "Pending"
| "Postponed";
| "Postponed"
| "SucceededWithErrors"; // synthetic state for ease-of-use in UI;

export interface Task {
id: number;
Expand Down Expand Up @@ -334,6 +335,24 @@ export interface Task {
attached?: TaskAttachment[];
}

/** A smaller version of `Task` fetched from the report/dashboard endpoint. */
export interface TaskDashboard {
id: number;
createUser: string;
updateUser: string;
createTime: string; // ISO-8601
name: string;
kind?: string;
addon?: string;
state: TaskState;
application: Ref;
started?: string; // ISO-8601
terminated?: string; // ISO-8601

/** Count of errors recorded on the task - even Succeeded tasks may have errors. */
errors?: number;
}

export interface TaskPolicy {
isolated?: boolean;
preemptEnabled?: boolean;
Expand Down
7 changes: 5 additions & 2 deletions client/src/app/api/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
Task,
Taskgroup,
TaskQueue,
TaskDashboard,
Ticket,
Tracker,
TrackerProject,
Expand Down Expand Up @@ -357,8 +358,10 @@ export function getTaskByIdAndFormat(
});
}

export const getTasks = () =>
axios.get<Task[]>(TASKS).then((response) => response.data);
export const getTasksDashboard = () =>
axios
.get<TaskDashboard[]>(`${TASKS}/report/dashboard`)
.then((response) => response.data);

export const getServerTasks = (params: HubRequestParams = {}) =>
getHubPaginatedResult<Task>(TASKS, params);
Expand Down
22 changes: 16 additions & 6 deletions client/src/app/components/Icons/IconedStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import React from "react";
import { Icon } 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 TopologyIcon from "@patternfly/react-icons/dist/esm/icons/topology-icon";
import { IconWithLabel } from "./IconWithLabel";
import { ReactElement } from "react-markdown/lib/react-markdown";

import {
CheckCircleIcon,
TimesCircleIcon,
InProgressIcon,
ExclamationCircleIcon,
ExclamationTriangleIcon,
UnknownIcon,
TopologyIcon,
} from "@patternfly/react-icons";

export type IconedStatusPreset =
| "InheritedReviews"
| "InProgressInheritedReviews"
| "InProgressInheritedAssessments"
| "InheritedAssessments"
| "Canceled"
| "Completed"
| "CompletedWithErrors"
| "Error"
| "Failed"
| "InProgress"
Expand Down Expand Up @@ -104,6 +109,11 @@ export const IconedStatus: React.FC<IIconedStatusProps> = ({
status: "success",
label: t("terms.completed"),
},
CompletedWithErrors: {
icon: <ExclamationTriangleIcon />,
status: "warning",
label: t("terms.completedWithErrors"),
},
Error: {
icon: <ExclamationCircleIcon />,
status: "danger",
Expand Down
7 changes: 7 additions & 0 deletions client/src/app/components/Icons/TaskStateIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TimesCircleIcon,
InProgressIcon,
ExclamationCircleIcon,
ExclamationTriangleIcon,
UnknownIcon,
PendingIcon,
TaskIcon,
Expand All @@ -29,6 +30,12 @@ export const TaskStateIcon: FC<{ state?: TaskState }> = ({ state }) => {
<CheckCircleIcon />
</Icon>
);
case "SucceededWithErrors":
return (
<Icon status="warning">
<ExclamationTriangleIcon />
</Icon>
);
case "Failed":
return (
<Icon status="danger">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,19 @@ exports[`StatusIcon Renders without crashing 1`] = `
<span
class="pf-v5-c-icon__content"
>
<test-file-stub />
<svg
aria-hidden="true"
class="pf-v5-svg"
fill="currentColor"
height="1em"
role="img"
viewBox="0 0 512 512"
width="1em"
>
<path
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
/>
</svg>
</span>
</span>
</div>
Expand All @@ -42,7 +54,19 @@ exports[`StatusIcon Renders without crashing 1`] = `
<span
class="pf-v5-c-icon__content"
>
<test-file-stub />
<svg
aria-hidden="true"
class="pf-v5-svg"
fill="currentColor"
height="1em"
role="img"
viewBox="0 0 512 512"
width="1em"
>
<path
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
/>
</svg>
</span>
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ import {
useBulkDeleteApplicationMutation,
useFetchApplications,
} from "@app/queries/applications";
import { useCancelTaskMutation, useFetchTasks } from "@app/queries/tasks";
import {
useDeleteAssessmentMutation,
useFetchAssessments,
} from "@app/queries/assessments";
useCancelTaskMutation,
useFetchTaskDashboard,
} from "@app/queries/tasks";
import { useDeleteAssessmentMutation } from "@app/queries/assessments";
import { useDeleteReviewMutation } from "@app/queries/reviews";
import { useFetchTagsWithTagItems } from "@app/queries/tags";
import { useFetchArchetypes } from "@app/queries/archetypes";

// Relative components
import { AnalysisWizard } from "../analysis-wizard/analysis-wizard";
Expand Down Expand Up @@ -182,7 +181,7 @@ export const ApplicationsTable: React.FC = () => {
// ----- Table data fetches and mutations
const { tagItems } = useFetchTagsWithTagItems();

const { tasks, hasActiveTasks } = useFetchTasks(isAnalyzeModalOpen);
const { tasks, hasActiveTasks } = useFetchTaskDashboard(isAnalyzeModalOpen);

const completedCancelTask = () => {
pushNotification({
Expand Down Expand Up @@ -231,11 +230,6 @@ export const ApplicationsTable: React.FC = () => {
referencedBusinessServiceRefs,
} = useDecoratedApplications(baseApplications, tasks);

const { assessments, isFetching: isFetchingAssessments } =
useFetchAssessments();

const { archetypes, isFetching: isFetchingArchetypes } = useFetchArchetypes();

const onDeleteApplicationSuccess = (appIDCount: number) => {
pushNotification({
title: t("toastr.success.applicationDeleted", {
Expand Down Expand Up @@ -913,11 +907,7 @@ export const ApplicationsTable: React.FC = () => {
>
<ApplicationAssessmentStatus
application={application}
isLoading={
isFetchingApplications ||
isFetchingArchetypes ||
isFetchingAssessments
}
isLoading={isFetchingApplications}
key={`${application?.id}-assessment-status`}
/>
</Td>
Expand Down Expand Up @@ -1067,12 +1057,9 @@ export const ApplicationsTable: React.FC = () => {

<ApplicationDetailDrawer
application={activeItem}
applications={applications}
assessments={assessments}
archetypes={archetypes}
onCloseClick={clearActiveItem}
onEditClick={() => setSaveApplicationModalState(activeItem)}
task={activeItem ? activeItem.tasks.currentAnalyzer : null}
task={activeItem?.tasks?.currentAnalyzer ?? null}
/>

<TaskGroupProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import React from "react";
import { Link } from "react-router-dom";
import dayjs from "dayjs";

import { Icon, Popover, PopoverProps, Tooltip } from "@patternfly/react-core";
import {
CheckCircleIcon,
TimesCircleIcon,
InProgressIcon,
ExclamationCircleIcon,
ExclamationTriangleIcon,
PendingIcon,
} from "@patternfly/react-icons";
import { Table, Tbody, Td, Thead, Tr } from "@patternfly/react-table";

import { IconWithLabel, TaskStateIcon } from "@app/components/Icons";
import { Paths } from "@app/Paths";
import { formatPath, universalComparator } from "@app/utils/utils";
import { TaskDashboard } from "@app/api/models";
import {
ApplicationTasksStatus,
DecoratedApplication,
} from "../useDecoratedApplications";
import { Paths } from "@app/Paths";
import { formatPath, universalComparator } from "@app/utils/utils";
import dayjs from "dayjs";
import { Table, Tbody, Td, Thead, Tr } from "@patternfly/react-table";
import { Task } from "@app/api/models";

interface StatusData {
popoverVariant: PopoverProps["alertSeverityVariant"];
Expand Down Expand Up @@ -79,14 +80,23 @@ const statusMap: Record<ApplicationTasksStatus, StatusData> = {
</Icon>
),
},
SuccessWithErrors: {
popoverVariant: "warning",
headerText: "All tasks succeeded, but some errors occurred",
icon: () => (
<Icon status="warning">
<ExclamationTriangleIcon />
</Icon>
),
},
};

const linkToTasks = (applicationName: string) => {
const search = `t:filters={"application":["${applicationName}"]}`;
return `${formatPath(Paths.tasks, {})}?${search}`;
};

const linkToDetails = (task: Task) => {
const linkToDetails = (task: TaskDashboard) => {
return formatPath(Paths.taskDetails, {
taskId: task.id,
});
Expand Down
Loading

0 comments on commit 4182243

Please sign in to comment.