import React, { type ComponentProps, Fragment } from "react" import { Stack, Heading, Separator, HStack, Flex, Badge, Card, LinkOverlay, LinkBox } from '@chakra-ui/react'; import { type ComponentClientApiJson, type ComponentCommonApiJson, type ComponentsApiJson, isComponentClientApiJson, isComponentSourceApiJson, type MsSseEvent, type MsSseEventPayload } from "../../../core/Api.js"; import { Link } from "react-router"; import { TextMuted } from "../TextMuted.js"; import { capitalize } from "../../../core/StringUtils.js"; import { ChevronRightButton, IdleIcon } from "../icons/ChakraIcons.js"; import { PlayersContainer, PlayersContainerFetchable } from "../chakraPlayer/Player.js"; import { type QueryFunctionContext, useQuery, useQueryClient } from '@tanstack/react-query'; import { ErrorAlert } from "../ErrorAlert"; import { useSSEContext, useSSEAnyEvent } from "@flamefrontend/sse-runtime-react"; import { CountIndicatorStreamable, DeadLetterIndicatorStreamable, QueuedIndicatorStreamable } from "./Stats.js"; import { ComponentStateBadge } from "../Badges.js"; import { MSErrorBoundary } from "../ErrorBoundary.js"; const presentPlayersContainerProps: ComponentProps = { //paddingTop: '2', //borderTopWidth: '1px' }; export const MSComponentSummary = (props: { data: ComponentsApiJson, fetchable?: boolean }) => { const { data, fetchable } = props; let sleepingRender: React.JSX.Element | null = null; const cardHeaderProps: Card.HeaderProps = {}; const isClient = isComponentClientApiJson(data); if(isComponentSourceApiJson(data)) { const { sleeping } = data; if(sleeping) { sleepingRender = ; } } const body = ( {fetchable ? : } ); return ( {data.name} {sleepingRender} {/* {props.data.status} */} {capitalize(data.type)} {capitalize(data.mode)} {body} ) } //colorPalette={data.mode === 'client' ? 'purple' : 'pink'} // color={data.mode === 'client' ? 'purple' : 'pink'} const QuickStatsSource = (props: { data: ComponentCommonApiJson, streamable?: boolean }) => ( ) export const MSComponentSummaryFetchable = (props: {componentId: number, data: ComponentsApiJson}) => { const { componentId, data: initData } = props; const queryClient = useQueryClient(); const client = useSSEContext(); useSSEAnyEvent(client, (payload) => { if('componentId' in (payload.data as object) && (payload.data as Record).componentId === componentId) { switch(payload.type) { case 'componentUpdate': queryClient.setQueryData(['components', componentId, 'summary'], (old) => { if(old === undefined) { return old; } const componentData = payload.data as MsSseEventPayload>; return {...old, ...componentData.data}; }); } } }); const { isPending, isError, data, error } = useQuery({ queryKey: ['components', componentId, 'summary'], queryFn: queryFn, // data comes from the parent list and is kept up to date by SSE events, never fetched initialData: initData, structuralSharing: false, staleTime: Infinity, }); if (isError) { return } return } type ComponentSummaryQueryKey = ['components', number, 'summary']; // placeholder, never called: query always has initialData and staleTime is Infinity const queryFn = async (context: QueryFunctionContext) => { return {} as ComponentsApiJson; }