feat: triage streams with open, close (#121)
* refactor: use interfaces for function params * cleanup message retention code * support open / closed streams - Tabs for viewing separately - Context menu to close / open streams - Update stream particle status field * ui tweak * show stream state in stream-view * ui tweaks * cleanup message retention from orion api
This commit was merged in pull request #121.
This commit is contained in:
@@ -9,17 +9,13 @@ import {
|
||||
FileText,
|
||||
CircleCheck,
|
||||
StickyNote,
|
||||
Timer,
|
||||
Headphones,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useLiveLatestChild } from "@/hooks/use-particle";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import {
|
||||
particlePath,
|
||||
type ParticlePath,
|
||||
} from "@/lib/particle-path";
|
||||
import { particlePath } from "@/lib/particle-path";
|
||||
import { getInitials } from "@/lib/utils";
|
||||
import { RelativeTimestamp } from "@/components/relative-timestamp";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
@@ -27,10 +23,10 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import { Small } from "@/components/ui/typography";
|
||||
import type { Particle, StreamProperties } from "@/api/types";
|
||||
import type { StreamParticle } from "@/hooks/use-stream-particles";
|
||||
import { useNetwork } from "@/hooks/use-networks";
|
||||
import { useExpiringSoon } from "@/hooks/use-expiring-soon";
|
||||
import { useStreamParticles } from "@/hooks/use-stream-particles";
|
||||
import { useStreamAutoplay } from "@/hooks/use-stream-autoplay";
|
||||
import { StreamContextMenu } from "@/features/particles/stream-context-menu";
|
||||
|
||||
function getParticleTypeIcon(particle: Particle): LucideIcon {
|
||||
switch (particle.type) {
|
||||
@@ -97,11 +93,6 @@ function StreamRow({
|
||||
|
||||
useStreamAutoplay(latestChild, particle, networkId, network ?? undefined);
|
||||
|
||||
const expiringSoon = useExpiringSoon(
|
||||
particle.last_child_created_at,
|
||||
network?.message_retention_hours ?? 24,
|
||||
);
|
||||
|
||||
const hasActiveHuddle =
|
||||
particle.huddle_active_participants && particle.huddle_active_participants.length > 0;
|
||||
const huddleCount = particle.huddle_active_participants?.length ?? 0;
|
||||
@@ -154,7 +145,7 @@ function StreamRow({
|
||||
|
||||
const subtitle = latestChild
|
||||
? getMessagePreview(latestChild)
|
||||
: particle.properties.status;
|
||||
: particle.properties.name;
|
||||
|
||||
const TypeIcon = latestChild ? getParticleTypeIcon(latestChild) : Radio;
|
||||
|
||||
@@ -201,9 +192,6 @@ function StreamRow({
|
||||
<span className="text-[10px] font-medium text-red-400">{huddleCount}</span>
|
||||
</span>
|
||||
)}
|
||||
{expiringSoon && (
|
||||
<Timer className="size-3 text-muted-foreground/60" />
|
||||
)}
|
||||
{latestChild && (
|
||||
<Small
|
||||
className={cn(
|
||||
@@ -246,15 +234,16 @@ function StreamRow({
|
||||
}
|
||||
|
||||
interface ParticleListViewProps {
|
||||
path: ParticlePath;
|
||||
streams: StreamParticle[];
|
||||
networkId: string;
|
||||
isLoading: boolean;
|
||||
selectedIndex?: number | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of stream particles for a container (network root, folder, etc.).
|
||||
*/
|
||||
export function ParticleListView({ path, selectedIndex }: ParticleListViewProps) {
|
||||
const { streams, isLoading, networkId } = useStreamParticles(path);
|
||||
export function ParticleListView({ streams, networkId, isLoading, selectedIndex }: ParticleListViewProps) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (isLoading) {
|
||||
@@ -266,7 +255,7 @@ export function ParticleListView({ path, selectedIndex }: ParticleListViewProps)
|
||||
<div className="mx-auto flex h-full max-w-sm flex-col items-center justify-center gap-2 px-4 text-center">
|
||||
<Radio className="text-muted-foreground size-8" />
|
||||
<p className="text-muted-foreground text-sm">
|
||||
No recent streams yet. Start a conversation using the keyboard shortcuts below.
|
||||
No streams here. Start a conversation using the keyboard shortcuts below.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -275,19 +264,20 @@ export function ParticleListView({ path, selectedIndex }: ParticleListViewProps)
|
||||
return (
|
||||
<div>
|
||||
{streams.map((stream, index) => (
|
||||
<div
|
||||
key={stream.id}
|
||||
ref={index === selectedIndex ? (el) => el?.scrollIntoView({ block: "nearest" }) : undefined}
|
||||
>
|
||||
<StreamRow
|
||||
particle={stream}
|
||||
networkId={networkId}
|
||||
onClick={() => navigate(`/${networkId}/${stream.id}`)}
|
||||
isSelected={index === selectedIndex}
|
||||
shortcutKey={index < 9 ? index + 1 : undefined}
|
||||
/>
|
||||
{index < streams.length - 1 && <Separator className="px-4" />}
|
||||
</div>
|
||||
<StreamContextMenu key={stream.id} particle={stream} networkId={networkId}>
|
||||
<div
|
||||
ref={index === selectedIndex ? (el) => el?.scrollIntoView({ block: "nearest" }) : undefined}
|
||||
>
|
||||
<StreamRow
|
||||
particle={stream}
|
||||
networkId={networkId}
|
||||
onClick={() => navigate(`/${networkId}/${stream.id}`)}
|
||||
isSelected={index === selectedIndex}
|
||||
shortcutKey={index < 9 ? index + 1 : undefined}
|
||||
/>
|
||||
{index < streams.length - 1 && <Separator className="px-4" />}
|
||||
</div>
|
||||
</StreamContextMenu>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user