Object Details Loading + NPE (#1075)

* Object Details Loading + NPE

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>

* remove commented line

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2021-09-22 12:10:50 -07:00
committed by GitHub
parent 2e300dba7d
commit 401a051b8e
2 changed files with 346 additions and 326 deletions

View File

@@ -23,6 +23,7 @@ import clsx from "clsx";
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
import {
CircularProgress,
LinearProgress,
Paper,
Table,
TableBody,
@@ -246,7 +247,7 @@ const ObjectDetails = ({
const [deleteTagModalOpen, setDeleteTagModalOpen] = useState<boolean>(false);
const [selectedTag, setSelectedTag] = useState<string[]>(["", ""]);
const [legalholdOpen, setLegalholdOpen] = useState<boolean>(false);
const [actualInfo, setActualInfo] = useState<IFileInfo>(emptyFile);
const [actualInfo, setActualInfo] = useState<IFileInfo | null>(null);
const [versions, setVersions] = useState<IFileInfo[]>([]);
const [filterVersion, setFilterVersion] = useState<string>("");
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
@@ -259,14 +260,6 @@ const ObjectDetails = ({
const allPathData = internalPaths.split("/");
const currentItem = allPathData.pop();
const previewObject: BucketObject = {
name: actualInfo.name,
version_id: actualInfo.version_id || "null",
size: parseInt(actualInfo.size || "0"),
content_type: "",
last_modified: new Date(actualInfo.last_modified),
};
useEffect(() => {
if (loadObjectData) {
const encodedPath = encodeURIComponent(internalPaths);
@@ -328,7 +321,7 @@ const ObjectDetails = ({
let tagKeys: string[] = [];
if (actualInfo.tags) {
if (actualInfo && actualInfo.tags) {
tagKeys = Object.keys(actualInfo.tags);
}
@@ -448,7 +441,7 @@ const ObjectDetails = ({
return (
<React.Fragment>
{shareFileModalOpen && (
{shareFileModalOpen && actualInfo && (
<ShareFile
open={shareFileModalOpen}
closeModalAndRefresh={closeShareModal}
@@ -456,7 +449,7 @@ const ObjectDetails = ({
dataObject={actualInfo}
/>
)}
{retentionModalOpen && (
{retentionModalOpen && actualInfo && (
<SetRetention
open={retentionModalOpen}
closeModalAndRefresh={closeRetentionModal}
@@ -473,7 +466,7 @@ const ObjectDetails = ({
closeDeleteModalAndRefresh={closeDeleteModal}
/>
)}
{tagModalOpen && (
{tagModalOpen && actualInfo && (
<AddTagModal
modalOpen={tagModalOpen}
currentTags={actualInfo.tags}
@@ -483,7 +476,7 @@ const ObjectDetails = ({
onCloseAndUpdate={closeAddTagModal}
/>
)}
{deleteTagModalOpen && (
{deleteTagModalOpen && actualInfo && (
<DeleteTagModal
deleteOpen={deleteTagModalOpen}
currentTags={actualInfo.tags}
@@ -494,7 +487,7 @@ const ObjectDetails = ({
selectedTag={selectedTag}
/>
)}
{legalholdOpen && (
{legalholdOpen && actualInfo && (
<SetLegalHoldModal
open={legalholdOpen}
closeModalAndRefresh={closeLegalholdModal}
@@ -505,331 +498,357 @@ const ObjectDetails = ({
)}
<Grid container>
<Grid item xs={12}>
<ScreenTitle
icon={
<Fragment>
<ObjectBrowserIcon width={40} />
</Fragment>
}
title={currentItem}
subTitle={
<Fragment>
<BrowserBreadcrumbs
bucketName={bucketName}
internalPaths={internalPaths}
/>
</Fragment>
}
actions={
<Fragment>
<Tooltip title="Share">
<IconButton
color="primary"
aria-label="share"
onClick={() => {
shareObject();
}}
disabled={actualInfo.is_delete_marker}
>
<ShareIcon />
</IconButton>
</Tooltip>
{downloadingFiles.includes(
`${bucketName}/${actualInfo.name}`
) ? (
<div className="progressDetails">
<CircularProgress
color="primary"
size={17}
variant="indeterminate"
/>
</div>
) : (
<Tooltip title="Download">
<IconButton
color="primary"
aria-label="download"
onClick={() => {
downloadObject(actualInfo);
}}
disabled={actualInfo.is_delete_marker}
>
<DownloadIcon />
</IconButton>
</Tooltip>
)}
<Tooltip title="Delete Object">
<IconButton
color="primary"
aria-label="delete"
onClick={() => {
setDeleteOpen(true);
}}
disabled={actualInfo.is_delete_marker}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</Fragment>
}
/>
</Grid>
<Grid item xs={2}>
<List component="nav" dense={true}>
<ListItem
button
selected={selectedTab === 0}
onClick={() => {
setSelectedTab(0);
}}
>
<ListItemText primary="Details" />
</ListItem>
<ListItem
button
selected={selectedTab === 1}
onClick={() => {
setSelectedTab(1);
}}
disabled={
!(actualInfo.version_id && actualInfo.version_id !== "null")
}
>
<ListItemText primary="Versions" />
</ListItem>
<ListItem
button
selected={selectedTab === 2}
onClick={() => {
setSelectedTab(2);
}}
disabled={extensionPreview(currentItem) === "none"}
>
<ListItemText primary="Preview" />
</ListItem>
</List>
</Grid>
<Grid item xs={10}>
{!actualInfo && (
<Grid item xs={12}>
<TabPanel index={0} value={selectedTab}>
<div className={classes.actionsTray}>
<h1 className={classes.sectionTitle}>Details</h1>
</div>
<br />
<Paper className={classes.paperContainer}>
<Grid container>
<Grid item xs={10}>
<table width={"100%"}>
<tbody>
<tr>
<td className={classes.titleCol}>Legal Hold:</td>
<td className={classes.capitalizeFirst}>
{actualInfo.version_id &&
actualInfo.version_id !== "null" ? (
<Fragment>
{actualInfo.legal_hold_status
? actualInfo.legal_hold_status.toLowerCase()
: "Off"}
<LinearProgress />
</Grid>
)}
{actualInfo && (
<Fragment>
<Grid item xs={12}>
<ScreenTitle
icon={
<Fragment>
<ObjectBrowserIcon width={40} />
</Fragment>
}
title={currentItem}
subTitle={
<Fragment>
<BrowserBreadcrumbs
bucketName={bucketName}
internalPaths={internalPaths}
/>
</Fragment>
}
actions={
<Fragment>
<Tooltip title="Share">
<IconButton
color="primary"
aria-label="share"
onClick={() => {
shareObject();
}}
disabled={actualInfo.is_delete_marker}
>
<ShareIcon />
</IconButton>
</Tooltip>
{downloadingFiles.includes(
`${bucketName}/${actualInfo.name}`
) ? (
<div className="progressDetails">
<CircularProgress
color="primary"
size={17}
variant="indeterminate"
/>
</div>
) : (
<Tooltip title="Download">
<IconButton
color="primary"
aria-label="download"
onClick={() => {
downloadObject(actualInfo);
}}
disabled={actualInfo.is_delete_marker}
>
<DownloadIcon />
</IconButton>
</Tooltip>
)}
<Tooltip title="Delete Object">
<IconButton
color="primary"
aria-label="delete"
onClick={() => {
setDeleteOpen(true);
}}
disabled={actualInfo.is_delete_marker}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</Fragment>
}
/>
</Grid>
<Grid item xs={2}>
<List component="nav" dense={true}>
<ListItem
button
selected={selectedTab === 0}
onClick={() => {
setSelectedTab(0);
}}
>
<ListItemText primary="Details" />
</ListItem>
<ListItem
button
selected={selectedTab === 1}
onClick={() => {
setSelectedTab(1);
}}
disabled={
!(actualInfo.version_id && actualInfo.version_id !== "null")
}
>
<ListItemText primary="Versions" />
</ListItem>
<ListItem
button
selected={selectedTab === 2}
onClick={() => {
setSelectedTab(2);
}}
disabled={extensionPreview(currentItem) === "none"}
>
<ListItemText primary="Preview" />
</ListItem>
</List>
</Grid>
<Grid item xs={10}>
<Grid item xs={12}>
<TabPanel index={0} value={selectedTab}>
<div className={classes.actionsTray}>
<h1 className={classes.sectionTitle}>Details</h1>
</div>
<br />
<Paper className={classes.paperContainer}>
<Grid container>
<Grid item xs={10}>
<table width={"100%"}>
<tbody>
<tr>
<td className={classes.titleCol}>Legal Hold:</td>
<td className={classes.capitalizeFirst}>
{actualInfo.version_id &&
actualInfo.version_id !== "null" ? (
<Fragment>
{actualInfo.legal_hold_status
? actualInfo.legal_hold_status.toLowerCase()
: "Off"}
<IconButton
color="primary"
aria-label="legal-hold"
size="small"
className={classes.propertiesIcon}
onClick={() => {
setLegalholdOpen(true);
}}
>
<EditIcon />
</IconButton>
</Fragment>
) : (
"Disabled"
)}
</td>
</tr>
<tr>
<td className={classes.titleCol}>Retention:</td>
<td className={classes.capitalizeFirst}>
{actualInfo.retention_mode
? actualInfo.retention_mode.toLowerCase()
: "Undefined"}
<IconButton
color="primary"
aria-label="legal-hold"
aria-label="retention"
size="small"
className={classes.propertiesIcon}
onClick={() => {
setLegalholdOpen(true);
openRetentionModal();
}}
>
<EditIcon />
</IconButton>
</Fragment>
) : (
"Disabled"
)}
</td>
</tr>
<tr>
<td className={classes.titleCol}>Retention:</td>
<td className={classes.capitalizeFirst}>
{actualInfo.retention_mode
? actualInfo.retention_mode.toLowerCase()
: "Undefined"}
<IconButton
color="primary"
aria-label="retention"
size="small"
className={classes.propertiesIcon}
onClick={() => {
openRetentionModal();
}}
>
<EditIcon />
</IconButton>
</td>
</tr>
<tr>
<td className={classes.titleCol}>Tags:</td>
<td>
{tagKeys &&
tagKeys.map((tagKey, index) => {
const tag = get(
actualInfo,
`tags.${tagKey}`,
""
);
if (tag !== "") {
return (
<Chip
key={`chip-${index}`}
className={classes.tag}
size="small"
label={`${tagKey} : ${tag}`}
color="primary"
deleteIcon={<CloseIcon />}
onDelete={() => {
deleteTag(tagKey, tag);
}}
/>
);
}
return null;
})}
<Chip
className={classes.tag}
icon={<AddIcon />}
clickable
size="small"
label="Add tag"
color="primary"
variant="outlined"
onClick={() => {
setTagModalOpen(true);
}}
/>
</td>
</tr>
</tbody>
</table>
</Grid>
</Grid>
</Paper>
<br />
<br />
<Paper className={classes.paperContainer}>
<Grid item xs={12}>
<Grid item xs={12}>
<h2>Object Metadata</h2>
<hr className={classes.hr}></hr>
</Grid>
</td>
</tr>
<tr>
<td className={classes.titleCol}>Tags:</td>
<td>
{tagKeys &&
tagKeys.map((tagKey, index) => {
const tag = get(
actualInfo,
`tags.${tagKey}`,
""
);
if (tag !== "") {
return (
<Chip
key={`chip-${index}`}
className={classes.tag}
size="small"
label={`${tagKey} : ${tag}`}
color="primary"
deleteIcon={<CloseIcon />}
onDelete={() => {
deleteTag(tagKey, tag);
}}
/>
);
}
return null;
})}
<Chip
className={classes.tag}
icon={<AddIcon />}
clickable
size="small"
label="Add tag"
color="primary"
variant="outlined"
onClick={() => {
setTagModalOpen(true);
}}
/>
</td>
</tr>
</tbody>
</table>
</Grid>
</Grid>
</Paper>
<br />
<br />
<Paper className={classes.paperContainer}>
<Grid item xs={12}>
<Grid item xs={12}>
<h2>Object Metadata</h2>
<hr className={classes.hr}></hr>
</Grid>
<Grid item xs={12}>
<Table className={classes.table} aria-label="simple table">
<TableBody>
{Object.keys(metadata).map((element, index) => {
return (
<TableRow key={`tRow-${index.toString()}`}>
<TableCell
component="th"
scope="row"
className={classes.titleItem}
>
{element}
</TableCell>
<TableCell align="right">
{metadata[element]}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</Grid>
</Grid>
</Paper>
</TabPanel>
<TabPanel index={1} value={selectedTab}>
<Fragment>
<div className={classes.actionsTray}>
<h1 className={classes.sectionTitle}>Versions</h1>
</div>
<br />
<Grid item xs={12} className={classes.actionsTray}>
{actualInfo.version_id && actualInfo.version_id !== "null" && (
<TextField
placeholder={`Search ${currentItem}`}
className={clsx(classes.search, classes.searchField)}
id="search-resource"
label=""
onChange={(val) => {
setFilterVersion(val.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
<Grid item xs={12}>
<Table
className={classes.table}
aria-label="simple table"
>
<TableBody>
{Object.keys(metadata).map((element, index) => {
return (
<TableRow key={`tRow-${index.toString()}`}>
<TableCell
component="th"
scope="row"
className={classes.titleItem}
>
{element}
</TableCell>
<TableCell align="right">
{metadata[element]}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</Grid>
</Grid>
</Paper>
</TabPanel>
<TabPanel index={1} value={selectedTab}>
<Fragment>
<div className={classes.actionsTray}>
<h1 className={classes.sectionTitle}>Versions</h1>
</div>
<br />
<Grid item xs={12} className={classes.actionsTray}>
{actualInfo.version_id &&
actualInfo.version_id !== "null" && (
<TextField
placeholder={`Search ${currentItem}`}
className={clsx(
classes.search,
classes.searchField
)}
id="search-resource"
label=""
onChange={(val) => {
setFilterVersion(val.target.value);
}}
InputProps={{
disableUnderline: true,
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
/>
)}
</Grid>
<Grid item xs={12}>
{actualInfo.version_id &&
actualInfo.version_id !== "null" && (
<TableWrapper
itemActions={tableActions}
columns={[
{
label: "",
width: 20,
renderFullObject: true,
renderFunction: (r) => {
const versOrd =
versions.length - versions.indexOf(r);
return `v${versOrd}`;
},
elementKey: "version_id",
},
{ label: "Version ID", elementKey: "version_id" },
{
label: "Last Modified",
elementKey: "last_modified",
renderFunction: displayParsedDate,
},
{
label: "Deleted",
width: 60,
contentTextAlign: "center",
renderFullObject: true,
elementKey: "is_delete_marker",
renderFunction: (r) => {
const versOrd = r.is_delete_marker
? "Yes"
: "No";
return `${versOrd}`;
},
},
]}
isLoading={false}
entityName="Versions"
idField="version_id"
records={filteredRecords}
/>
)}
</Grid>
</Fragment>
</TabPanel>
<TabPanel index={2} value={selectedTab}>
{selectedTab === 2 && actualInfo && (
<PreviewFileContent
bucketName={bucketName}
object={{
name: actualInfo.name,
version_id: actualInfo.version_id || "null",
size: parseInt(actualInfo.size || "0"),
content_type: "",
last_modified: new Date(actualInfo.last_modified),
}}
isFullscreen
/>
)}
</Grid>
<Grid item xs={12}>
{actualInfo.version_id && actualInfo.version_id !== "null" && (
<TableWrapper
itemActions={tableActions}
columns={[
{
label: "",
width: 20,
renderFullObject: true,
renderFunction: (r) => {
const versOrd =
versions.length - versions.indexOf(r);
return `v${versOrd}`;
},
elementKey: "version_id",
},
{ label: "Version ID", elementKey: "version_id" },
{
label: "Last Modified",
elementKey: "last_modified",
renderFunction: displayParsedDate,
},
{
label: "Deleted",
width: 60,
contentTextAlign: "center",
renderFullObject: true,
elementKey: "is_delete_marker",
renderFunction: (r) => {
const versOrd = r.is_delete_marker ? "Yes" : "No";
return `${versOrd}`;
},
},
]}
isLoading={false}
entityName="Versions"
idField="version_id"
records={filteredRecords}
/>
)}
</Grid>
</Fragment>
</TabPanel>
<TabPanel index={2} value={selectedTab}>
{selectedTab === 2 && (
<PreviewFileContent
bucketName={bucketName}
object={previewObject}
isFullscreen
/>
)}
</TabPanel>
</Grid>
</Grid>
</TabPanel>
</Grid>
</Grid>
</Fragment>
)}
</Grid>
</React.Fragment>
);

View File

@@ -51,6 +51,7 @@ export const extensionPreview = (
"jpeg",
"gif",
"png",
"heic",
];
const textExtensions = ["pdf", "txt"];
const audioExtensions = ["wav", "mp3", "alac", "aiff", "dsd", "pcm"];