import React, {useCallback, useState} from 'react'; import PlayDisplay from "../components/PlayDisplay"; import {recentIncludes} from "../../core/Atomic"; import {useSearchParams} from "react-router-dom"; import { useGetDeadQuery, useRemoveDeadSingleMutation, useProcessDeadSingleMutation, useLazyProcessDeadQuery, useLazyRemoveDeadQuery, deadAdapter, clearDead, } from "./deadLetterDucks"; import dayjs from "dayjs"; import type {RootState} from "../store"; import {connect, type ConnectedProps} from "react-redux"; import { faBug } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import clsx from "clsx"; import { useCopyToClipboard } from '../components/copyToClipboardHook'; import { messageWithCauses } from '../../core/ErrorUtils'; const displayOpts = { include: recentIncludes, includeWeb: true } const dead = (props: PropsFromRedux) => { const { data = [], } = props; const [searchParams, setSearchParams] = useSearchParams(); const { isLoading, isSuccess } = useGetDeadQuery({name: searchParams.get('name'), type: searchParams.get('type')}); const { copy, isCopied } = useCopyToClipboard(); const [copiedIndex, setIndex] = useState(null); const copyActionCB = useCallback((obj, index) => { copy(JSON.stringify(obj, null, 2)); setIndex(index); },[copy, setIndex]); const baseClass = ['mr-3']; const [removeDeadFetch, removeResult] = useRemoveDeadSingleMutation(); const [retryDeadFetch, processResult] = useProcessDeadSingleMutation(); const [removeAllDeadFetch] = useLazyRemoveDeadQuery(); const [retryAllDeadFetch] = useLazyProcessDeadQuery(); const retryDead = useCallback((id: string) => retryDeadFetch({name: searchParams.get('name'), type: searchParams.get('type'), id}), [retryDeadFetch, searchParams]); const removeDead = useCallback((id: string) => removeDeadFetch({name: searchParams.get('name'), type: searchParams.get('type'), id}), [removeDeadFetch, searchParams]); const removeAllDead = useCallback(() => removeAllDeadFetch({name: searchParams.get('name'), type: searchParams.get('type')}), [removeAllDeadFetch, searchParams]); const retryAllDead = useCallback(() => retryAllDeadFetch({name: searchParams.get('name'), type: searchParams.get('type')}), [retryAllDeadFetch, searchParams]); return (

Failed Scrobbles - retryAllDead()} className="capitalize underline cursor-pointer max-w-fit">Retry All | removeAllDead()} className="capitalize underline cursor-pointer max-w-fit">Remove All

{isSuccess && !isLoading && data.length === 0 ? 'No failed scrobbles!' : null}
    {data.map(x => { let errorSummary: string; try { // @ts-expect-error errorSummary = messageWithCauses(x.error, undefined, '\n caused by: '); } catch (e) { console.warn(new Error('Could not convert error to summary', {cause: e})); } const classes = [...baseClass].concat(copiedIndex !== x.id ? ['underline','cursor-pointer'] : []); return (
  • Source:{x.source === undefined ? 'Source - Unknown' : x.source.replace('Source -', '')}
    Status:{x.status}
    Retries: {x.retries}
    Last Retried: {x.lastRetry === undefined ? 'Never' : dayjs.duration(dayjs(x.lastRetry).diff(dayjs())).humanize(true)}
    {errorSummary === undefined ? null :
    Error Summary:
    {errorSummary}
    }
    retryDead(x.id)} className="capitalize underline cursor-pointer max-w-fit">Retry
    removeDead(x.id)} className="capitalize underline cursor-pointer max-w-fit">Remove
  • ) } )}
); } const deadSelectors = deadAdapter.getSelectors(); const mapStateToProps = (state: RootState) => { return { data: deadSelectors.selectAll(state.deadLetter) } } const mapDispatchToProps = (dispatch) => { return { clearDeadLetter: () => dispatch(clearDead()) } } const connector = connect(mapStateToProps, mapDispatchToProps); type PropsFromRedux = ConnectedProps export default connector(dead);