Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
779c340
feat: add OrchestratorVotingList component for displaying voting data
Jipperism Dec 22, 2025
77689dd
feat: integrate Cube.js client and add VotingHistoryView component
Jipperism Dec 22, 2025
b2499a3
feat: enhance voting history functionality and UI
Jipperism Dec 22, 2025
7a772b0
feat: enhance orchestrators page with voting history and summaries
Jipperism Dec 22, 2025
d4d97c0
feat: add Vector.png asset for UI enhancements
Jipperism Dec 22, 2025
ea087fc
Cherry pick PR https://github.com/livepeer/explorer/pull/300
Jipperism Dec 22, 2025
3e5ac11
Merge branch 'main' into 310-showcase-orchestrator-voting-activity-in…
Jipperism Dec 22, 2025
0a56114
fix: update Cube.js data fetching and response handling
Jipperism Dec 23, 2025
91d8581
fix: standardize address and transaction hash formatting
Jipperism Dec 23, 2025
a443e2b
fix: orchestrators page early return
Jipperism Dec 23, 2025
6e55877
feat: add governance participation stat card to orchestrator overview
thebeyondr Dec 23, 2025
504f604
fix: add TypeScript error handling for string query in getAccountVote…
thebeyondr Dec 23, 2025
278a93a
refactor: refresh the treasury voters list experience and unify termi…
thebeyondr Dec 24, 2025
5c758d8
refactor: remove unused agent log and clean up VoteTable component
thebeyondr Dec 24, 2025
2a4911d
refactor: update voting badge terminology and styling in Transactions…
thebeyondr Dec 24, 2025
debdee4
fix(votes): correct SWR key to resolve missing proposal titles
thebeyondr Dec 24, 2025
a9684e1
feat(ux): add focus trap, keyboard shortcuts, and ARIA support to modal
thebeyondr Dec 24, 2025
4a2c314
feat(votes): add voting summary stats and ENS propagation to voter hi…
thebeyondr Dec 24, 2025
08039eb
style(ui): refactor vote cards with timeline layout and high-contrast…
thebeyondr Dec 24, 2025
fc7293a
style(table): change overflow property from scroll to auto for better…
thebeyondr Dec 24, 2025
a0e5a1e
style: refine treasury voting widget UI and accessibility
thebeyondr Dec 24, 2025
0e5e915
style: Reduce font weight from 600 to 500 for better visual hierarchy.
thebeyondr Dec 24, 2025
4a84597
refactor(account): remove voting history tab and associated components
Jipperism Jan 9, 2026
d79f05b
feat(votes): add treasury and vote event queries with hooks
Jipperism Jan 9, 2026
a122748
feat(history): integrate treasury and vote events into HistoryView
Jipperism Jan 9, 2026
507bda9
chore(voting): remove VotingHistoryView component
Jipperism Jan 9, 2026
c3d1e88
chore: remove OrchestratorVotingList component
Jipperism Jan 9, 2026
28e7999
chore: remove voting_history component as votes have been integrated …
Jipperism Jan 9, 2026
fa784c5
chore: remove Cube.js client and related query generator
Jipperism Jan 9, 2026
6df9ac9
feat(votes): enhance treasury vote handling and display
Jipperism Jan 9, 2026
4738dcb
chore: remove outdated hooks
Jipperism Jan 9, 2026
8d9206e
chore: remove outdated variables
Jipperism Jan 9, 2026
53a340d
style(voting): standardize For/Against colors and labels
thebeyondr Jan 9, 2026
46e8fbe
style(vote-table): update link and badge styles
thebeyondr Jan 9, 2026
efcd61b
style(voting): unify governance UI and implement accessibility signals
thebeyondr Jan 9, 2026
0795ac5
chore(merge): Merge branch '310-showcase-orchestrator-voting-activity…
thebeyondr Jan 9, 2026
a6b317f
Merge branch 'main' into 310-showcase-orchestrator-voting-activity-in…
Jipperism Jan 12, 2026
0502be8
refactor(votes): separate poll and treasury vote types
thebeyondr Jan 12, 2026
d55815a
refactor(votes): migrate components to use new vote type system
thebeyondr Jan 12, 2026
75f4576
refactor(votes): standardize terminology from Yes/No to For/Against
thebeyondr Jan 12, 2026
095c822
feat(votes): add vote icons and improve badge styling
thebeyondr Jan 12, 2026
18ca7dd
feat(treasury): add TreasuryVoteEvent component to display voting det…
Jipperism Jan 13, 2026
d3272cd
refactor(votes): extract vote logic into custom hook and enhance load…
Jipperism Jan 13, 2026
437236a
feat(votes): add formatWeight prop to VoteDetail and VotePopover comp…
Jipperism Jan 13, 2026
443921f
refactor(history): standardize naming for treasury vote events and im…
Jipperism Jan 13, 2026
246e5f9
style(voting): update text colors and border radius for voting indica…
thebeyondr Jan 13, 2026
7910f40
Merge branch 'main' into 310-showcase-orchestrator-voting-activity-in…
Jipperism Jan 15, 2026
a011063
feat(treasury): improve vote navigation in TreasuryVotingWidget
thebeyondr Jan 16, 2026
7eb8b56
feat(votes): add popover for long vote reasons
thebeyondr Jan 16, 2026
bac8449
feat(ui): refine treasury proposal UI and implement mobile reason exp…
thebeyondr Jan 16, 2026
1114a71
style(treasury): unify tab button styles and fix active border layering
thebeyondr Jan 16, 2026
590080f
style(layouts, treasury): add minHeight to flex containers for improv…
thebeyondr Jan 18, 2026
ea4de6f
fix: address PR #457 review comments
thebeyondr Jan 20, 2026
1a704c4
style(HorizontalScrollContainer): hide vertical overflow for improved…
thebeyondr Jan 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,160 changes: 1,071 additions & 89 deletions apollo/subgraph.ts

Large diffs are not rendered by default.

273 changes: 269 additions & 4 deletions components/HistoryView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
import Spinner from "@components/Spinner";
import { Fm } from "@lib/api/polls";
import { parseProposalText, Proposal } from "@lib/api/treasury";
import { POLL_VOTES, VOTING_SUPPORT_MAP } from "@lib/api/types/votes";
import dayjs from "@lib/dayjs";
import { formatAddress, formatTransactionHash } from "@lib/utils";
import {
Badge,
Box,
Card as CardBase,
Flex,
Link as A,
styled,
} from "@livepeer/design-system";
import { ExternalLinkIcon } from "@modulz/radix-icons";
import { useTransactionsQuery } from "apollo";
import {
TreasuryVoteEvent,
TreasuryVoteSupport,
useTransactionsQuery,
useTreasuryVoteEventsQuery,
useVoteEventsQuery,
VoteEvent,
} from "apollo";
import fm from "front-matter";
import { CHAIN_INFO, DEFAULT_CHAIN_ID } from "lib/chains";
import { useRouter } from "next/router";
import numbro from "numbro";
import { useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
import { catIpfsJson, IpfsPoll } from "utils/ipfs";

const Card = styled(CardBase, {
length: {},
Expand All @@ -28,6 +41,81 @@ const Index = () => {
const query = router.query;
const account = query.account as string;

const { data: treasuryVoteEventsData } = useTreasuryVoteEventsQuery({
variables: {
where: {
voter: account.toLowerCase(),
},
},
notifyOnNetworkStatusChange: true,
});
const [extendedTreasuryVoteEventsData, setExtendedTreasuryVoteEventsData] =
useState<(TreasuryVoteEvent & { attributes: Fm | null })[]>([]);
useEffect(() => {
if (treasuryVoteEventsData) {
const extendedTreasureVoteEventsData =
treasuryVoteEventsData?.treasuryVoteEvents.map((treasuryVoteEvent) => {
const parsed = parseProposalText(
treasuryVoteEvent.proposal as Proposal
);
return {
...treasuryVoteEvent,
attributes: parsed.attributes,
};
});
setExtendedTreasuryVoteEventsData(
extendedTreasureVoteEventsData as (TreasuryVoteEvent & {
attributes: Fm | null;
})[]
);
}
}, [treasuryVoteEventsData]);

const { data: voteEventsData } = useVoteEventsQuery({
variables: {
where: {
voter: account.toLowerCase(),
},
},
notifyOnNetworkStatusChange: true,
});
const [extendedVoteEventsData, setExtendedVoteEventsData] = useState<
(VoteEvent & { attributes: Fm | null })[]
>([]);
useEffect(() => {
const getExtendedVoteEventsData = async () => {
const extendedVoteEventsData = await Promise.all(
voteEventsData?.voteEvents.map(async (voteEvent) => {
const ipfsObject = await catIpfsJson<IpfsPoll>(
voteEvent.poll?.proposal
);
let attributes: Fm | null = null;

// only include proposals with valid format
if (ipfsObject?.text && ipfsObject?.gitCommitHash) {
const transformedProposal = fm<Fm>(ipfsObject.text);

attributes = {
title: String(transformedProposal.attributes.title),
lip: String(transformedProposal.attributes.lip),
commitHash: String(ipfsObject.gitCommitHash),
created: String(transformedProposal.attributes.created),
text: String(transformedProposal.body),
};
}
return {
...voteEvent,
attributes,
};
}) || []
);
setExtendedVoteEventsData(
extendedVoteEventsData as (VoteEvent & { attributes: Fm | null })[]
);
};
getExtendedVoteEventsData();
}, [voteEventsData]);

const { data, loading, error, fetchMore, stopPolling } = useTransactionsQuery(
{
variables: {
Expand Down Expand Up @@ -61,15 +149,28 @@ const Index = () => {
const mergedEvents = useMemo(
() =>
[
...events.filter((e) => e?.__typename !== "WinningTicketRedeemedEvent"),
...events.filter(
(e) =>
e?.__typename !== "WinningTicketRedeemedEvent" &&
e?.__typename !== "TreasuryVoteEvent" &&
e?.__typename !== "VoteEvent"
),
...(data?.winningTicketRedeemedEvents?.filter(
(e) => (e?.transaction?.timestamp ?? 0) > lastEventTimestamp
) ?? []),
...extendedTreasuryVoteEventsData,
...extendedVoteEventsData,
].sort(
(a, b) =>
(b?.transaction?.timestamp ?? 0) - (a?.transaction?.timestamp ?? 0)
),
[events, data, lastEventTimestamp]
[
events,
data,
lastEventTimestamp,
extendedTreasuryVoteEventsData,
extendedVoteEventsData,
]
);

if (error) {
Expand Down Expand Up @@ -832,6 +933,170 @@ function renderSwitch(event, i: number) {
</Flex>
</Card>
);
case "TreasuryVoteEvent":
const supportTreasuryVoteEvent =
VOTING_SUPPORT_MAP[event.support] ||
VOTING_SUPPORT_MAP[TreasuryVoteSupport.Abstain];
return (
<Card
as={A}
key={i}
href={`https://explorer.livepeer.org/treasury/${event.proposal?.id}`}
target="_blank"
rel="noopener noreferrer"
css={{
textDecoration: "none",
"&:hover": {
textDecoration: "none",
},
}}
>
<Flex
css={{
width: "100%",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Box>
<Box css={{ fontWeight: 500 }}>
Voted on treasury proposal &quot;
{event.attributes?.title?.trim()}&quot;
</Box>
<Box
css={{ marginTop: "$2", fontSize: "$1", color: "$neutral11" }}
>
{dayjs
.unix(event.transaction.timestamp)
.format("MM/DD/YYYY h:mm:ss a")}{" "}
- Round #{event.round.id}
</Box>
<Flex
css={{
alignItems: "center",
marginTop: "$2",
fontSize: "$1",
color: "$neutral11",
}}
as={A}
href={`https://explorer.livepeer.org/treasury/${event.transaction?.id}`}
target="_blank"
rel="noopener noreferrer"
>
<Box css={{ marginRight: "$1" }}>
{formatTransactionHash(event.transaction.id)}
</Box>
<ExternalLinkIcon />
</Flex>
</Box>
<Box css={{ fontSize: "$3", marginLeft: "$4" }}>
<Badge
size="1"
css={{
backgroundColor:
supportTreasuryVoteEvent.style.backgroundColor,
color: supportTreasuryVoteEvent.style.color,
fontWeight: supportTreasuryVoteEvent.style.fontWeight,
border: "none",
width: "86px",
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
gap: "$1",
}}
>
<Box
as={supportTreasuryVoteEvent.icon}
css={{ width: 12, height: 12 }}
/>
{supportTreasuryVoteEvent.text}
</Badge>
</Box>
</Flex>
</Card>
);
case "VoteEvent":
const supportVoteEvent = POLL_VOTES[event.choiceID];
if (!supportVoteEvent) {
return null;
}
return (
<Card
as={A}
key={i}
href={`https://explorer.livepeer.org/voting/${event.poll?.id}`}
target="_blank"
rel="noopener noreferrer"
css={{
textDecoration: "none",
"&:hover": {
textDecoration: "none",
},
}}
>
<Flex
css={{
width: "100%",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Box>
<Box css={{ fontWeight: 500 }}>
Voted on poll &quot;{event.attributes?.title?.trim()}&quot;
</Box>
<Box
css={{ marginTop: "$2", fontSize: "$1", color: "$neutral11" }}
>
{dayjs
.unix(event.transaction.timestamp)
.format("MM/DD/YYYY h:mm:ss a")}{" "}
- Round #{event.round.id}
</Box>
<Flex
css={{
alignItems: "center",
marginTop: "$2",
fontSize: "$1",
color: "$neutral11",
}}
as={A}
href={`${CHAIN_INFO[DEFAULT_CHAIN_ID].explorer}tx/${event.transaction.id}`}
target="_blank"
rel="noopener noreferrer"
>
<Box css={{ marginRight: "$1" }}>
{formatTransactionHash(event.transaction.id)}
</Box>
<ExternalLinkIcon />
</Flex>
</Box>
<Box css={{ fontSize: "$3", marginLeft: "$4" }}>
<Badge
size="1"
css={{
backgroundColor: supportVoteEvent.style.backgroundColor,
color: supportVoteEvent.style.color,
fontWeight: supportVoteEvent.style.fontWeight,
fontSize: "$4",
border: "none",
width: "86px",
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
gap: "$1",
}}
>
<Box
as={supportVoteEvent.icon}
css={{ width: 16, height: 16 }}
/>
{supportVoteEvent.text}
</Badge>
</Box>
</Flex>
</Card>
);
default:
return null;
}
Expand Down
13 changes: 11 additions & 2 deletions components/HorizontalScrollContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,14 @@ const HorizontalScrollContainer = forwardRef<
<Box
css={{
position: "relative",
borderBottom: "1px solid",
borderColor: "$neutral6",
"&::after": {
content: '""',
position: "absolute",
left: 0,
right: 0,
bottom: 0,
borderBottom: "1px solid $neutral6",
},
}}
>
<Box
Expand All @@ -107,8 +113,11 @@ const HorizontalScrollContainer = forwardRef<
alignItems: "center",
width: "100%",
overflowX: "auto",
overflowY: "hidden",
WebkitOverflowScrolling: "touch",
flexWrap: "nowrap",
position: "relative",
zIndex: 1,
}}
role={role}
aria-label={ariaLabel}
Expand Down
Loading