반응형
깃허브 데스크탑으로 프로젝트 관리하기 강의 오픈!! (인프런 바로가기)
참고
- 깃허브 리포지토리 이미지 불러오기
- 깃허브 API로 이미지 업로드하기
- 깃허브에 업로드된 이미지 삭제하기
- 캡처한 이미지를 깃허브에 업로드하기
- 캡처한 이미지 여러 개 업로드하기
- Toast UI 에디터로 이미지를 포함한 깃허브 마크다운 저장하기
이제 업로드된 이미지를 리액트에서 지우고, 깃허브에서 파일을 삭제해 보자.
먼저 아이콘 버튼을 알맞은 이미지로 교체하자.
DeleteOutlineIcon으로 수정하였다.
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
...
<ImageListItemBar
title={item.title}
subtitle={item.author}
actionIcon={
<IconButton
sx={{ color: "rgba(255, 255, 255, 0.54)" }}
aria-label={`info about ${item.title}`}
>
<DeleteOutlineIcon />
</IconButton>
}
/>
깃허브에 업로드된 이미지를 지우기 위해 fileLoad를 할 때, path 정보도 저장해 둔다.
const fileLoad = async () => {
...
for (let path of fileList) {
let obj = {
img: `https://github.com/bloodstrawberry/auto-test/raw/main/${path}`,
title: `image_${count++}`,
author: "bloodstrawberry",
path // for delete
};
temp.push(obj);
}
setItemData(temp);
};
IconButton에 deleteImage 메서드를 추가한다.
<IconButton
sx={{ color: "rgba(255, 255, 255, 0.54)" }}
aria-label={`info about ${item.title}`}
onClick={() => deleteImage(item.path)}
>
<DeleteOutlineIcon />
</IconButton>
해당 메서드에서 path 정보를 전달받았기 때문에 filter와 setItemData로 이미지를 새로 갱신한다.
const deleteImage = (path) => {
let newItemData = itemData.filter((item) => item.path !== path);
setItemData(newItemData);
}
아래와 같이 이미지가 사라지는 것을 알 수 있다.
Delete GitHub Image
깃허브 RESTful API로 리포지토리의 파일을 삭제할 수 있다.
링크를 참고하여 fileDelete를 추가하자. (아래 전체 코드 참고)
const deleteImage = async (path) => {
let newItemData = itemData.filter((item) => item.path !== path);
setItemData(newItemData);
let response = await gh.fileDelete(path);
console.log(response);
}
삭제 버튼을 클릭하면 아래와 같이 응답을 받을 수 있다.
실제 리포지토리에서 commit history를 확인해 보자.
전체 코드는 다음과 같다.
githublibrary.js
import axios from "axios";
import { Octokit } from "@octokit/rest";
const myKey = process.env.REACT_APP_MY_TOKEN;
const repo = `auto-test`;
const getSHA = async (path) => {
const octokit = new Octokit({
auth: myKey,
});
try {
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
return result.data.sha;
}
catch (e) {
console.log("error : ", e);
return undefined;
}
};
export const fileDelete = async (path) => {
let sha = await getSHA(path);
if(sha === undefined) return undefined;
try {
const octokit = new Octokit({
auth: myKey,
});
const result = await octokit.request(
`DELETE /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo,
path,
message: "delete!!",
sha,
}
);
return result;
} catch (e) {
console.log("error : ", e);
return undefined;
}
};
export const fileRead = async (path) => {
try {
const octokit = new Octokit({
auth: myKey,
});
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
encoding: "utf-8",
decoding: "utf-8",
}
);
return result;
} catch (e) {
console.log("error : ", e);
return undefined;
}
};
ReactImageList.js
import React, { useEffect, useState } from "react";
import Box from "@mui/material/Box";
import ImageList from "@mui/material/ImageList";
import ImageListItem from "@mui/material/ImageListItem";
import ImageListItemBar from "@mui/material/ImageListItemBar";
import ListSubheader from "@mui/material/ListSubheader";
import IconButton from "@mui/material/IconButton";
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
// upload button
import { styled } from "@mui/material/styles";
import Button from "@mui/material/Button";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import axios from "axios";
import * as gh from "../githublibrary.js";
const VisuallyHiddenInput = styled("input")({
clip: "rect(0 0 0 0)",
clipPath: "inset(50%)",
height: 1,
overflow: "hidden",
position: "absolute",
bottom: 0,
left: 0,
whiteSpace: "nowrap",
width: 1,
});
const ReactImageList = () => {
const [itemData, setItemData] = useState([]);
const fileLoad = async () => {
let result = await gh.fileRead("images");
let fileList = result.data.map((item) => item.path);
let temp = [];
let count = 1;
for (let path of fileList) {
let obj = {
img: `https://github.com/bloodstrawberry/auto-test/raw/main/${path}`,
title: `image_${count++}`,
author: "bloodstrawberry",
path // for delete
};
temp.push(obj);
}
setItemData(temp);
};
useEffect(() => {
fileLoad();
}, []);
const githubUpload = async (image) => {
const reader = new FileReader();
reader.onloadend = async () => {
const base64encoded = reader.result.split(",")[1];
const apiURL = `https://api.github.com/repos/bloodstrawberry/auto-test/contents/images/${image.name}`;
const accessToken = process.env.REACT_APP_MY_TOKEN;
try {
const response = await axios.put(
apiURL,
{
message: "Add image",
content: base64encoded,
branch: "main",
},
{
headers: {
Authorization: `token ${accessToken}`,
"Content-Type": "application/json",
},
}
);
console.log("Image uploaded successfully:", response.data.content.name);
} catch (error) {
console.error("Error uploading image:", error);
}
};
reader.readAsDataURL(image);
};
const handleFileUpload = (e) => {
const selectedImages = e.target.files;
const uploadImageWithDelay = async () => {
githubUpload(selectedImages[0]);
for (let i = 1; i < selectedImages.length; i++) {
await new Promise((resolve) => {
setTimeout(() => {
githubUpload(selectedImages[i]);
resolve();
}, 5000); // 5초 delay
});
}
};
uploadImageWithDelay();
};
const deleteImage = async (path) => {
let newItemData = itemData.filter((item) => item.path !== path);
setItemData(newItemData);
let response = await gh.fileDelete(path);
console.log(response);
}
return (
<Box sx={{ m: 3 }}>
<Button
component="label"
variant="contained"
startIcon={<CloudUploadIcon />}
onChange={handleFileUpload}
>
Upload file
<VisuallyHiddenInput type="file" accept="image/*" multiple />
</Button>
<ImageList sx={{ width: 248 * 3 }} cols={3}>
<ImageListItem key="Subheader" cols={3}>
<ListSubheader component="div">GitHub Images Directory</ListSubheader>
</ImageListItem>
{itemData.map((item) => (
<ImageListItem key={item.img}>
<img
srcSet={`${item.img}?w=248&fit=crop&auto=format&dpr=2 2x`}
src={`${item.img}?w=248&fit=crop&auto=format`}
alt={item.title}
loading="lazy"
/>
<ImageListItemBar
title={item.title}
subtitle={item.author}
actionIcon={
<IconButton
sx={{ color: "rgba(255, 255, 255, 0.54)" }}
aria-label={`info about ${item.title}`}
onClick={() => deleteImage(item.path)}
>
<DeleteOutlineIcon />
</IconButton>
}
/>
</ImageListItem>
))}
</ImageList>
</Box>
);
};
export default ReactImageList;
반응형
'개발 > React' 카테고리의 다른 글
리액트 - 캡처한 이미지 여러 개 업로드하기 (Upload Captured Images to GitHub) (0) | 2024.01.17 |
---|---|
리액트 - 캡처한 이미지를 깃허브에 업로드하기 (Upload Captured Image to GitHub) (0) | 2024.01.17 |
리액트 - 깃허브 API로 이미지 업로드하기 (Upload Images with GitHub RESTful API) (0) | 2024.01.17 |
리액트 Material - 깃허브 리포지토리 이미지 불러오기 (Load GitHub Repository Images with Image List) (0) | 2024.01.17 |
리액트 - 이미지 캡처해서 웹에 붙여넣기 (Capture and Paste Image) (0) | 2024.01.15 |
댓글