uploade
This commit is contained in:
@@ -2,7 +2,6 @@ import React, { useMemo, useRef, useEffect } from 'react';
|
||||
import { Observation, Summary, UserPrompt, FeedItem } from '../types';
|
||||
import { ObservationCard } from './ObservationCard';
|
||||
import { SummaryCard } from './SummaryCard';
|
||||
import { SummarySkeleton } from './SummarySkeleton';
|
||||
import { PromptCard } from './PromptCard';
|
||||
import { UI } from '../constants/ui';
|
||||
|
||||
@@ -10,13 +9,12 @@ interface FeedProps {
|
||||
observations: Observation[];
|
||||
summaries: Summary[];
|
||||
prompts: UserPrompt[];
|
||||
processingSessions: Set<string>;
|
||||
onLoadMore: () => void;
|
||||
isLoading: boolean;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
export function Feed({ observations, summaries, prompts, processingSessions, onLoadMore, isLoading, hasMore }: FeedProps) {
|
||||
export function Feed({ observations, summaries, prompts, onLoadMore, isLoading, hasMore }: FeedProps) {
|
||||
const loadMoreRef = useRef<HTMLDivElement>(null);
|
||||
const onLoadMoreRef = useRef(onLoadMore);
|
||||
|
||||
@@ -51,45 +49,14 @@ export function Feed({ observations, summaries, prompts, processingSessions, onL
|
||||
}, [hasMore, isLoading]);
|
||||
|
||||
const items = useMemo<FeedItem[]>(() => {
|
||||
// Create a set of session IDs that already have summaries
|
||||
const sessionsWithSummaries = new Set(summaries.map(s => s.session_id));
|
||||
|
||||
// Find the most recent prompt for each processing session
|
||||
const sessionPrompts = new Map<string, UserPrompt>();
|
||||
prompts.forEach(p => {
|
||||
const existing = sessionPrompts.get(p.claude_session_id);
|
||||
if (!existing || p.created_at_epoch > existing.created_at_epoch) {
|
||||
sessionPrompts.set(p.claude_session_id, p);
|
||||
}
|
||||
});
|
||||
|
||||
// Create skeleton items for sessions being processed that don't have summaries yet
|
||||
const skeletons: FeedItem[] = [];
|
||||
processingSessions.forEach(sessionId => {
|
||||
if (!sessionsWithSummaries.has(sessionId)) {
|
||||
const prompt = sessionPrompts.get(sessionId);
|
||||
skeletons.push({
|
||||
itemType: 'skeleton',
|
||||
id: sessionId, // Don't add prefix - key construction adds itemType already
|
||||
session_id: sessionId,
|
||||
project: prompt?.project,
|
||||
// Always use current time so skeletons appear at top of feed
|
||||
created_at_epoch: Date.now()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Data is already filtered by App.tsx - no need to filter again
|
||||
const combined = [
|
||||
...observations.map(o => ({ ...o, itemType: 'observation' as const })),
|
||||
...summaries.map(s => ({ ...s, itemType: 'summary' as const })),
|
||||
...prompts.map(p => ({ ...p, itemType: 'prompt' as const })),
|
||||
...skeletons
|
||||
...prompts.map(p => ({ ...p, itemType: 'prompt' as const }))
|
||||
];
|
||||
|
||||
return combined
|
||||
.sort((a, b) => b.created_at_epoch - a.created_at_epoch);
|
||||
}, [observations, summaries, prompts, processingSessions]);
|
||||
return combined.sort((a, b) => b.created_at_epoch - a.created_at_epoch);
|
||||
}, [observations, summaries, prompts]);
|
||||
|
||||
return (
|
||||
<div className="feed">
|
||||
@@ -100,8 +67,6 @@ export function Feed({ observations, summaries, prompts, processingSessions, onL
|
||||
return <ObservationCard key={key} observation={item} />;
|
||||
} else if (item.itemType === 'summary') {
|
||||
return <SummaryCard key={key} summary={item} />;
|
||||
} else if (item.itemType === 'skeleton') {
|
||||
return <SummarySkeleton key={key} sessionId={item.session_id} project={item.project} />;
|
||||
} else {
|
||||
return <PromptCard key={key} prompt={item} />;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ export function Header({
|
||||
</h1>
|
||||
<div className="status">
|
||||
<a
|
||||
href="https://github.com/thedotmack/claude-mem/"
|
||||
href="https://docs.claude-mem.ai"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="GitHub"
|
||||
title="Documentation"
|
||||
style={{
|
||||
display: 'block',
|
||||
padding: '8px 4px 8px 8px',
|
||||
@@ -44,7 +44,27 @@ export function Header({
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#ffffff'}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
|
||||
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/thedotmack/claude-mem/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="GitHub"
|
||||
style={{
|
||||
display: 'block',
|
||||
padding: '8px 4px',
|
||||
color: '#a0a0a0',
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
@@ -63,7 +83,7 @@ export function Header({
|
||||
transition: 'color 0.2s',
|
||||
lineHeight: 0
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#ffffff'}
|
||||
onMouseEnter={(e) => e.currentTarget.style.color = '#606060'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.color = '#a0a0a0'}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
interface SummarySkeletonProps {
|
||||
sessionId: string;
|
||||
project?: string;
|
||||
}
|
||||
|
||||
export function SummarySkeleton({ sessionId, project }: SummarySkeletonProps) {
|
||||
return (
|
||||
<div className="card summary-card summary-skeleton">
|
||||
<div className="card-header">
|
||||
<span className="card-type">SUMMARY</span>
|
||||
{project && <span>{project}</span>}
|
||||
<div className="processing-indicator">
|
||||
<div className="spinner"></div>
|
||||
<span>Generating...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="skeleton-line skeleton-title"></div>
|
||||
<div className="skeleton-line skeleton-subtitle"></div>
|
||||
<div className="skeleton-line skeleton-subtitle short"></div>
|
||||
<div className="card-meta">Session: {sessionId}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user