Skip to content

Commit

Permalink
🐛 Fetch target images in auth envs (#1420)
Browse files Browse the repository at this point in the history
Closes https://issues.redhat.com/browse/MTA-1249?filter=-1

- Image was not being fetched in envs with auth enabled. Image tags
(<img>) in HTML do not follow the same request mechanism as AJAX or
fetch requests. They do not use the XMLHttpRequest or axios API, so they
were not intercepted by axios middleware interceptor we have set up for
API requests.

---------

Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 committed Oct 2, 2023
1 parent bc0fe72 commit b5f715b
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 26 deletions.
2 changes: 1 addition & 1 deletion client/src/app/components/KeycloakProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { deleteCookie, getCookie, setCookie } from "@app/queries/cookies";
import { AppPlaceholder } from "./AppPlaceholder";
import { Flex, FlexItem, Spinner } from "@patternfly/react-core";
import { ReactKeycloakProvider } from "@react-keycloak/web";
import React, { Suspense, useEffect } from "react";
import React, { Suspense } from "react";

interface IKeycloakProviderProps {
children: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useState, useEffect } from "react";
import axios from "axios";
import DefaultImage from "@app/images/Icon-Red_Hat-Virtual_server_stack-A-Black-RGB.svg";
import { Target } from "@app/api/models";
import { FILES } from "@app/api/rest";

const useFetchImageDataUrl = (target: Target) => {
const [imageDataUrl, setImageDataUrl] = useState<string | null>(null);

useEffect(() => {
const imagePath = target?.image?.id
? `${FILES}/${target?.image.id}`
: DefaultImage;

(async () => {
try {
const response = await axios.get(imagePath, {
headers: {
Accept: "application/octet-stream",
},
responseType: "arraybuffer",
});
const contentType = response.headers["content-type"];

let imageData;

if (contentType === "image/svg+xml") {
const text = new TextDecoder().decode(response.data);
imageData = `data:${contentType},${encodeURIComponent(text)}`;
} else {
const base64 = btoa(
new Uint8Array(response.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
);
imageData = `data:${contentType};base64,${base64}`;
}

setImageDataUrl(imageData);
} catch (error) {
console.error("There was an issue fetching the image:", error);
}
})();
}, [target]);

return imageDataUrl;
};

export default useFetchImageDataUrl;
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "./target-card.css";
import * as React from "react";
import {
EmptyState,
Expand All @@ -24,14 +25,14 @@ import {
SelectVariant,
SelectOptionObject,
} from "@patternfly/react-core/deprecated";
import { CubesIcon, GripVerticalIcon } from "@patternfly/react-icons";
import { GripVerticalIcon } from "@patternfly/react-icons";
import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { useTranslation } from "react-i18next";

import { KebabDropdown } from "./KebabDropdown";
import DefaultRulesetIcon from "@app/images/Icon-Red_Hat-Virtual_server_stack-A-Black-RGB.svg";
import { KebabDropdown } from "../KebabDropdown";
import DefaultImage from "@app/images/Icon-Red_Hat-Virtual_server_stack-A-Black-RGB.svg";
import { Target, TargetLabel } from "@app/api/models";
import "./TargetCard.css";
import useFetchImageDataUrl from "./hooks/useFetchImageDataUrl";

export interface TargetCardProps {
item: Target;
Expand Down Expand Up @@ -67,6 +68,7 @@ export const TargetCard: React.FC<TargetCardProps> = ({
}) => {
const { t } = useTranslation();
const [isCardSelected, setCardSelected] = React.useState(cardSelected);
const imageDataUrl = useFetchImageDataUrl(target);

const prevSelectedLabel =
formLabels?.find((formLabel) => {
Expand Down Expand Up @@ -105,24 +107,6 @@ export const TargetCard: React.FC<TargetCardProps> = ({
}
};

const getImage = (): React.ComponentType => {
let result: React.ComponentType<any> = CubesIcon;
const imagePath = target?.image?.id
? `/hub/files/${target?.image.id}`
: DefaultRulesetIcon;
if (target.image) {
result = () => (
<img
src={imagePath}
alt="Card logo"
style={{ height: 80, pointerEvents: "none" }}
/>
);
}

return result;
};

return (
<Card
onClick={handleCardClick}
Expand Down Expand Up @@ -176,7 +160,18 @@ export const TargetCard: React.FC<TargetCardProps> = ({
variant={EmptyStateVariant.sm}
className="select-card__component__empty-state"
>
<EmptyStateIcon icon={getImage()} />
<EmptyStateIcon
icon={() => (
<img
src={imageDataUrl || DefaultImage}
alt="Card logo"
style={{ height: 80, pointerEvents: "none" }}
onError={(e) => {
e.currentTarget.src = DefaultImage;
}}
/>
)}
/>
<Title headingLevel="h4" size="md">
{target.name}
</Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { useTranslation } from "react-i18next";
import { useFormContext } from "react-hook-form";

import { TargetCard } from "@app/components/TargetCard";
import { TargetCard } from "@app/components/target-card/target-card";
import { AnalysisWizardFormValues } from "./schema";
import { useSetting } from "@app/queries/settings";
import { useFetchTargets } from "@app/queries/targets";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import { TargetCard } from "@app/components/TargetCard";
import { TargetCard } from "@app/components/target-card/target-card";
import { useFetchTargets } from "@app/queries/targets";

interface ItemProps {
Expand Down

0 comments on commit b5f715b

Please sign in to comment.