mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-04-10 06:09:03 +02:00
render image grid for admin file list
This commit is contained in:
parent
f724203a93
commit
0786c6830c
@ -4,7 +4,6 @@ import {useSelector} from "react-redux";
|
||||
import {Navigate} from "react-router-dom";
|
||||
import {AdminProfile} from "@void-cat/api";
|
||||
|
||||
import {FileList} from "../Components/Shared/FileList";
|
||||
import {UserList} from "./UserList";
|
||||
import {VoidButton} from "../Components/Shared/VoidButton";
|
||||
import VoidModal from "../Components/Shared/VoidModal";
|
||||
@ -12,6 +11,7 @@ import EditUser from "./EditUser";
|
||||
|
||||
import useApi from "Hooks/UseApi";
|
||||
import {RootState} from "Store";
|
||||
import ImageGrid from "../Components/Shared/ImageGrid";
|
||||
|
||||
export function Admin() {
|
||||
const auth = useSelector((state: RootState) => state.login.jwt);
|
||||
@ -41,7 +41,7 @@ export function Admin() {
|
||||
]}/>
|
||||
|
||||
<h2>Files</h2>
|
||||
<FileList loadPage={r => AdminApi.adminListFiles(r)} actions={(i) => {
|
||||
<ImageGrid loadPage={r => AdminApi.adminListFiles(r)} actions={(i) => {
|
||||
return <td>
|
||||
<VoidButton onClick={() => deleteFile(i.id)}>Delete</VoidButton>
|
||||
</td>
|
||||
|
@ -65,7 +65,7 @@ export function FileList(props: FileListProps) {
|
||||
loadFileList().catch(console.error)
|
||||
}, [page]);
|
||||
|
||||
if (accessDenied === true) {
|
||||
if (accessDenied) {
|
||||
return <h3>Access Denied</h3>;
|
||||
}
|
||||
|
||||
|
18
VoidCat/spa/src/app/src/Components/Shared/ImageGrid.css
Normal file
18
VoidCat/spa/src/app/src/Components/Shared/ImageGrid.css
Normal file
@ -0,0 +1,18 @@
|
||||
.image-grid {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.image-grid > div {
|
||||
width: 100px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-grid img, .image-grid video, .image-grid audio {
|
||||
width: stretch;
|
||||
}
|
103
VoidCat/spa/src/app/src/Components/Shared/ImageGrid.tsx
Normal file
103
VoidCat/spa/src/app/src/Components/Shared/ImageGrid.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import "./ImageGrid.css";
|
||||
|
||||
import {ApiError, PagedRequest, PagedResponse, PagedSortBy, PageSortOrder, VoidFileResponse} from "@void-cat/api";
|
||||
import {ReactNode, useEffect, useState} from "react";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {logout} from "../../LoginState";
|
||||
import {PageSelector} from "./PageSelector";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
|
||||
interface ImageGridProps {
|
||||
actions?: (f: VoidFileResponse) => ReactNode
|
||||
loadPage: (req: PagedRequest) => Promise<PagedResponse<any>>
|
||||
}
|
||||
|
||||
export default function ImageGrid(props: ImageGridProps) {
|
||||
const navigate = useNavigate();
|
||||
const loadPage = props.loadPage;
|
||||
const actions = props.actions;
|
||||
const dispatch = useDispatch();
|
||||
const [files, setFiles] = useState<PagedResponse<VoidFileResponse>>();
|
||||
const [page, setPage] = useState(0);
|
||||
const pageSize = 20;
|
||||
const [accessDenied, setAccessDenied] = useState<boolean>();
|
||||
|
||||
async function loadFileList() {
|
||||
try {
|
||||
const pageReq = {
|
||||
page: page,
|
||||
pageSize,
|
||||
sortBy: PagedSortBy.Date,
|
||||
sortOrder: PageSortOrder.Dsc
|
||||
};
|
||||
const rsp = await loadPage(pageReq);
|
||||
setFiles(rsp);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (e instanceof ApiError) {
|
||||
if (e.statusCode === 401) {
|
||||
dispatch(logout());
|
||||
} else if (e.statusCode === 403) {
|
||||
setAccessDenied(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadFileList().catch(console.error)
|
||||
}, [page]);
|
||||
|
||||
function renderPreview(info: VoidFileResponse) {
|
||||
const link = `/d/${info.id}`;
|
||||
|
||||
if (info.metadata) {
|
||||
switch (info.metadata.mimeType) {
|
||||
case "image/avif":
|
||||
case "image/bmp":
|
||||
case "image/gif":
|
||||
case "image/svg+xml":
|
||||
case "image/tiff":
|
||||
case "image/webp":
|
||||
case "image/jpg":
|
||||
case "image/jpeg":
|
||||
case "image/png": {
|
||||
return <img src={link} alt={info.metadata.name}/>;
|
||||
}
|
||||
case "audio/aac":
|
||||
case "audio/opus":
|
||||
case "audio/wav":
|
||||
case "audio/webm":
|
||||
case "audio/midi":
|
||||
case "audio/mpeg":
|
||||
case "audio/ogg": {
|
||||
return <audio src={link} controls/>;
|
||||
}
|
||||
case "video/x-msvideo":
|
||||
case "video/mpeg":
|
||||
case "video/ogg":
|
||||
case "video/mp2t":
|
||||
case "video/mp4":
|
||||
case "video/matroksa":
|
||||
case "video/x-matroska":
|
||||
case "video/webm":
|
||||
case "video/quicktime": {
|
||||
return <video src={link}/>;
|
||||
}
|
||||
default: {
|
||||
return <b>{info.metadata?.name ?? info.id}</b>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className="image-grid">
|
||||
{files?.results.map(v => <div key={v.id} onClick={() => navigate(`/${v.id}`)}>
|
||||
{renderPreview(v)}
|
||||
</div>)}
|
||||
</div>
|
||||
<PageSelector onSelectPage={(x) => setPage(x)} page={page} total={files?.totalResults ?? 0}
|
||||
pageSize={pageSize}/>
|
||||
</>
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
grid-auto-flow: column;
|
||||
width: min-content;
|
||||
margin-top: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.page-buttons > div {
|
||||
|
Loading…
x
Reference in New Issue
Block a user