feat(ui): comment insert / close

This commit is contained in:
null 2026-05-21 23:45:59 -05:00
parent 9300f4b670
commit a985af3f4a
2 changed files with 33 additions and 3 deletions

View File

@ -2,7 +2,7 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { ExternalLink, Loader2, MessageSquarePlus, Pencil } from "lucide-react"; import { ExternalLink, Loader2, MessageSquarePlus, Pencil, XCircle } from "lucide-react";
import { import {
Dialog, Dialog,
@ -20,8 +20,9 @@ import {
type ForgejoIssue, type ForgejoIssue,
type ForgejoIssueDetail, type ForgejoIssueDetail,
} from "@/lib/api-forgejo"; } from "@/lib/api-forgejo";
import { PostForgejoCommentDialog } from "@/components/git/PostForgejoCommentDialog"; import { CloseForgejoIssueDialog } from "@/components/git/CloseForgejoIssueDialog";
import { EditForgejoIssueDialog } from "@/components/git/EditForgejoIssueDialog"; import { EditForgejoIssueDialog } from "@/components/git/EditForgejoIssueDialog";
import { PostForgejoCommentDialog } from "@/components/git/PostForgejoCommentDialog";
type ForgejoIssueDetailDialogProps = { type ForgejoIssueDetailDialogProps = {
issue: ForgejoIssue | null; issue: ForgejoIssue | null;
@ -29,6 +30,7 @@ type ForgejoIssueDetailDialogProps = {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
onRefresh?: () => void; onRefresh?: () => void;
canClose?: boolean;
}; };
const formatDateTime = (value: string | null | undefined): string => { const formatDateTime = (value: string | null | undefined): string => {
@ -58,6 +60,7 @@ export function ForgejoIssueDetailDialog({
open, open,
onOpenChange, onOpenChange,
onRefresh, onRefresh,
canClose = false,
}: ForgejoIssueDetailDialogProps) { }: ForgejoIssueDetailDialogProps) {
const [detail, setDetail] = useState<ForgejoIssueDetail | null>(null); const [detail, setDetail] = useState<ForgejoIssueDetail | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@ -66,6 +69,7 @@ export function ForgejoIssueDetailDialog({
const [isCommentDialogOpen, setIsCommentDialogOpen] = useState(false); const [isCommentDialogOpen, setIsCommentDialogOpen] = useState(false);
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
const [isCloseIssueDialogOpen, setIsCloseIssueDialogOpen] = useState(false);
const loadDetail = (id: string) => { const loadDetail = (id: string) => {
let cancelled = false; let cancelled = false;
@ -113,6 +117,12 @@ export function ForgejoIssueDetailDialog({
const body = detail?.body ?? issue.body ?? issue.body_preview ?? ""; const body = detail?.body ?? issue.body ?? issue.body_preview ?? "";
const stateVariant = active.state === "open" ? "success" : "default"; const stateVariant = active.state === "open" ? "success" : "default";
const handleCloseIssueSuccess = () => {
if (detail) setDetail({ ...detail, state: "closed" });
if (issue) loadDetail(issue.id);
onRefresh?.();
};
const handleCommentSuccess = () => { const handleCommentSuccess = () => {
if (issue) loadDetail(issue.id); if (issue) loadDetail(issue.id);
onRefresh?.(); onRefresh?.();
@ -179,6 +189,17 @@ export function ForgejoIssueDetailDialog({
<MessageSquarePlus className="h-3.5 w-3.5" /> <MessageSquarePlus className="h-3.5 w-3.5" />
Comment Comment
</Button> </Button>
{canClose && active.state === "open" ? (
<Button
variant="outline"
size="sm"
className="h-9 gap-2 rounded-xl border-[color:rgba(248,113,113,0.45)] px-3 text-xs font-semibold text-[color:var(--danger)] hover:bg-[color:rgba(248,113,113,0.08)]"
onClick={() => setIsCloseIssueDialogOpen(true)}
>
<XCircle className="h-3.5 w-3.5" />
Close Issue
</Button>
) : null}
<a <a
href={active.html_url} href={active.html_url}
target="_blank" target="_blank"
@ -357,12 +378,20 @@ export function ForgejoIssueDetailDialog({
<div className="flex justify-end"> <div className="flex justify-end">
<Button variant="outline" onClick={() => onOpenChange(false)}> <Button variant="outline" onClick={() => onOpenChange(false)}>
Close Dismiss
</Button> </Button>
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
<CloseForgejoIssueDialog
issue={issue}
repositoryName={repositoryName}
open={isCloseIssueDialogOpen}
onOpenChange={setIsCloseIssueDialogOpen}
onCloseSuccess={handleCloseIssueSuccess}
/>
<PostForgejoCommentDialog <PostForgejoCommentDialog
issue={issue} issue={issue}
repositoryName={repositoryName} repositoryName={repositoryName}

View File

@ -421,6 +421,7 @@ export function ForgejoIssuesTable({
} }
}} }}
onRefresh={onRefresh} onRefresh={onRefresh}
canClose={canClose}
/> />
<EditForgejoIssueDialog <EditForgejoIssueDialog
issue={issueToEdit} issue={issueToEdit}