mirror of
https://github.com/stronk-dev/LivepeerEvents.git
synced 2025-07-05 02:35:09 +02:00
Add a summary page and a clipboard icon to copy to clipboard for montlhy factoids
This commit is contained in:
parent
3ce2a36ac0
commit
95ad97c870
@ -4,6 +4,7 @@ import Startup from './pages/loadingScreen.js';
|
||||
import Grafana from './pages/grafana.js';
|
||||
import Livepeer from './pages/livepeer.js';
|
||||
import Stats from './pages/stats.js';
|
||||
import Summary from './pages/summary.js'
|
||||
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
@ -20,6 +21,7 @@ export default function App() {
|
||||
<Route exact path='/livepeer' element={<Livepeer />} />
|
||||
<Route exact path='/tickets' element={<Stats />} />
|
||||
<Route exact path='/stats' element={<Stats />} />
|
||||
<Route exact path='/summary' element={<Summary />} />
|
||||
<Route exact path='/orchestrator' element={<Grafana />} />
|
||||
<Route path='/' element={<Home />} />
|
||||
</Routes>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import Ticket from "../components/TicketViewer";
|
||||
import ScrollContainer from 'react-indiana-drag-scroll';
|
||||
|
||||
const claimColour = "rgba(25, 158, 29, 0.4)";
|
||||
const stakeColour = "rgba(25, 158, 147, 0.4)";
|
||||
@ -13,6 +12,27 @@ const activationColour = "rgba(154, 158, 25, 0.4)";
|
||||
const ticketTransferColour = "rgba(88, 91, 42, 0.3)";
|
||||
const greyColour = "rgba(122, 128, 127, 0.4)";
|
||||
|
||||
function updateClipboard(newClip) {
|
||||
navigator.clipboard.writeText(newClip).then(
|
||||
() => {
|
||||
console.log("Copied!");
|
||||
},
|
||||
() => {
|
||||
console.log("Copy failed!");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function copyLink(addr) {
|
||||
navigator.permissions
|
||||
.query({ name: "clipboard-write" })
|
||||
.then((result) => {
|
||||
if (result.state === "granted" || result.state === "prompt") {
|
||||
updateClipboard(addr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const MonthlyFactoids = (obj) => {
|
||||
// Pies for stake overview, if have stake data for that month saved
|
||||
let totalStakeSum = 0;
|
||||
@ -26,9 +46,47 @@ const MonthlyFactoids = (obj) => {
|
||||
}
|
||||
}
|
||||
|
||||
let summary = "";
|
||||
if (obj.data.reactivationCount) {
|
||||
summary += "🔌 " + obj.data.reactivationCount + " orchestrators reactivated \r\n";
|
||||
}
|
||||
if (obj.data.activationCount) {
|
||||
summary += "🔧 " + obj.data.activationCount + " orchestrators joined with an initial stake of " + obj.data.activationInitialSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT \r\n";
|
||||
}
|
||||
if (obj.data.latestCommission && obj.data.latestCommission.length) {
|
||||
summary += "🔗 " + obj.data.latestCommission.length + " orchestrators had a total of " + totalStakeSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT staked to them \r\n";
|
||||
}
|
||||
if (obj.data.bondCount) {
|
||||
summary += "📈 " + obj.data.bondCount + " accounts delegated for the first time for a total of " + obj.data.bondStakeSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT \r\n";
|
||||
}
|
||||
if (obj.data.unbondCount) {
|
||||
summary +="📉 " + obj.data.unbondCount + " delegators unbonded " + obj.data.unbondStakeSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT \r\n";
|
||||
}
|
||||
if (obj.data.rewardCount) {
|
||||
summary += "⌛ " + obj.data.rewardCount + " reward calls made were made by orchestrators worth " + obj.data.rewardAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT \r\n";
|
||||
}
|
||||
if (obj.data.claimCount) {
|
||||
summary += "🏦 " + obj.data.claimRewardSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT and " + obj.data.claimFeeSum.toLocaleString({ maximumFractionDigits: 2 }) + " ETH worth of rewards were claimed by delegators \r\n";
|
||||
}
|
||||
if (obj.data.withdrawStakeCount) {
|
||||
summary += "💸 " + obj.data.withdrawStakeAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT worth of staking rewards were withdrawn to the accounts of delegators \r\n";
|
||||
}
|
||||
if (obj.data.withdrawFeesCount) {
|
||||
summary += "💸 " + obj.data.withdrawFeesAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " ETH worth of transcoding fees were withdrawn to the accounts of delegators \r\n";
|
||||
}
|
||||
if (obj.data.moveStakeCount) {
|
||||
summary += "🔄 " + obj.data.moveStakeSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT worth of stake was moved directly between orchestrators in " + obj.data.moveStakeCount + " transactions \r\n";
|
||||
}
|
||||
if (obj.data.winningTicketsReceivedCount) {
|
||||
summary += "🎫 " + obj.data.winningTicketsReceivedCount + " winning tickets were sent out by " + obj.data.winningTicketsSent.length + " broadcasters \r\n";
|
||||
}
|
||||
if (obj.data.winningTicketsRedeemedCount) {
|
||||
summary += "🎟️ " + obj.data.winningTicketsRedeemedCount + " winning tickets were redeemed worth " + obj.data.winningTicketsRedeemedSum.toLocaleString({ maximumFractionDigits: 2 }) + " ETH \r\n";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="stroke insetEffect" key={obj.seed + "factoids"}>
|
||||
<div className="overflow-content" style={{ cursor: 'grab', width: "unset" }}>
|
||||
<div className="overflow-content" style={{ width: "unset" }}>
|
||||
{obj.data.reactivationCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<div className="halfVerticalDivider" />
|
||||
@ -104,7 +162,7 @@ const MonthlyFactoids = (obj) => {
|
||||
<div className="halfVerticalDivider" />
|
||||
<div className="row" style={{ justifyContent: 'space-between', alignItems: 'stretch', maxWidth: '61.8%', textAlign: 'justify', padding: '0.5em', backgroundColor: withdrawStakeColour, border: '0.1em solid rgba(54, 46, 46, 0.1)' }}>
|
||||
<Ticket seed={obj.seed + "-neworchs-"} icon={"💸"} subtext={obj.data.withdrawStakeCount + " withdraw reward calls"} descriptions={[
|
||||
obj.data.withdrawStakeAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT worth of staking rewards were withdrawn to the account of the delegator"
|
||||
obj.data.withdrawStakeAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " LPT worth of staking rewards were withdrawn to the accounts of delegators"
|
||||
]} />
|
||||
</div>
|
||||
</div> : null
|
||||
@ -114,7 +172,7 @@ const MonthlyFactoids = (obj) => {
|
||||
<div className="halfVerticalDivider" />
|
||||
<div className="row" style={{ justifyContent: 'space-between', alignItems: 'stretch', maxWidth: '61.8%', textAlign: 'justify', padding: '0.5em', backgroundColor: withdrawStakeColour, border: '0.1em solid rgba(54, 46, 46, 0.1)' }}>
|
||||
<Ticket seed={obj.seed + "-neworchs-"} icon={"💸"} subtext={obj.data.withdrawFeesCount + " withdraw fee calls"} descriptions={[
|
||||
obj.data.withdrawFeesAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " ETH worth of transcoding fees were withdrawn to the account of the delegator"
|
||||
obj.data.withdrawFeesAmountSum.toLocaleString({ maximumFractionDigits: 2 }) + " ETH worth of transcoding fees were withdrawn to the accounts of delegators"
|
||||
]} />
|
||||
</div>
|
||||
</div> : null
|
||||
@ -150,6 +208,12 @@ const MonthlyFactoids = (obj) => {
|
||||
</div> : null
|
||||
}
|
||||
<div className="halfVerticalDivider" />
|
||||
<button className="selectOrchLight" onClick={() => {
|
||||
copyLink(summary);
|
||||
}}>
|
||||
<img alt="" src="clipboard.svg" width="20em" height="20em" />
|
||||
</button>
|
||||
<div className="halfVerticalDivider" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -178,7 +178,7 @@ const OrchInfoViewer = (obj) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row" style={{maxWidth: '500px'}}>
|
||||
<div className="row" style={{ maxWidth: '500px' }}>
|
||||
<div className="stroke sideMargin">
|
||||
<div className="verticalDivider" />
|
||||
<div className="row">
|
||||
|
86
src/pages/MonthlyStatsSummary.js
Normal file
86
src/pages/MonthlyStatsSummary.js
Normal file
@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
|
||||
const MonthlyStatsSummary = (obj) => {
|
||||
let totalStakeSum = 0;
|
||||
if (obj.data.latestTotalStake && obj.data.latestTotalStake.length) {
|
||||
let ticketIdx = obj.data.latestTotalStake.length - 1;
|
||||
// Calc total stake at that time
|
||||
while (ticketIdx >= 0) {
|
||||
const thisTicket = obj.data.latestTotalStake[ticketIdx];
|
||||
ticketIdx -= 1;
|
||||
totalStakeSum += thisTicket.totalStake;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="stroke insetEffect" key={obj.seed + "factoids"}>
|
||||
<div className="hostInfo" style={{ flexDirection: 'column' }}>
|
||||
{obj.data.reactivationCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🔌 {obj.data.reactivationCount} orchestrators reactivated</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.activationCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🔧 {obj.data.activationCount} orchestrators joined with an initial stake of {obj.data.activationInitialSum.toLocaleString({ maximumFractionDigits: 2 })} LPT</p>
|
||||
</div> : null
|
||||
}
|
||||
{(obj.data.latestCommission && obj.data.latestCommission.length) ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🔗 {obj.data.latestCommission.length} orchestrators had a total of {totalStakeSum.toLocaleString({ maximumFractionDigits: 2 })} LPT staked to them</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.bondCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>📈 {obj.data.bondCount} accounts delegated for the first time for a total of {obj.data.bondStakeSum.toLocaleString({ maximumFractionDigits: 2 })} LPT</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.unbondCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>📉 {obj.data.unbondCount} delegators unbonded {obj.data.unbondStakeSum.toLocaleString({ maximumFractionDigits: 2 })} LPT</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.rewardCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>⌛ {obj.data.rewardCount} reward calls made were made by orchestrators worth {obj.data.rewardAmountSum.toLocaleString({ maximumFractionDigits: 2 })} LPT</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.claimCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🏦 {obj.data.claimRewardSum.toLocaleString({ maximumFractionDigits: 2 })} LPT and {obj.data.claimFeeSum.toLocaleString({ maximumFractionDigits: 2 })} ETH worth of rewards were claimed by delegators</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.withdrawStakeCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>💸 {obj.data.withdrawStakeAmountSum.toLocaleString({ maximumFractionDigits: 2 })} LPT worth of staking rewards were withdrawn to the account of the delegator</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.withdrawFeesCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>💸 {obj.data.withdrawFeesAmountSum.toLocaleString({ maximumFractionDigits: 2 })} ETH worth of transcoding fees were withdrawn to the account of the delegator</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.moveStakeCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🔄 {obj.data.moveStakeSum.toLocaleString({ maximumFractionDigits: 2 })} LPT worth of stake was moved between orchestrators</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.winningTicketsReceivedCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🎫 {obj.data.winningTicketsReceivedCount} winning tickets were sent out by {obj.data.winningTicketsSent.length} broadcasters</p>
|
||||
</div> : null
|
||||
}
|
||||
{obj.data.winningTicketsRedeemedCount ?
|
||||
<div className="stroke" style={{ width: 'unset' }}>
|
||||
<p>🎟️ {obj.data.winningTicketsRedeemedCount} winning tickets were redeemed worth {obj.data.winningTicketsRedeemedSum.toLocaleString({ maximumFractionDigits: 2 })} ETH</p>
|
||||
</div> : null
|
||||
}
|
||||
<div className="halfVerticalDivider" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default MonthlyStatsSummary;
|
162
src/pages/summary.js
Normal file
162
src/pages/summary.js
Normal file
@ -0,0 +1,162 @@
|
||||
import React, { useState } from 'react'
|
||||
import '../style.css';
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Accordion } from '@mantine/core';
|
||||
import MonthlyStatsSummary from './MonthlyStatsSummary';
|
||||
|
||||
const Stats = (obj) => {
|
||||
const livepeer = useSelector((state) => state.livepeerstate);
|
||||
const [redirectToHome, setRedirectToHome] = useState(false);
|
||||
const [showOnlyTranscoders, setShowOnlyTranscoders] = useState(true);
|
||||
|
||||
console.log("Rendering Stats Viewer");
|
||||
|
||||
if (redirectToHome) {
|
||||
return <Navigate push to="/" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ margin: 0, padding: 0, height: '100%', width: '100%', overflow: 'hidden' }}>
|
||||
<div id='header'>
|
||||
<div className='rowAlignLeft'>
|
||||
<button className="homeButton" onClick={() => {
|
||||
setRedirectToHome(true);
|
||||
}}>
|
||||
<h1>🏠</h1>
|
||||
</button>
|
||||
<h4 className="rowAlignLeft withWrap showNeverOnMobile">Statistics</h4>
|
||||
</div>
|
||||
<div className='rowAlignRight'>
|
||||
<p>Hide non-earners</p>
|
||||
<div className="toggle-container" onClick={() => setShowOnlyTranscoders(!showOnlyTranscoders)}>
|
||||
<div className={`dialog-button ${showOnlyTranscoders ? "" : "disabled"}`}>
|
||||
{showOnlyTranscoders ? "Show" : "Hide"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='bodyContent'>
|
||||
<div className="row">
|
||||
<div className="stroke roundedOpaque onlyVerticalScroll" style={{ minWidth: '350px', width: '50vw', maxWidth: '1200px', height: 'calc( 100vh - 50px - 2em)', marginTop: '2em' }}>
|
||||
<div className="content-wrapper" style={{ width: '100%' }}>
|
||||
<div className="overflow-container">
|
||||
<div className="overflow-content" style={{ padding: 0 }}>
|
||||
<div className="flexContainer forceWrap" >
|
||||
<Accordion initialItem={0} className="stroke"
|
||||
style={{
|
||||
width: '100%', alignItems: 'stretch'
|
||||
}}
|
||||
styles={{
|
||||
item: {
|
||||
padding: 0, width: '100%', alignItems: 'stretch',
|
||||
color: 'black',
|
||||
border: '1px solid rgba(56, 56, 56, 0.9)',
|
||||
'&:hover': {
|
||||
color: 'black',
|
||||
border: '1px solid rgba(56, 56, 56, 0.9)',
|
||||
},
|
||||
'&': {
|
||||
color: 'black',
|
||||
border: '1px solid rgba(56, 56, 56, 0.9)',
|
||||
}
|
||||
},
|
||||
itemOpened: { padding: 0, width: '100%', alignItems: 'stretch' },
|
||||
itemTitle: {
|
||||
color: 'rgba(218, 218, 218, 0.9)',
|
||||
padding: 0, width: '100%',
|
||||
},
|
||||
control: {
|
||||
color: 'rgba(218, 218, 218, 0.9)',
|
||||
padding: 0, margin: 0, height: '100%',
|
||||
backgroundColor: 'rgba(56, 56, 56, 0.8)',
|
||||
boxShadow: 'inset 3px 3px 12px 2px rgba(62, 62, 104, 0.05)',
|
||||
color: 'black',
|
||||
border: 'none',
|
||||
'&:hover': {
|
||||
color: 'black',
|
||||
backgroundColor: 'rgba(56, 56, 56, 0.9)',
|
||||
},
|
||||
'&': {
|
||||
color: 'black',
|
||||
backgroundColor: 'rgba(56, 56, 56, 0.8)',
|
||||
border: 'none',
|
||||
}
|
||||
},
|
||||
label: {
|
||||
color: 'rgba(218, 218, 218, 0.9)',
|
||||
padding: '1em', width: '100%',
|
||||
backgroundColor: 'rgba(56, 56, 56, 0.8)',
|
||||
boxShadow: 'inset 3px 3px 12px 2px rgba(62, 62, 104, 0.05)'
|
||||
},
|
||||
icon: {
|
||||
padding: '0.2em', margin: '0.2em',
|
||||
},
|
||||
content: {
|
||||
padding: 0, alignItems: 'stretch', width: '100%', height: '100%',
|
||||
backgroundColor: 'rgba(56, 56, 56, 0.3)',
|
||||
boxShadow: 'inset 3px 3px 12px 2px rgba(62, 62, 104, 0.05)'
|
||||
},
|
||||
contentInner: { padding: 0, width: '100%', height: '100%' },
|
||||
}}>
|
||||
{
|
||||
livepeer.monthlyStats.slice(0).reverse().map(function (data, i) {
|
||||
let thisMonth = "";
|
||||
let monthAsNum = data.month;
|
||||
if (monthAsNum == 0) {
|
||||
thisMonth = "Januari";;
|
||||
} else if (monthAsNum == 1) {
|
||||
thisMonth = "Februari";;
|
||||
} else if (monthAsNum == 2) {
|
||||
thisMonth = "March";;
|
||||
} else if (monthAsNum == 3) {
|
||||
thisMonth = "April";
|
||||
} else if (monthAsNum == 4) {
|
||||
thisMonth = "May";
|
||||
} else if (monthAsNum == 5) {
|
||||
thisMonth = "June";
|
||||
} else if (monthAsNum == 6) {
|
||||
thisMonth = "July";
|
||||
} else if (monthAsNum == 7) {
|
||||
thisMonth = "August";
|
||||
} else if (monthAsNum == 8) {
|
||||
thisMonth = "September";
|
||||
} else if (monthAsNum == 9) {
|
||||
thisMonth = "October";
|
||||
} else if (monthAsNum == 10) {
|
||||
thisMonth = "November";
|
||||
} else if (monthAsNum == 11) {
|
||||
thisMonth = "December";;
|
||||
}
|
||||
|
||||
const title = data.year + "-" + thisMonth + ": " + data.winningTicketsReceived.length + " orchestrators earned " + data.winningTicketsReceivedSum.toFixed(2) + " Eth";
|
||||
|
||||
return (
|
||||
<Accordion.Item
|
||||
label={title}
|
||||
icon={"🔄"}
|
||||
className="stroke"
|
||||
style={{ width: '100%', alignItems: 'stretch' }}
|
||||
key={"accord" + i + data.year + "-" + data.month + "-" + data.total}>
|
||||
<MonthlyStatsSummary
|
||||
data={data}
|
||||
showOnlyTranscoders={showOnlyTranscoders}
|
||||
seed={"win" + i + data.year + "-" + data.month + "-" + data.total}
|
||||
/>
|
||||
</Accordion.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Accordion>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
export default Stats;
|
Loading…
x
Reference in New Issue
Block a user