Skip to content

Commit

Permalink
Merge pull request #102 from hotosm/feature/file_structure
Browse files Browse the repository at this point in the history
Feature File Structure
  • Loading branch information
kshitijrajsharma authored Apr 14, 2023
2 parents 99fb8e3 + 13e2354 commit bb384d0
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 60 deletions.
118 changes: 58 additions & 60 deletions frontend/src/components/Header/UserProfile.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,59 @@
import { Avatar, IconButton, Typography } from '@mui/material'
import React, { useContext, useEffect } from 'react'
import AuthContext from '../../Context/AuthContext'
import axios from '../../axios'
import { useQuery } from 'react-query'
const UserProfile = props => {

const { accessToken,authenticate } = useContext(AuthContext);

const authMe = async () => {

if (!accessToken) return;
try {
const headers = {
"access-token": accessToken
}
const res = await axios.get(`/auth/me/`, { headers });

if (res.error) {
// setMapError(res.error.response.statusText);
console.log(res);
if (res.error.response.status === 403)
{
authenticate('')
}
}
else {
console.log('Auth me ', res.data)
return res.data;
}

} catch (e) {
console.log("isError", e);

} finally {

import { Avatar, IconButton, Typography } from "@mui/material";
import React, { useContext, useEffect } from "react";
import AuthContext from "../../Context/AuthContext";
import axios from "../../axios";
import { useQuery } from "react-query";
const UserProfile = (props) => {
const { accessToken, authenticate } = useContext(AuthContext);

const authMe = async () => {
if (!accessToken) return;
try {
const headers = {
"access-token": accessToken,
};
const res = await axios.get(`/auth/me/`, { headers });

if (res.error) {
// setMapError(res.error.response.statusText);
console.log(res);
if (res.error.response.status === 403) {
authenticate("");
}
};
const { data, refetch } = useQuery("authMe" + props.aoiId, authMe, { refetchInterval: 120000 });

useEffect(() => {
if (accessToken)
refetch()

return () => {

}
}, [accessToken, refetch])

return (

<div>
<IconButton onClick={props.handleOpenUserMenu} sx={{ p: 0 }} >
<Avatar alt="Remy Sharp" src={accessToken && data && data.img_url} />
</IconButton>
<Typography variant="caption" display="block" textAlign="center" gutterBottom>{accessToken && data ? data.username : "Login here"}</Typography>
</div>
)
}

export default UserProfile
} else {
// console.log('Auth me ', res.data)
return res.data;
}
} catch (e) {
console.log("isError", e);
} finally {
}
};
const { data, refetch } = useQuery("authMe" + props.aoiId, authMe, {
refetchInterval: 120000,
});

useEffect(() => {
if (accessToken) refetch();

return () => {};
}, [accessToken, refetch]);

return (
<div>
<IconButton onClick={props.handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar alt="Remy Sharp" src={accessToken && data && data.img_url} />
</IconButton>
<Typography
variant="caption"
display="block"
textAlign="center"
gutterBottom
>
{accessToken && data ? data.username : "Login here"}
</Typography>
</div>
);
};

export default UserProfile;
146 changes: 146 additions & 0 deletions frontend/src/components/Layout/AIModels/AIModelEditor/FileStructure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import React, { useState } from "react";
import {
ListItem,
ListItemIcon,
ListItemText,
CircularProgress,
Collapse,
Box,
Button,
} from "@mui/material";
import {
Folder,
InsertDriveFile,
ExpandLess,
ExpandMore,
} from "@mui/icons-material";

const FileStructure = ({
name,
content,
length,
size,
path,
isFile,
downloadUrl,
onDirClick,
}) => {
const [open, setOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);

const handleClick = () => {
if (!isFile) {
setOpen(!open);
setIsLoading(true);
onDirClick(`${path}/`);
setIsLoading(false);
} else {
window.open(`${downloadUrl}${path}`, "_blank");
}
};
const formatFileSize = (sizeInBytes) => {
const units = ["bytes", "KB", "MB", "GB", "TB"];

let formattedSize = sizeInBytes;
let unitIndex = 0;

while (formattedSize > 1024 && unitIndex < units.length - 1) {
formattedSize /= 1024;
unitIndex++;
}

return `${formattedSize.toFixed(2)} ${units[unitIndex]}`;
};

const renderContent = () => {
if (isFile) return null;

const dirContent = Object.entries(content.dir || {}).map(([key, value]) => {
return (
<FileStructure
key={key}
name={key}
length={value["len"]}
size={value["size"]}
content={value}
path={`${path}${key}/`}
isFile={false}
downloadUrl={downloadUrl}
onDirClick={onDirClick}
/>
);
});

const fileContent = Object.entries(content.file || {}).map(
([key, value]) => (
<FileStructure
key={key}
name={key}
size={value["size"]}
length={value["len"]}
content={value}
path={`${path}${key}`}
isFile={true}
downloadUrl={downloadUrl}
/>
)
);

return [...dirContent, ...fileContent];
};

const iconStyles = {
minWidth: "32px",
color: "#757575",
};

const listItemTextStyles = {
fontSize: "0.875rem",
color: "white",
};

return (
<Box borderRadius="5px" padding="8px">
<ListItem
Button
onClick={handleClick}
style={{
paddingLeft: isFile ? "32px" : "16px",
color: "white",
background: "#E7D6BD",
}}
>
<ListItemIcon style={iconStyles}>
{isFile ? (
<InsertDriveFile fontSize="small" />
) : (
<Folder fontSize="small" />
)}
</ListItemIcon>
<ListItemText
primary={name}
secondary={`${size ? formatFileSize(size) : ""} ${
length ? `${length} file` : ""
}`}
primaryTypographyProps={{ style: listItemTextStyles }}
/>

{!isFile &&
(open ? (
<ExpandLess fontSize="small" />
) : (
<ExpandMore fontSize="small" />
))}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
{isLoading ? (
<CircularProgress size={20} style={{ margin: "16px" }} />
) : (
renderContent()
)}
</Collapse>
</Box>
);
};

export default FileStructure;
69 changes: 69 additions & 0 deletions frontend/src/components/Layout/AIModels/AIModelEditor/Popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,51 @@ import {
Button,
CircularProgress,
} from "@mui/material";
import FileStructure from "./FileStructure";

import axios from "../../../../axios";

const Popup = ({ open, handleClose, row }) => {
const [error, setError] = useState(null);
const [traceback, setTraceback] = useState(null);
const [imageUrl, setImageUrl] = useState(null);
const [trainingWorkspaceURL, settrainingWorkspaceURL] = useState(null);

const [loading, setLoading] = useState(false);
const [fileStructure, setFileStructure] = useState(null);
const [dirHistory, setDirHistory] = useState([]);

const getFileStructure = async (currentPath = "") => {
try {
const res = await axios.get(
`/workspace/${trainingWorkspaceURL}${currentPath}`
);
if (res.error) {
console.error(res.error);
} else {
setFileStructure(res.data);
}
} catch (e) {
console.error(e);
}
};

const handleDirClick = (newPath) => {
setDirHistory([...dirHistory, newPath]);
getFileStructure(newPath);
};

const handleGoBack = () => {
const newHistory = [...dirHistory];
newHistory.pop();
setDirHistory(newHistory);

if (newHistory.length > 0) {
getFileStructure(newHistory[newHistory.length - 1]);
} else {
getFileStructure();
}
};
const getTrainingStatus = async (taskId) => {
try {
const res = await axios.get(`/training/status/${taskId}`);
Expand Down Expand Up @@ -42,6 +79,9 @@ const Popup = ({ open, handleClose, row }) => {
setImageUrl(
`${axios.defaults.baseURL}/workspace/download/dataset_${res.data.dataset}/output/training_${row.id}/graphs/training_validation_sparse_categorical_accuracy.png`
);
settrainingWorkspaceURL(
`dataset_${res.data.dataset}/output/training_${row.id}/`
);
}
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -103,6 +143,23 @@ const Popup = ({ open, handleClose, row }) => {
<p>
<b>Status:</b> {row.status}
</p>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Button
onClick={() => getFileStructure()}
style={{ color: "white", fontSize: "0.875rem" }}
>
Training Files
</Button>
{row.status === "FINISHED" && (
<Button
onClick={handleGoBack}
disabled={dirHistory.length === 0}
style={{ color: "white", fontSize: "0.875rem" }}
>
Go Back
</Button>
)}
</div>
{(row.status === "FAILED" || row.status === "RUNNING") && (
<>
{loading ? (
Expand Down Expand Up @@ -130,6 +187,18 @@ const Popup = ({ open, handleClose, row }) => {
)}
{row.status === "FINISHED" && (
<>
{fileStructure && (
<FileStructure
name={`training_${row.id}`}
content={fileStructure}
path={
dirHistory.length > 0 ? dirHistory[dirHistory.length - 1] : ""
}
isFile={false}
downloadUrl={`${axios.defaults.baseURL}/workspace/download/${trainingWorkspaceURL}`}
onDirClick={handleDirClick}
/>
)}
{loading ? (
<div style={{ display: "flex", justifyContent: "center" }}>
<CircularProgress />
Expand Down

0 comments on commit bb384d0

Please sign in to comment.