mirror of https://git.sr.ht/~ashkeel/strimertul
feat: add marker in recent events to show which events are new
This commit is contained in:
parent
5bdc05ced8
commit
a1fab34a70
|
@ -267,6 +267,7 @@
|
|||
"header": "Recent events",
|
||||
"warning": "This section only contains events that happened while {{APPNAME}} was open, so only use it for recent stuff",
|
||||
"anonymous": "An anonymous viewer",
|
||||
"marker": "Events from previous sessions",
|
||||
"events": {
|
||||
"follow": "<n>{{name}}</n> followed you",
|
||||
"redemption": "<n>{{name}}</n> redeemed <r>{{reward}}</r>",
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
"anonymous": "Uno spettatore anonimo",
|
||||
"header": "Eventi recenti",
|
||||
"warning": "Questa sezione contiene solo gli eventi accaduti mentre {{APPNAME}} era aperto, quindi utilizzala solo per cose recenti",
|
||||
"marker": "Eventi delle sessioni precedenti",
|
||||
"events": {
|
||||
"channel-updated": "Informazioni stream modificate",
|
||||
"cheered": "<n>{{name}}</n> ti ha tifato con <b>{{bits}} bit</b>",
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { ClipboardCopyIcon, Cross2Icon, SizeIcon } from '@radix-ui/react-icons';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from 'src/store';
|
||||
import { useAppSelector } from 'src/store';
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import { delay } from '~/lib/time';
|
||||
import { ProcessedLogEntry } from '~/store/logging/reducer';
|
||||
|
@ -294,12 +293,14 @@ export function LogItem({ data, expandDefault }: LogItemProps) {
|
|||
const details = Object.entries(data.data).filter(([key]) => key.length > 1);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [showDetails, setShowDetails] = useState(expandDefault ?? false);
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
await navigator.clipboard.writeText(JSON.stringify(data.data));
|
||||
setCopied(true);
|
||||
await delay(2000);
|
||||
setCopied(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<LogEntryContainer level={levelStyle}>
|
||||
<LogTime level={levelStyle}>{formatTime(data.time)}</LogTime>
|
||||
|
@ -355,7 +356,7 @@ interface LogDialogProps {
|
|||
}
|
||||
|
||||
function LogDialog({ initialFilter }: LogDialogProps) {
|
||||
const logEntries = useSelector((state: RootState) => state.logging.messages);
|
||||
const logEntries = useAppSelector((state) => state.logging.messages);
|
||||
const [filter, setFilter] = useState({
|
||||
...emptyFilter,
|
||||
...Object.fromEntries(initialFilter.map((f) => [f, true])),
|
||||
|
@ -440,7 +441,7 @@ function LogDialog({ initialFilter }: LogDialogProps) {
|
|||
}
|
||||
|
||||
function LogViewer() {
|
||||
const logEntries = useSelector((state: RootState) => state.logging.messages);
|
||||
const logEntries = useAppSelector((state) => state.logging.messages);
|
||||
const [activeDialog, setActiveDialog] = useState<LogLevel>(null);
|
||||
|
||||
const count = logEntries.reduce(
|
||||
|
|
|
@ -16,7 +16,11 @@ import { modules } from '~/store/api/reducer';
|
|||
import * as HoverCard from '@radix-ui/react-hover-card';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { main } from '@wailsapp/go/models';
|
||||
import { GetProblems, GetTwitchAuthURL } from '@wailsapp/go/main/App';
|
||||
import {
|
||||
GetLastLogs,
|
||||
GetProblems,
|
||||
GetTwitchAuthURL,
|
||||
} from '@wailsapp/go/main/App';
|
||||
import { BrowserOpenURL } from '@wailsapp/runtime/runtime';
|
||||
import {
|
||||
PageContainer,
|
||||
|
@ -362,8 +366,64 @@ function TwitchEvent({ data }: { data: EventSubNotification }) {
|
|||
);
|
||||
}
|
||||
|
||||
function TwitchEventLog({ events }: { events: EventSubNotification[] }) {
|
||||
const block = {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
width: '1rem',
|
||||
height: '0.1rem',
|
||||
margin: '0 0.5rem',
|
||||
backgroundColor: '$gray9',
|
||||
};
|
||||
|
||||
const SessionMarker = styled('div', {
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: '600',
|
||||
fontSize: '0.75rem',
|
||||
color: '$gray11',
|
||||
margin: '0.25rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
'&::before': block,
|
||||
'&::after': block,
|
||||
});
|
||||
|
||||
interface TwitchEventLogProps {
|
||||
events: EventSubNotification[];
|
||||
dateMarker: number;
|
||||
}
|
||||
|
||||
type EventItem =
|
||||
| { type: 'marker' }
|
||||
| { type: 'event'; event: EventSubNotification };
|
||||
|
||||
function TwitchEventLog({ events, dateMarker }: TwitchEventLogProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Filter only supported events and order them by date
|
||||
const orderedEvents: EventItem[] = events
|
||||
.filter((ev) => supportedMessages.includes(ev.subscription.type))
|
||||
.sort((a, b) =>
|
||||
a.date && b.date
|
||||
? Date.parse(b.date) - Date.parse(a.date)
|
||||
: Date.parse(b.subscription.created_at) -
|
||||
Date.parse(a.subscription.created_at),
|
||||
)
|
||||
.map((ev) => ({ type: 'event', event: ev }));
|
||||
|
||||
// Add marker
|
||||
if (dateMarker) {
|
||||
const index = orderedEvents.findIndex((ev) => {
|
||||
if (ev.type !== 'event') {
|
||||
return false;
|
||||
}
|
||||
return Date.parse(ev.event.date) < dateMarker;
|
||||
});
|
||||
if (index >= 0) {
|
||||
orderedEvents.splice(index, 0, { type: 'marker' });
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<HoverCard.Root>
|
||||
|
@ -383,17 +443,23 @@ function TwitchEventLog({ events }: { events: EventSubNotification[] }) {
|
|||
</HoverCard.Root>
|
||||
<Scrollbar vertical={true} viewport={{ maxHeight: '250px' }}>
|
||||
<EventListContainer>
|
||||
{events
|
||||
.filter((ev) => supportedMessages.includes(ev.subscription.type))
|
||||
.sort((a, b) =>
|
||||
a.date && b.date
|
||||
? Date.parse(b.date) - Date.parse(a.date)
|
||||
: Date.parse(b.subscription.created_at) -
|
||||
Date.parse(a.subscription.created_at),
|
||||
)
|
||||
.map((ev) => (
|
||||
<TwitchEvent key={eventSubKeyFunction(ev)} data={ev} />
|
||||
))}
|
||||
{orderedEvents.map((ev) => {
|
||||
switch (ev.type) {
|
||||
case 'marker':
|
||||
return (
|
||||
<SessionMarker key="marker">
|
||||
{t('pages.dashboard.twitch-events.marker')}
|
||||
</SessionMarker>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<TwitchEvent
|
||||
key={eventSubKeyFunction(ev.event)}
|
||||
data={ev.event}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</EventListContainer>
|
||||
</Scrollbar>
|
||||
</>
|
||||
|
@ -439,6 +505,19 @@ function TwitchSection() {
|
|||
const twitchInfo = useLiveKey<StreamInfo[]>('twitch/stream-info');
|
||||
const kv = useAppSelector((state) => state.api.client);
|
||||
const [twitchEvents, setTwitchEvents] = useState<EventSubNotification[]>([]);
|
||||
const [oldestLog, setOldestLog] = useState(Date.now());
|
||||
|
||||
useEffect(() => {
|
||||
GetLastLogs().then((res) => {
|
||||
// Get oldest log entry
|
||||
const oldest = res.reduce<number>((acc, log) => {
|
||||
const parsedDate = Date.parse(log.time);
|
||||
return parsedDate < acc ? parsedDate : acc;
|
||||
}, Date.now());
|
||||
|
||||
setOldestLog(oldest);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const keyfn = (ev: EventSubNotification) => JSON.stringify(ev);
|
||||
|
||||
|
@ -493,7 +572,9 @@ function TwitchSection() {
|
|||
) : (
|
||||
<TextBlock>{t('pages.dashboard.not-live')}</TextBlock>
|
||||
)}
|
||||
{twitchEvents ? <TwitchEventLog events={twitchEvents} /> : null}
|
||||
{twitchEvents ? (
|
||||
<TwitchEventLog events={twitchEvents} dateMarker={oldestLog} />
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue