Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import {
} from "../../../../Common/FormComponents/common/styleLibrary";
import { Badge } from "@mui/material";
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
import { extensionPreview } from "../utils";
import { AllowedPreviews, previewObjectType } from "../utils";
import { ErrorResponseHandler } from "../../../../../../common/types";

import { AppState, useAppDispatch } from "../../../../../../store";
Expand Down Expand Up @@ -301,6 +301,9 @@ const ListObjects = () => {
const [canPreviewFile, setCanPreviewFile] = useState<boolean>(false);
const [quota, setQuota] = useState<BucketQuota | null>(null);

const [metaData, setMetaData] = useState<any>(null);
const [isMetaDataLoaded, setIsMetaDataLoaded] = useState(false);

const isVersioningApplied = isVersionedMode(versioningConfig.status);
const bucketName = params.bucketName || "";

Expand Down Expand Up @@ -365,6 +368,37 @@ const ListObjects = () => {
(state: AppState) => state.objectBrowser.selectedObjects
);

const fetchMetadata = useCallback(() => {
const objectName = selectedObjects[0];

if (!isMetaDataLoaded) {
const encodedPath = encodeURLString(objectName);
api.buckets
.getObjectMetadata(bucketName, {
prefix: encodedPath,
})
.then((res) => {
let metadata = get(res.data, "objectMetadata", {});
setIsMetaDataLoaded(true);
setMetaData(metadata);
})
.catch((err) => {
console.error(
"Error Getting Metadata Status: ",
err,
err?.detailedError
);
setIsMetaDataLoaded(true);
});
}
}, [bucketName, selectedObjects, isMetaDataLoaded]);

useEffect(() => {
if (bucketName && selectedObjects.length === 1) {
fetchMetadata();
}
}, [bucketName, selectedObjects, fetchMetadata]);

useEffect(() => {
dispatch(setSearchObjects(""));
dispatch(setLoadingObjects(true));
Expand Down Expand Up @@ -392,8 +426,9 @@ const ListObjects = () => {
useEffect(() => {
if (selectedObjects.length === 1) {
const objectName = selectedObjects[0];
let objectType: AllowedPreviews = previewObjectType(metaData, objectName);

if (extensionPreview(objectName) !== "none" && canDownload) {
if (objectType !== "none" && canDownload) {
setCanPreviewFile(true);
} else {
setCanPreviewFile(false);
Expand All @@ -408,7 +443,7 @@ const ListObjects = () => {
setCanShareFile(false);
setCanPreviewFile(false);
}
}, [selectedObjects, canDownload]);
}, [selectedObjects, canDownload, metaData]);

useEffect(() => {
if (!quota && !anonymousMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
spacingUtils,
textStyleUtils,
} from "../../../../Common/FormComponents/common/styleLibrary";
import { extensionPreview } from "../utils";
import { AllowedPreviews, previewObjectType } from "../utils";

import {
decodeURLString,
Expand Down Expand Up @@ -395,6 +395,8 @@ const ObjectDetailPanel = ({
[IAM_SCOPES.S3_DELETE_OBJECT]
);

let objectType: AllowedPreviews = previewObjectType(metaData, currentItem);

const multiActionButtons = [
{
action: () => {
Expand Down Expand Up @@ -431,8 +433,7 @@ const ObjectDetailPanel = ({
label: "Preview",
disabled:
!!actualInfo.is_delete_marker ||
extensionPreview(currentItem) === "none" ||
!canGetObject,
(objectType === "none" && !canGetObject),
icon: <PreviewIcon />,
tooltip: canGetObject
? "Preview this File"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import React, { Fragment, useState } from "react";
import React, { Fragment, useCallback, useEffect, useState } from "react";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { Grid, LinearProgress } from "@mui/material";
import { BucketObjectItem } from "../ListObjects/types";
import { extensionPreview } from "../utils";
import { AllowedPreviews, previewObjectType } from "../utils";
import { encodeURLString } from "../../../../../../common/utils";
import clsx from "clsx";
import WarningMessage from "../../../../Common/WarningMessage/WarningMessage";
import { api } from "../../../../../../api";
import get from "lodash/get";

const styles = () =>
createStyles({
Expand Down Expand Up @@ -72,6 +75,40 @@ const PreviewFile = ({
}: IPreviewFileProps) => {
const [loading, setLoading] = useState<boolean>(true);

const [metaData, setMetaData] = useState<any>(null);
const [isMetaDataLoaded, setIsMetaDataLoaded] = useState(false);

const objectName = object?.name || "";

const fetchMetadata = useCallback(() => {
if (!isMetaDataLoaded) {
const encodedPath = encodeURLString(objectName);
api.buckets
.getObjectMetadata(bucketName, {
prefix: encodedPath,
})
.then((res) => {
let metadata = get(res.data, "objectMetadata", {});
setIsMetaDataLoaded(true);
setMetaData(metadata);
})
.catch((err) => {
console.error(
"Error Getting Metadata Status: ",
err,
err?.detailedError
);
setIsMetaDataLoaded(true);
});
}
}, [bucketName, objectName, isMetaDataLoaded]);

useEffect(() => {
if (bucketName && objectName) {
fetchMetadata();
}
}, [bucketName, objectName, fetchMetadata]);

let path = "";

if (object) {
Expand All @@ -83,87 +120,99 @@ const PreviewFile = ({
}
}

const objectType = extensionPreview(object?.name || "");
let objectType: AllowedPreviews = previewObjectType(metaData, objectName);

const iframeLoaded = () => {
setLoading(false);
};

return (
<Fragment>
{loading && (
{objectType !== "none" && loading && (
<Grid item xs={12}>
<LinearProgress />
</Grid>
)}
<div style={{ textAlign: "center" }}>
{objectType === "video" && (
<video
style={{
width: "auto",
height: "auto",
maxWidth: "calc(100vw - 100px)",
maxHeight: "calc(100vh - 200px)",
}}
autoPlay={true}
controls={true}
muted={false}
playsInline={true}
onPlay={iframeLoaded}
>
<source src={path} type="video/mp4" />
</video>
)}
{objectType === "audio" && (
<audio
style={{
width: "100%",
height: "auto",
}}
autoPlay={true}
controls={true}
muted={false}
playsInline={true}
onPlay={iframeLoaded}
>
<source src={path} type="audio/mpeg" />
</audio>
)}
{objectType === "image" && (
<img
style={{
width: "auto",
height: "auto",
maxWidth: "100vw",
maxHeight: "100vh",
}}
src={path}
alt={"preview"}
onLoad={iframeLoaded}
/>
)}
{objectType !== "video" &&
objectType !== "audio" &&
objectType !== "image" && (
<div
className={clsx(classes.iframeBase, {
[classes.iframeHidden]: loading,
})}
{isMetaDataLoaded ? (
<div style={{ textAlign: "center" }}>
{objectType === "video" && (
<video
style={{
width: "auto",
height: "auto",
maxWidth: "calc(100vw - 100px)",
maxHeight: "calc(100vh - 200px)",
}}
autoPlay={true}
controls={true}
muted={false}
playsInline={true}
onPlay={iframeLoaded}
>
<iframe
src={path}
title="File Preview"
allowTransparency
className={`${classes.iframeContainer} ${
isFullscreen ? "fullHeight" : objectType
}`}
onLoad={iframeLoaded}
>
File couldn't be loaded. Please try Download instead
</iframe>
<source src={path} type="video/mp4" />
</video>
)}
{objectType === "audio" && (
<audio
style={{
width: "100%",
height: "auto",
}}
autoPlay={true}
controls={true}
muted={false}
playsInline={true}
onPlay={iframeLoaded}
>
<source src={path} type="audio/mpeg" />
</audio>
)}
{objectType === "image" && (
<img
style={{
width: "auto",
height: "auto",
maxWidth: "100vw",
maxHeight: "100vh",
}}
src={path}
alt={"preview"}
onLoad={iframeLoaded}
/>
)}
{objectType === "none" && (
<div>
<WarningMessage
label=" File couldn't be previewed using file extension or mime type. Please
try Download instead"
title="Preview unavailable "
/>
</div>
)}
</div>
{objectType !== "none" &&
objectType !== "video" &&
objectType !== "audio" &&
objectType !== "image" && (
<div
className={clsx(classes.iframeBase, {
[classes.iframeHidden]: loading,
})}
>
<iframe
src={path}
title="File Preview"
allowTransparency
className={`${classes.iframeContainer} ${
isFullscreen ? "fullHeight" : objectType
}`}
onLoad={iframeLoaded}
>
File couldn't be loaded. Please try Download instead
</iframe>
</div>
)}
</div>
) : null}
</Fragment>
);
};
Expand Down
50 changes: 47 additions & 3 deletions portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,30 @@ class DownloadHelper {
}
}

export type AllowedPreviews = "image" | "text" | "audio" | "video" | "none";
export const contentTypePreview = (contentType: string): AllowedPreviews => {
if (contentType) {
const mimeObjectType = (contentType || "").toLowerCase();

if (mimeObjectType.includes("image")) {
return "image";
}
if (mimeObjectType.includes("text")) {
return "text";
}
if (mimeObjectType.includes("audio")) {
return "audio";
}
if (mimeObjectType.includes("video")) {
return "video";
}
}

return "none";
};

// Review file extension by name & returns the type of preview browser that can be used
export const extensionPreview = (
fileName: string
): "image" | "text" | "audio" | "video" | "none" => {
export const extensionPreview = (fileName: string): AllowedPreviews => {
const imageExtensions = [
"jif",
"jfif",
Expand Down Expand Up @@ -262,6 +282,30 @@ export const extensionPreview = (
return "none";
};

export const previewObjectType = (
metaData: Record<any, any>,
objectName: string
) => {
const metaContentType = (
(metaData && metaData["Content-Type"]) ||
""
).toString();

const extensionType = extensionPreview(objectName || "");
const contentType = contentTypePreview(metaContentType);

let objectType: AllowedPreviews = extensionType;

if (extensionType === contentType) {
objectType = extensionType;
} else if (extensionType === "none" && contentType !== "none") {
objectType = contentType;
} else if (contentType === "none" && extensionType !== "none") {
objectType = extensionType;
}

return objectType;
};
export const sortListObjects = (fieldSort: string) => {
switch (fieldSort) {
case "name":
Expand Down
Loading