mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-06-05 10:11:12 +02:00
fix(status): show Open by default instead of infinite loading spinner (#244)
StatusIndicator was stuck showing a loading spinner indefinitely when no status events existed, because the useTimeline observable never completes for live Nostr subscriptions. Default to showing "Open" immediately and update reactively when status events arrive. https://claude.ai/code/session_01UAjKegpi8uWyLdjgRpNeEJ Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,4 @@
|
|||||||
import {
|
import { CircleDot, CheckCircle2, XCircle, FileEdit } from "lucide-react";
|
||||||
CircleDot,
|
|
||||||
CheckCircle2,
|
|
||||||
XCircle,
|
|
||||||
FileEdit,
|
|
||||||
Loader2,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { getStatusType } from "@/lib/nip34-helpers";
|
import { getStatusType } from "@/lib/nip34-helpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,8 +60,6 @@ function getStatusBadgeClasses(kind: number): string {
|
|||||||
export interface StatusIndicatorProps {
|
export interface StatusIndicatorProps {
|
||||||
/** The status event kind (1630-1633) or undefined for default "open" */
|
/** The status event kind (1630-1633) or undefined for default "open" */
|
||||||
statusKind?: number;
|
statusKind?: number;
|
||||||
/** Whether status is loading */
|
|
||||||
loading?: boolean;
|
|
||||||
/** Event type for appropriate labeling (affects "resolved" vs "merged") */
|
/** Event type for appropriate labeling (affects "resolved" vs "merged") */
|
||||||
eventType?: "issue" | "patch" | "pr";
|
eventType?: "issue" | "patch" | "pr";
|
||||||
/** Display variant */
|
/** Display variant */
|
||||||
@@ -82,23 +74,11 @@ export interface StatusIndicatorProps {
|
|||||||
*/
|
*/
|
||||||
export function StatusIndicator({
|
export function StatusIndicator({
|
||||||
statusKind,
|
statusKind,
|
||||||
loading = false,
|
|
||||||
eventType = "issue",
|
eventType = "issue",
|
||||||
variant = "inline",
|
variant = "inline",
|
||||||
className = "",
|
className = "",
|
||||||
}: StatusIndicatorProps) {
|
}: StatusIndicatorProps) {
|
||||||
if (loading) {
|
// Default to "open" if no status (shown immediately, updates reactively when status events arrive)
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className={`inline-flex items-center gap-1.5 text-sm text-muted-foreground ${className}`}
|
|
||||||
>
|
|
||||||
<Loader2 className="size-3.5 animate-spin" />
|
|
||||||
<span>Loading...</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to "open" if no status
|
|
||||||
const effectiveKind = statusKind ?? 1630;
|
const effectiveKind = statusKind ?? 1630;
|
||||||
|
|
||||||
// For patches/PRs, kind 1631 means "merged" not "resolved"
|
// For patches/PRs, kind 1631 means "merged" not "resolved"
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export function IssueDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
[event.id],
|
[event.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { events: statusEvents, loading: statusLoading } = useTimeline(
|
const { events: statusEvents } = useTimeline(
|
||||||
`issue-status-${event.id}`,
|
`issue-status-${event.id}`,
|
||||||
statusFilter,
|
statusFilter,
|
||||||
statusRelays,
|
statusRelays,
|
||||||
@@ -120,7 +120,6 @@ export function IssueDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
{/* Status Badge (below title) */}
|
{/* Status Badge (below title) */}
|
||||||
<StatusIndicator
|
<StatusIndicator
|
||||||
statusKind={currentStatus?.kind}
|
statusKind={currentStatus?.kind}
|
||||||
loading={statusLoading}
|
|
||||||
eventType="issue"
|
eventType="issue"
|
||||||
variant="badge"
|
variant="badge"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export function PatchDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
[event.id],
|
[event.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { events: statusEvents, loading: statusLoading } = useTimeline(
|
const { events: statusEvents } = useTimeline(
|
||||||
`patch-status-${event.id}`,
|
`patch-status-${event.id}`,
|
||||||
statusFilter,
|
statusFilter,
|
||||||
statusRelays,
|
statusRelays,
|
||||||
@@ -124,7 +124,6 @@ export function PatchDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<StatusIndicator
|
<StatusIndicator
|
||||||
statusKind={currentStatus?.kind}
|
statusKind={currentStatus?.kind}
|
||||||
loading={statusLoading}
|
|
||||||
eventType="patch"
|
eventType="patch"
|
||||||
variant="badge"
|
variant="badge"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function PullRequestDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
[event.id],
|
[event.id],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { events: statusEvents, loading: statusLoading } = useTimeline(
|
const { events: statusEvents } = useTimeline(
|
||||||
`pr-status-${event.id}`,
|
`pr-status-${event.id}`,
|
||||||
statusFilter,
|
statusFilter,
|
||||||
statusRelays,
|
statusRelays,
|
||||||
@@ -124,7 +124,6 @@ export function PullRequestDetailRenderer({ event }: { event: NostrEvent }) {
|
|||||||
{/* Status Badge (below title) */}
|
{/* Status Badge (below title) */}
|
||||||
<StatusIndicator
|
<StatusIndicator
|
||||||
statusKind={currentStatus?.kind}
|
statusKind={currentStatus?.kind}
|
||||||
loading={statusLoading}
|
|
||||||
eventType="pr"
|
eventType="pr"
|
||||||
variant="badge"
|
variant="badge"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user