Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add SimpleDocumentViewerModal to display analysis details #1072

Merged
merged 1 commit into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@patternfly/react-charts": "^6.67.1",
"@patternfly/react-code-editor": "^4.82.115",
"@patternfly/react-core": "^4.214.1",
"@patternfly/react-styles": "^4.92.6",
"@patternfly/react-table": "^4.83.1",
"@patternfly/react-tokens": "^4.66.1",
"@react-keycloak/web": "^3.4.0",
Expand Down
39 changes: 28 additions & 11 deletions client/src/app/api/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const ASSESSMENTS = PATHFINDER + "/assessments";
const jsonHeaders = { headers: { Accept: "application/json" } };
const formHeaders = { headers: { Accept: "multipart/form-data" } };
const fileHeaders = { headers: { Accept: "application/json" } };
const yamlHeaders = { headers: { Accept: "application/x-yaml" } };

type Direction = "asc" | "desc";

Expand All @@ -128,17 +129,6 @@ const buildQuery = (params: any) => {
return query;
};

//Volumes
// poll clean task
export const getTaskById = ({
queryKey,
}: {
queryKey: QueryKey;
}): AxiosPromise<Task> => {
const [_, processId] = queryKey;
return axios.get<Task>(`${TASKS}/${processId}`);
};

// Business services

export const getBusinessServices = (): AxiosPromise<Array<BusinessService>> => {
Expand Down Expand Up @@ -426,6 +416,33 @@ export const getApplicationImports = (
.get(`${APP_IMPORT}?importSummary.id=${importSummaryID}&isValid=${isValid}`)
.then((response) => response.data);

export const getApplicationAnalysis = (
applicationId: number,
format: "json" | "yaml"
): Promise<string> => {
const headers = format === "yaml" ? yamlHeaders : jsonHeaders;
return axios
.get<string>(`${APPLICATIONS}/${applicationId}/analysis`, headers)
.then((response) => response.data);
};

export function getTaskById(id: number, format: "json"): Promise<Task>;
export function getTaskById(id: number, format: "yaml"): Promise<string>;
export function getTaskById(
id: number,
format: "json" | "yaml"
): Promise<Task | string> {
if (format === "yaml") {
return axios
.get<Task>(`${TASKS}/${id}`, yamlHeaders)
.then((response) => response.data);
} else {
return axios
.get<string>(`${TASKS}/${id}`, jsonHeaders)
.then((response) => response.data);
}
}

export const getTasks = () =>
axios.get<Task[]>(TASKS).then((response) => response.data);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import { NotificationsContext } from "@app/shared/notifications-context";
import { ConfirmDialog } from "@app/shared/components/confirm-dialog/confirm-dialog";
import { ApplicationDetailDrawerAnalysis } from "../components/application-detail-drawer";
import { useQueryClient } from "@tanstack/react-query";
import { SimpleDocumentViewerModal } from "@app/shared/components/simple-task-viewer";
import { getTaskById } from "@app/api/rest";

const ENTITY_FIELD = "entity";

Expand All @@ -94,6 +96,11 @@ export const ApplicationsTableAnalyze: React.FC = () => {
const [isApplicationImportModalOpen, setIsApplicationImportModalOpen] =
React.useState(false);

const [taskToView, setTaskToView] = React.useState<{
name: string;
task: number | undefined;
}>();

// Router
const history = useHistory();

Expand Down Expand Up @@ -364,7 +371,7 @@ export const ApplicationsTableAnalyze: React.FC = () => {
isAriaDisabled: !getTask(row),
onClick: () => {
const task = getTask(row);
if (task) window.open(`/hub/tasks/${task.id}`, "_blank");
if (task) setTaskToView({ name: row.name, task: task.id });
},
});
}
Expand Down Expand Up @@ -727,6 +734,7 @@ export const ApplicationsTableAnalyze: React.FC = () => {
"dialog.message.delete"
)}`}
</Modal>

{isConfirmDialogOpen && (
<ConfirmDialog
title={t("dialog.title.delete", {
Expand All @@ -749,6 +757,13 @@ export const ApplicationsTableAnalyze: React.FC = () => {
}}
/>
)}

<SimpleDocumentViewerModal<Task | string>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

I was wondering why you chose to pass the fetch functions down as props rather than use them inside the component itself. Seems like since we are already using conditional logic to determine the language type here, then we can just use the appropriate fetch functions within that conditional? Does that make sense?

Either way, I like the use of typescript to make the component more extensible down the road. Maybe that was your intention. Just curious.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I wanted to have a more generic component that could be used elsewhere, and doing the fetch as a prop allows the location and methodology for the fetch can vary as needed.

In this PR, I eventually found 3 places that did a window.open or a Link with target="_blank". Two of those places used 1 URL, and the Link style was another. So more generic FTW! And playing with some generic typing with function type overloading got interesting.

One use:

<SimpleDocumentViewerModal<Task | string>
title={`Analysis details for ${application?.name}`}
fetch={getTaskById}
documentId={taskIdToView}
onClose={() => setTaskIdToView(undefined)}
/>

The other use:

<SimpleDocumentViewerModal<string>
title={`Analysis for ${application?.name}`}
fetch={getApplicationAnalysis}
documentId={appAnalysisToView}
onClose={() => setAppAnalysisToView(undefined)}
/>

title={`Analysis details for ${taskToView?.name}`}
fetch={getTaskById}
documentId={taskToView?.task}
onClose={() => setTaskToView(undefined)}
/>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
import { EmptyTextMessage } from "@app/shared/components";
import { useFetchFacts } from "@app/queries/facts";
import { ApplicationFacts } from "./application-facts";
import { SimpleDocumentViewerModal } from "@app/shared/components/simple-task-viewer";
import { getApplicationAnalysis, getTaskById } from "@app/api/rest";

export interface IApplicationDetailDrawerAnalysisProps
extends Pick<
Expand All @@ -39,6 +41,8 @@ export const ApplicationDetailDrawerAnalysis: React.FC<

const { identities } = useFetchIdentities();
const { facts, isFetching } = useFetchFacts(application?.id);
const [appAnalysisToView, setAppAnalysisToView] = React.useState<number>();
const [taskIdToView, setTaskIdToView] = React.useState<number>();

let matchingSourceCredsRef: Identity | undefined;
let matchingMavenCredsRef: Identity | undefined;
Expand All @@ -47,10 +51,6 @@ export const ApplicationDetailDrawerAnalysis: React.FC<
matchingMavenCredsRef = getKindIDByRef(identities, application, "maven");
}

const openAnalysisDetails = () => {
if (task) window.open(`/hub/tasks/${task.id}`, "_blank");
};

const notAvailable = <EmptyTextMessage message={t("terms.notAvailable")} />;

const updatedApplication = applications?.find(
Expand Down Expand Up @@ -101,19 +101,25 @@ export const ApplicationDetailDrawerAnalysis: React.FC<
{task?.state === "Succeeded" && application ? (
<>
<Tooltip content="View Report">
<Button variant="link" isInline>
<Link
to={`/hub/applications/${application.id}/analysis`}
target="_blank"
>
View analysis
</Link>
<Button
type="button"
variant="link"
isInline
onClick={() => setAppAnalysisToView(application.id)}
>
View analysis
</Button>
</Tooltip>
<SimpleDocumentViewerModal<string>
title={`Analysis for ${application?.name}`}
fetch={getApplicationAnalysis}
documentId={appAnalysisToView}
onClose={() => setAppAnalysisToView(undefined)}
/>
</>
) : task?.state === "Failed" ? (
<>
{task ? (
task ? (
<>
<Button
icon={
<span className={spacing.mrXs}>
Expand All @@ -122,19 +128,25 @@ export const ApplicationDetailDrawerAnalysis: React.FC<
}
type="button"
variant="link"
onClick={openAnalysisDetails}
onClick={() => setTaskIdToView(task.id)}
className={spacing.ml_0}
style={{ margin: "0", padding: "0" }}
>
Analysis details
</Button>
) : (
<span className={spacing.mlSm}>
<ExclamationCircleIcon color="#c9190b"></ExclamationCircleIcon>
Failed
</span>
)}
</>
<SimpleDocumentViewerModal<Task | string>
title={`Analysis details for ${application?.name}`}
fetch={getTaskById}
documentId={taskIdToView}
onClose={() => setTaskIdToView(undefined)}
/>
</>
) : (
<span className={spacing.mlSm}>
<ExclamationCircleIcon color="#c9190b"></ExclamationCircleIcon>
Failed
</span>
)
) : (
notAvailable
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./simple-document-viewer";
Loading