forked from Gitlink/forgeplus-react
回归代码评审issue
This commit is contained in:
parent
732afc85f5
commit
08d59f4612
|
|
@ -31,7 +31,7 @@
|
|||
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
|
||||
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/moment/2.29.4/moment.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.11/bundle/alex.all.global.js"></script>
|
||||
<script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.12-0/bundle/alex.all.global.js"></script>
|
||||
<%= htmlWebpackPlugin.tags.bodyTags %>
|
||||
</body>
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export function timeAgo(backDate) {
|
|||
var days = Math.floor(time / (1000 * 60 * 60 * 24));
|
||||
var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
|
||||
var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
|
||||
// var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
|
||||
if (time <= 0) {
|
||||
return "刚刚";
|
||||
}
|
||||
|
|
@ -129,10 +129,10 @@ export function timeAgo(backDate) {
|
|||
return hours + "小时前";
|
||||
}
|
||||
if (minutes) {
|
||||
return minutes + "分前";
|
||||
}
|
||||
if (seconds) {
|
||||
return seconds + "秒前";
|
||||
return minutes + "分钟前";
|
||||
}
|
||||
// if (seconds) {
|
||||
// return seconds + "秒前";
|
||||
// }
|
||||
return "刚刚";
|
||||
}
|
||||
|
|
@ -22,9 +22,9 @@ import {
|
|||
Popconfirm,
|
||||
Checkbox,
|
||||
} from "antd";
|
||||
// @ts-ignore
|
||||
import { Link } from "react-router-dom";
|
||||
import { usePersistFn } from "ahooks";
|
||||
import { getImageUrl } from "educoder";
|
||||
import { getImageUrl, timeAgo } from "educoder";
|
||||
import { camelcaseToUnderscore } from '../utils/camelcase-convert';
|
||||
import "./style.module.less";
|
||||
import { useAcr, useNote, useGlobal } from "../../model";
|
||||
|
|
@ -42,21 +42,21 @@ const noteType = {
|
|||
export const Commenting = (props) => {
|
||||
const { user } = useGlobal();
|
||||
const { addComment } = useNote();
|
||||
const { toVersion,stDiff } = useAcr();
|
||||
const { toVersion, stDiff } = useAcr();
|
||||
console.log('Commenting--props');
|
||||
console.log(props);
|
||||
// console.log(stDiff);
|
||||
const submit = usePersistFn(async (note, type) => {
|
||||
try {
|
||||
console.log(note,type);
|
||||
console.log(note, type);
|
||||
await addComment({
|
||||
note,
|
||||
diffId: toVersion.id,
|
||||
line_code: props.lineCode,
|
||||
discussionId: props.discussionId,
|
||||
parent_id: props.id,
|
||||
path: props.path,
|
||||
type,
|
||||
diff:stDiff,
|
||||
type: type || 'comment',
|
||||
diff:props.id?null: stDiff,
|
||||
});
|
||||
props.onClose && props.onClose();
|
||||
} catch (e) {
|
||||
|
|
@ -90,136 +90,186 @@ export const Commenting = (props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="arc-container">
|
||||
<div
|
||||
className={`arc-commenting-container ${props.noPadding ? "no-padding" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="avatar">
|
||||
<Tooltip title={user.name}>
|
||||
<Avatar src={ user && user.image_url
|
||||
? getImageUrl(`/${user.image_url}`)
|
||||
: "images/avatars/User/b"} size={24} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
placeholder="请输入描述信息"
|
||||
value={note}
|
||||
onChange={(e) => setNote(e.target.value)}
|
||||
style={{ height: 150 }}
|
||||
/>
|
||||
<div className="action">
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onSubmit}
|
||||
disabled={!note.trim()}
|
||||
style={{ marginRight: 8 }}
|
||||
// <div className="arc-container">
|
||||
<div
|
||||
className={`arc-commenting-container ${props.noPadding ? "no-padding" : ""}`}>
|
||||
<div className="avatar">
|
||||
<Tooltip title={user.name}>
|
||||
<Avatar src={user && user.image_url
|
||||
? getImageUrl(`/${user.image_url}`)
|
||||
: "images/avatars/User/b"} size={24} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
placeholder="请输入评论信息"
|
||||
value={note}
|
||||
onChange={(e) => setNote(e.target.value)}
|
||||
style={{ height: 150 }}
|
||||
/>
|
||||
<div className="action">
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onSubmit}
|
||||
disabled={!note.trim()}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
评论
|
||||
</Button>
|
||||
{note.trim() ? (
|
||||
<Popconfirm
|
||||
title="你确定要取消?"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={props.onClose}
|
||||
>
|
||||
评论
|
||||
</Button>
|
||||
{note.trim() ? (
|
||||
<Popconfirm
|
||||
title="你确定要取消?"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={props.onClose}
|
||||
>
|
||||
<Button>取消</Button>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Button onClick={props.onClose}>取消</Button>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{replyNote && (
|
||||
<div className="reply-note">Reply to {replyNote.author.name}</div>
|
||||
)}
|
||||
</div>
|
||||
<Button>取消</Button>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Button onClick={props.onClose}>取消</Button>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{replyNote && (
|
||||
<div className="reply-note">Reply to {replyNote.author.name}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
// </div>
|
||||
);
|
||||
};
|
||||
|
||||
const ReplyItem = memo(({note, isChild}) => {
|
||||
const { user } = useGlobal();
|
||||
const { deleteComment } = useNote();
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
return <div className={`reply-item ${isChild?'reply-item-child':''}`}>
|
||||
<div className="reply-item-head">
|
||||
<Link
|
||||
to={`/${note.user && note.user.login}`}
|
||||
className="show-user-link"
|
||||
>
|
||||
<Avatar src={note.user && note.user.imageUrl
|
||||
? getImageUrl(`/${note.user.imageUrl}`)
|
||||
: "images/avatars/User/b"} size={24} />
|
||||
</Link>
|
||||
<Link
|
||||
to={`/${note.user && note.user.login}`}
|
||||
className="show-user-link color-black ml10 fwb"
|
||||
>
|
||||
{note.user && note.user.username}
|
||||
</Link> 于 <span className="show-user-link color-black">{timeAgo(note.createdAt)}</span> 发表评论:
|
||||
<span className="btn-right">
|
||||
{user &&
|
||||
(user.admin ||
|
||||
user.login === note.user.login) ? (
|
||||
<Popconfirm
|
||||
placement="bottom"
|
||||
title={"确定要删除当前评论吗?"}
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
onConfirm={() => deleteComment(note.id)}
|
||||
>
|
||||
<Button type="link">
|
||||
<i className="iconfont icon-shanchu3 font-15 color-grey-6 mr5 ver-middle"></i>
|
||||
<span className="font-12 color-grey-6">删除</span>
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{!isChild ? <Button
|
||||
type="link"
|
||||
className="ml-10"
|
||||
onClick={() => setVisible(true)}
|
||||
>
|
||||
<i className="iconfont icon-huifu1 font-15 color-grey-6 mr5 ver-middle"></i>
|
||||
<span className="font-12 color-grey-6">回复</span>
|
||||
</Button> : ''}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="reply-item-content">{note.note}</div>
|
||||
{visible && <Commenting style={{paddingLeft:'20px'}} onClose={() => { setVisible(false) }} {...note} />}
|
||||
</div>
|
||||
})
|
||||
|
||||
export const DiscussionItem = memo((props) => {
|
||||
const { noteId } = props;
|
||||
const { commentPack } = useNote();
|
||||
const { commentPack, deleteComment } = useNote();
|
||||
|
||||
const [commenting, setCommenting] = useState(false);
|
||||
const [commentReply, setCommentReply] = useState();
|
||||
// const [commenting, setCommenting] = useState(false);
|
||||
// const [commentReply, setCommentReply] = useState();
|
||||
|
||||
const replyIdSet = commentPack.noteIdToReplyIdSet.get(noteId);
|
||||
const replyIds = replyIdSet
|
||||
? Array.from(replyIdSet).sort((a, b) => a - b)
|
||||
: null;
|
||||
|
||||
const pending = (function () {
|
||||
if (!commentPack.hasPendingReview) {
|
||||
return false;
|
||||
}
|
||||
const reviewId = commentPack.noteIdToReviewId.get(noteId);
|
||||
if (!reviewId) return false;
|
||||
const review = reviewId ? commentPack.reviewIdToReview.get(reviewId) : null;
|
||||
if (!review) return false;
|
||||
return review.pending;
|
||||
})();
|
||||
const hasPendingNote = (function () {
|
||||
if (pending) return true;
|
||||
if (replyIds) {
|
||||
for (const replyId of replyIds) {
|
||||
const reviewId = commentPack.noteIdToReviewId.get(replyId);
|
||||
if (reviewId && commentPack.reviewIdToReview.get(reviewId) && commentPack.reviewIdToReview.get(reviewId).pending) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
// const pending = (function () {
|
||||
// if (!commentPack.hasPendingReview) {
|
||||
// return false;
|
||||
// }
|
||||
// const reviewId = commentPack.noteIdToReviewId.get(noteId);
|
||||
// if (!reviewId) return false;
|
||||
// const review = reviewId ? commentPack.reviewIdToReview.get(reviewId) : null;
|
||||
// if (!review) return false;
|
||||
// return review.pending;
|
||||
// })();
|
||||
// const hasPendingNote = (function () {
|
||||
// if (pending) return true;
|
||||
// if (replyIds) {
|
||||
// for (const replyId of replyIds) {
|
||||
// const reviewId = commentPack.noteIdToReviewId.get(replyId);
|
||||
// if (reviewId && commentPack.reviewIdToReview.get(reviewId) && commentPack.reviewIdToReview.get(reviewId).pending) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// })();
|
||||
|
||||
const handleReply = (replyNote) => {
|
||||
if (replyNote) {
|
||||
setCommentReply(replyNote);
|
||||
}
|
||||
setCommenting(true);
|
||||
};
|
||||
// const handleReply = (replyNote) => {
|
||||
// if (replyNote) {
|
||||
// setCommentReply(replyNote);
|
||||
// }
|
||||
// setCommenting(true);
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!commenting) {
|
||||
// setCommentReply(undefined);
|
||||
// }
|
||||
// }, [commenting]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!commenting) {
|
||||
setCommentReply(undefined);
|
||||
}
|
||||
}, [commenting]);
|
||||
|
||||
const note = commentPack.noteIdToNote.get(noteId);
|
||||
if (!note) return null;
|
||||
|
||||
console.log('note');
|
||||
console.log(note);
|
||||
return (
|
||||
<div className="arc-container">
|
||||
<div>
|
||||
{/* {note.type === noteType.problem && (
|
||||
{/* <div>
|
||||
{note.type === noteType.problem && (
|
||||
<Fragment>
|
||||
{note.state === "resolved" && !pending && "已解决"}
|
||||
{note.state === "opened" && !pending && "待解决"}
|
||||
{pending && "需要回应"}
|
||||
</Fragment>
|
||||
)} */}
|
||||
</div>
|
||||
<div style={{ paddingLeft: 16 }}>
|
||||
<div>{note.author.name} 发表评论:</div>
|
||||
<div>{note.note}</div>
|
||||
</div>
|
||||
)}
|
||||
</div> */}
|
||||
<ReplyItem note={note}/>
|
||||
|
||||
{replyIds && (
|
||||
<div style={{ paddingLeft: 32 }}>
|
||||
{replyIds.map((replyId) => {
|
||||
<div style={{ paddingLeft: 50 }}>
|
||||
{replyIds.reverse().map((replyId) => {
|
||||
const note = commentPack.noteIdToNote.get(replyId);
|
||||
if (!note) return null;
|
||||
return (
|
||||
<div key={replyId}>
|
||||
<div>{note.author.name} 发表评论</div>
|
||||
<div>{note.note}</div>
|
||||
</div>
|
||||
);
|
||||
return <ReplyItem note={note} key={replyId} isChild={true} />
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -248,7 +298,6 @@ export const Menubar = memo((props) => {
|
|||
};
|
||||
}, [isFullscreen]);
|
||||
|
||||
const { project, pr } = useGlobal();
|
||||
const { versions, fromVersion, toVersion, updateQuery } = useAcr();
|
||||
|
||||
const idToVerbose = new Map();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,32 @@
|
|||
|
||||
.arc-container {
|
||||
border: solid 1px #eee;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
// border: solid 1px #eee;
|
||||
// border-left: none;
|
||||
// border-right: none;
|
||||
|
||||
.reply-item{
|
||||
padding:16px 16px 20px;
|
||||
|
||||
&.reply-item-child{
|
||||
margin-top:-10px;
|
||||
padding:5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.reply-item-head{
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
}
|
||||
.btn-right{
|
||||
float: right;
|
||||
}
|
||||
.reply-item-content{
|
||||
padding-left:35px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.show-user-link{
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.arc-menubar {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export const prService = {
|
|||
item.author.username=item.user.name;
|
||||
item.type='Common';
|
||||
item.stDiff=item.diff;
|
||||
item.discussionId=item.parentId
|
||||
// item.lineType='old';
|
||||
}
|
||||
return journals;
|
||||
|
|
@ -172,6 +173,11 @@ export const prService = {
|
|||
return commentData;
|
||||
},
|
||||
|
||||
async deleteComment(projectsId, owner, mergeId,id){
|
||||
const res = await axios.delete(`/v1/${owner}/${projectsId}/pulls/${mergeId}/journals/${id}.json`);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async createReview(projectsId, owner, mergeId, data) {
|
||||
const res = await axios.post(`/v1/${owner}/${projectsId}/pulls/${mergeId}/reviews.json`, data);
|
||||
console.log('createReview--data');
|
||||
|
|
|
|||
|
|
@ -176,8 +176,7 @@ const useCommentPack = (projectId, prId) => {
|
|||
}
|
||||
fetchingRef.current = true;
|
||||
// 获取评论内容
|
||||
// const pack = await prService.getCommentPack(projectsId, owner, mergeId);
|
||||
const commentPack = await prService.getCommentPack(projectsId, owner, mergeId,{path:filePath});
|
||||
const commentPack = await prService.getCommentPack(projectsId, owner, mergeId,{path:filePath,is_full:true});
|
||||
const reviews = await prService.getReviews(projectsId, owner, mergeId);
|
||||
// debugger
|
||||
for (const review of reviews) {
|
||||
|
|
@ -250,6 +249,11 @@ const useCommentPack = (projectId, prId) => {
|
|||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function manualRemoveNote(id) {
|
||||
noteIdToNote.delete(id);
|
||||
setUpdateFlag({});
|
||||
}
|
||||
|
||||
function manualUpdateNote(note) {
|
||||
const reviewId = noteIdToReviewId.get(note.id);
|
||||
const review = reviewId ? reviewIdToReview.get(reviewId) : null;
|
||||
|
|
@ -310,6 +314,7 @@ const useCommentPack = (projectId, prId) => {
|
|||
doRefresh,
|
||||
manualUpdateReview,
|
||||
manualAddNote,
|
||||
manualRemoveNote,
|
||||
manualUpdateNote,
|
||||
pendingReviewRef,
|
||||
getRelatedFilePathByNoteId,
|
||||
|
|
@ -346,6 +351,14 @@ const [NoteProvider, useNote] = createContainer(() => {
|
|||
commentPack.manualAddNote(note, commentPack.pendingReviewRef.current);
|
||||
}
|
||||
|
||||
async function deleteComment(id){
|
||||
const res = await prService.deleteComment(projectsId, owner, mergeId,id);
|
||||
if(res.status==0){
|
||||
commentPack.manualRemoveNote(id);
|
||||
}
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
async function commitReview(body) {
|
||||
if (!commentPack.hasPendingReview) {
|
||||
let reviewData = {
|
||||
|
|
@ -364,6 +377,7 @@ const [NoteProvider, useNote] = createContainer(() => {
|
|||
commentPack,
|
||||
...commentPack,
|
||||
addComment,
|
||||
deleteComment,
|
||||
commitReview,
|
||||
prId,
|
||||
activateRef,
|
||||
|
|
@ -570,9 +584,9 @@ const [AcrProvider, useAcr] = createContainer(() => {
|
|||
}
|
||||
);
|
||||
|
||||
// useEffect(() => {
|
||||
// commentPack.doRefresh();
|
||||
// }, []);
|
||||
useEffect(() => {
|
||||
commentPack.doRefresh();
|
||||
}, []);
|
||||
|
||||
async function getDiffById(diffId) {
|
||||
let thisStDiff= await prService.getDiffById(projectsId, owner, mergeId, toVersion.id,
|
||||
|
|
@ -641,7 +655,7 @@ const [AcrProvider, useAcr] = createContainer(() => {
|
|||
export const Provider = (props) => {
|
||||
const match = props.match;
|
||||
let project = {};
|
||||
let user = mockService['/api/v3/user'];
|
||||
// let user = mockService['/api/v3/user'];
|
||||
if (props.projectDetail) {
|
||||
let details = props.projectDetail;
|
||||
project = {
|
||||
|
|
@ -650,12 +664,12 @@ export const Provider = (props) => {
|
|||
pathWithNamespace: details.full_name,
|
||||
}
|
||||
}
|
||||
let user={};
|
||||
if (props.current_user) {
|
||||
let current_user = props.current_user;
|
||||
user = { ...user, ...current_user, avatar_url: current_user.image_url, name: current_user.username, };
|
||||
user = { ...current_user, avatar_url: current_user.image_url, name: current_user.username, };
|
||||
}
|
||||
console.log(user);
|
||||
console.log('user');
|
||||
|
||||
return (
|
||||
<ContextProps.Provider value={{
|
||||
project, user, params: match.params
|
||||
|
|
|
|||
Loading…
Reference in New Issue