-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: file upload and display section functionallity
- Loading branch information
1 parent
008eb77
commit 5252473
Showing
13 changed files
with
406 additions
and
12 deletions.
There are no files selected for viewing
132 changes: 132 additions & 0 deletions
132
GUI/front-end/src/components/displays/extension/FileInstance.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { Box, Typography, useTheme, IconButton, Button } from "@mui/material"; | ||
import { useLanguageContext } from "../../../contexts"; | ||
import { useEffect, useState } from "react"; | ||
import { useDeleteFile, useGetWorkspaceFiles, useUploadFile } from "../../../hooks"; | ||
import { useWorkspaceContext } from "../../../contexts/tool/UseWorkspaceContext"; | ||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; | ||
import FileInput from "../../fileInput/FileInput"; | ||
|
||
const FileInstance: React.FC = () => { | ||
|
||
const Theme = useTheme(); | ||
|
||
const languageContext = useLanguageContext(); | ||
const workspaceContext = useWorkspaceContext(); | ||
const deleteFile = useDeleteFile(); | ||
const createFile = useUploadFile(); | ||
|
||
|
||
const [files, setFiles] = useState<string[]>([]); | ||
const [file, setFile] = useState<string | ArrayBuffer | null>(null); | ||
const [fileName, setFileName] = useState<string>(''); | ||
|
||
const { data, isLoading, isFetching } = useGetWorkspaceFiles(workspaceContext.workspace as string); | ||
|
||
useEffect(() => { | ||
if (data?.files.length > 0) { | ||
setFiles(data.files); | ||
} else { | ||
setFiles([]); | ||
} | ||
}, [data]); | ||
|
||
const onFileSelect = (selectedFile: string | ArrayBuffer | null, name: string) => { | ||
setFile(selectedFile); | ||
setFileName(name); | ||
} | ||
|
||
const createNewFile = async () => { | ||
|
||
const binaryData = dataURLtoBlob(file); | ||
|
||
const data = new FormData(); | ||
data.append('workspace', workspaceContext.workspace as string); | ||
data.append('file', binaryData); | ||
data.append('file_name', fileName); | ||
|
||
await createFile.mutateAsync(data); | ||
} | ||
|
||
const dataURLtoBlob = (file : string | ArrayBuffer | null) => { | ||
const stringFile = file as string; | ||
const arr = stringFile.split(","); | ||
const mimeMatch = arr[0].match(/:(.*?);/); | ||
|
||
if (!mimeMatch) { | ||
return new Blob(); | ||
} | ||
|
||
const mime = mimeMatch[1]; | ||
const bstr = atob(arr[1]); | ||
let n = bstr.length; | ||
const u8arr = new Uint8Array(n); | ||
|
||
while (n--) { | ||
u8arr[n] = bstr.charCodeAt(n); | ||
} | ||
|
||
return new Blob([u8arr], { type: mime }); | ||
}; | ||
|
||
return ( | ||
<> | ||
{workspaceContext.workspace && !isLoading && !isFetching && ( | ||
<> | ||
<Typography>{languageContext.language === 'en' ? 'Files' : 'Failai'}</Typography> | ||
<Box | ||
sx={{ | ||
color: Theme.palette.text.secondary, | ||
backgroundColor: Theme.palette.background.default, | ||
borderRadius: '10px', | ||
padding: '10px', | ||
px: '10px', | ||
}} | ||
> | ||
<FileInput onFileSelect={onFileSelect} /> | ||
<Button | ||
variant="contained" | ||
sx={{ | ||
color: Theme.palette.text.secondary, | ||
backgroundColor: Theme.palette.background.default, | ||
borderRadius: '10px', | ||
height: '40px', | ||
px: '10px', | ||
}} | ||
onClick={() => createNewFile()} | ||
> | ||
{languageContext.language === 'en' ? 'Upload file' : 'Įkelti failą'} | ||
</Button> | ||
{file && fileName && (fileName)} | ||
{ | ||
files?.length > 0 ? ( | ||
files.map((file) => ( | ||
<Typography key={file}> | ||
{file} | ||
<IconButton | ||
edge="end" | ||
aria-label="delete" | ||
size="small" | ||
onClick={ async () => { | ||
const data = { | ||
workspace: workspaceContext.workspace, | ||
file_name: file, | ||
} | ||
|
||
await deleteFile.mutateAsync(data); | ||
}} | ||
> | ||
<DeleteForeverIcon sx={{ height: '40px' }} /> | ||
</IconButton> | ||
</Typography> | ||
)) | ||
) : ( | ||
<Typography>{languageContext.language === 'en' ? 'No files' : 'Nėra failų'}</Typography> | ||
)} | ||
</Box> | ||
</> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
export default FileInstance; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
GUI/front-end/src/components/displays/extension/WorkspaceInstance.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { Select, useTheme, styled, MenuItem, TextField, Button, IconButton } from "@mui/material"; | ||
import { ArrowDropDown as ArrowDropDownIcon } from '@mui/icons-material/'; | ||
import { useLanguageContext } from "../../../contexts"; | ||
import { useWorkspaceContext } from "../../../contexts/tool/UseWorkspaceContext"; | ||
import { useEffect, useState } from "react"; | ||
import { useCreateWorkspace, useDeleteWorkspace, useGetWorkspaces } from "../../../hooks"; | ||
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; | ||
import FileInstance from "./FileInstance"; | ||
|
||
const WorkspaceInstance: React.FC = () => { | ||
const Theme = useTheme(); | ||
|
||
const languageContext = useLanguageContext(); | ||
const workspaceContext = useWorkspaceContext(); | ||
|
||
const [awailableWorkspaces, setAwailableWorkspaces] = useState<string[]>([]); | ||
const [newWorkspace, setNewWorkspace] = useState<string>(''); | ||
|
||
const { data, isLoading, isFetching } = useGetWorkspaces(); | ||
const createWorkspace = useCreateWorkspace(); | ||
const deleteWorkspace = useDeleteWorkspace(); | ||
|
||
const createNewWorkspace = () => { | ||
createWorkspace.mutate(newWorkspace); | ||
workspaceContext.update(newWorkspace); | ||
setNewWorkspace(''); | ||
} | ||
|
||
useEffect(() => { | ||
if (data?.workspaces.length > 0) { | ||
setAwailableWorkspaces(data.workspaces); | ||
} else { | ||
setAwailableWorkspaces([]); | ||
} | ||
}, [data]); | ||
|
||
return ( | ||
<> | ||
<TextField | ||
variant="standard" | ||
sx={{ | ||
color: Theme.palette.text.secondary, | ||
backgroundColor: Theme.palette.background.default, | ||
borderRadius: '10px', | ||
height: '40px', | ||
px: '10px', | ||
}} | ||
label={languageContext.language === 'en' ? 'Create new workspace' : 'Pridėti darbo aplinką'} | ||
value={newWorkspace} | ||
onChange={(e) => setNewWorkspace(e.target.value)} | ||
/> | ||
<Button | ||
variant="contained" | ||
sx={{ | ||
color: Theme.palette.text.secondary, | ||
backgroundColor: Theme.palette.background.default, | ||
borderRadius: '10px', | ||
height: '40px', | ||
px: '10px', | ||
}} | ||
onClick={() => createNewWorkspace()} | ||
> | ||
{languageContext.language === 'en' ? 'Create' : 'Sukurti'} | ||
</Button> | ||
{awailableWorkspaces.length > 0 && !isFetching && !isLoading && ( | ||
<> | ||
<Select | ||
variant="standard" | ||
IconComponent={styled(ArrowDropDownIcon)({ | ||
width: '24px', | ||
height: '24px', | ||
})} | ||
disableInjectingGlobalStyles={true} | ||
disableUnderline={true} | ||
sx={{ | ||
color: Theme.palette.text.secondary, | ||
backgroundColor: Theme.palette.background.default, | ||
borderRadius: '10px', | ||
height: '40px', | ||
px: '10px', | ||
}} | ||
value={workspaceContext.workspace || ''} | ||
onChange={(e) => workspaceContext.update(e.target.value as string)} | ||
> | ||
{ | ||
awailableWorkspaces.map((value) => ( | ||
<MenuItem | ||
key={value} | ||
value={value} | ||
sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }} | ||
> | ||
{value} | ||
<IconButton | ||
edge="end" | ||
aria-label="delete" | ||
size="small" | ||
onClick={ async (e) => { | ||
e.stopPropagation(); | ||
await deleteWorkspace.mutate(value); | ||
workspaceContext.update(''); | ||
}} | ||
> | ||
<DeleteForeverIcon sx={{ height: '40px' }} /> | ||
</IconButton> | ||
</MenuItem> | ||
))} | ||
</Select> | ||
<FileInstance /> | ||
</> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
export default WorkspaceInstance; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Button } from "@mui/material"; | ||
import { useRef } from "react"; | ||
import { useLanguageContext } from "../../contexts"; | ||
|
||
function FileInput({ onFileSelect } : { onFileSelect: (file: string | ArrayBuffer | null, name: string) => void}){ | ||
const languageContext = useLanguageContext(); | ||
const inputRef = useRef<HTMLInputElement>(null); | ||
|
||
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
if(e.target.files && e.target.files.length > 0){ | ||
const file = e.target.files[0]; | ||
|
||
if(!['text/plain'].includes(file.type)){ | ||
alert('Please select a text file'); | ||
return; | ||
} | ||
|
||
const reader = new FileReader(); | ||
reader.readAsDataURL(file); | ||
reader.onload = () => { | ||
onFileSelect(reader.result, file.name); | ||
}; | ||
|
||
if (inputRef.current) { | ||
inputRef.current.value = ''; | ||
} | ||
} | ||
|
||
|
||
}; | ||
|
||
const onFileInputClick = () => { | ||
if (inputRef.current) { | ||
inputRef.current.click(); | ||
} | ||
}; | ||
|
||
return ( | ||
<div> | ||
<input | ||
type="file" | ||
accept=".txt" | ||
ref={inputRef} | ||
onChange={handleFileSelect} | ||
style={{ display: 'none' }} | ||
/> | ||
<Button | ||
variant="contained" | ||
onClick={onFileInputClick} | ||
> | ||
{languageContext.language === 'en' ? 'Select file' : 'Pasirinkti failą'} | ||
</Button> | ||
</div> | ||
); | ||
} | ||
|
||
export default FileInput; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { useContext } from "react"; | ||
import { WorkspaceContext } from "./WorkspaceContextProvider"; | ||
|
||
export const useWorkspaceContext = () => useContext(WorkspaceContext); |
29 changes: 29 additions & 0 deletions
29
GUI/front-end/src/contexts/tool/WorkspaceContextProvider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React, { createContext, useState } from "react"; | ||
|
||
interface WorkspaceContextProps { | ||
workspace: string | null; | ||
update: (newWorkspace: string) => void; | ||
} | ||
|
||
export const WorkspaceContext = createContext<WorkspaceContextProps>({ | ||
workspace: null, | ||
update: () => {}, | ||
}) | ||
|
||
interface Props { | ||
children?: React.ReactNode; | ||
} | ||
|
||
export const WorkspaceContextProvider: React.FC<Props> = ({ children }) => { | ||
const [workspace, setWorkspace] = useState<string | null>(null); | ||
|
||
function updateWorkspace(newWorkspace: string) { | ||
setWorkspace(newWorkspace); | ||
} | ||
|
||
return ( | ||
<WorkspaceContext.Provider value={{ workspace, update: updateWorkspace }}> | ||
{children} | ||
</WorkspaceContext.Provider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
export { useGetUsers } from './user/userHook'; | ||
export { useSendRequest } from './request/requestHook'; | ||
export { useGetWorkspaces, useCreateWorkspace, useDeleteWorkspace, useGetWorkspaceFiles } from './workspace/workspaceHook'; | ||
export { useGetWorkspaces, useCreateWorkspace, useDeleteWorkspace, useGetWorkspaceFiles, useUploadFile, useDeleteFile } from './workspace/workspaceHook'; |
Oops, something went wrong.