Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds proposal status polling #5428

Merged
merged 8 commits into from Dec 16, 2022
Merged
6 changes: 6 additions & 0 deletions packages/desktop/views/dashboard/governance/Governance.svelte
@@ -1,7 +1,13 @@
<script lang="typescript">
import { onMount } from 'svelte'
import { DetailsView, ProposalsView } from './views'
import { selectedAccount } from '@core/account'
import { GovernanceRoute, governanceRoute } from '@core/router'
import { pollProposalsState } from '@core/governance/actions'

onMount(async () => {
await pollProposalsState()
})
</script>

{#if $selectedAccount}
Expand Down
Expand Up @@ -21,15 +21,16 @@
import type { IParticipations } from '@core/governance/interfaces'
import { openPopup } from '@auxiliary/popup'
import { ProposalStatus } from '@core/governance/enums'
import { networkStatus } from '@core/network'
import { proposalsState } from '@core/governance/stores'
import { networkStatus } from '@core/network/stores'

let selectedIndices: number[] = []

let votingPayload: VotingEventPayload
$: void setVotingEventPayload($selectedProposal?.id)

let totalVotes = 0

$: void setVotingEventPayload($selectedProposal?.id)
$: void setTotalVotes()
$: proposalStatus = $proposalsState[$selectedProposal?.id]?.status

$: votesCounter = {
total: totalVotes,
Expand All @@ -41,8 +42,8 @@
selectedIndices = Array<number>(questions?.length)
}
$: isVotingDisabled =
$selectedProposal?.status === ProposalStatus.Announcement ||
$selectedProposal?.status === ProposalStatus.Closed ||
proposalStatus === ProposalStatus.Upcoming ||
proposalStatus === ProposalStatus.Ended ||
selectedIndices?.length === 0 ||
selectedIndices?.includes(undefined)

Expand Down
Expand Up @@ -12,16 +12,16 @@

let eventProgress: number
switch (status) {
case ProposalStatus.Announcement:
case ProposalStatus.Upcoming:
eventProgress = 0
break
case ProposalStatus.VotingOpen:
case ProposalStatus.Commencing:
eventProgress = 1
break
case ProposalStatus.Counting:
case ProposalStatus.Holding:
eventProgress = 2
break
case ProposalStatus.Closed:
case ProposalStatus.Ended:
eventProgress = 3
break
default:
Expand Down
Expand Up @@ -6,10 +6,10 @@
export let status: ProposalStatus

const STATUS_COLORS: Record<ProposalStatus, string> = {
[ProposalStatus.Announcement]: 'purple-200',
[ProposalStatus.VotingOpen]: 'blue-200',
[ProposalStatus.Counting]: 'green-300',
[ProposalStatus.Closed]: 'gray-200',
[ProposalStatus.Upcoming]: 'purple-200',
[ProposalStatus.Commencing]: 'blue-200',
[ProposalStatus.Holding]: 'green-300',
[ProposalStatus.Ended]: 'gray-200',
}
</script>

Expand Down
7 changes: 5 additions & 2 deletions packages/shared/components/organisms/ProposalCard.svelte
Expand Up @@ -8,9 +8,12 @@
import { FontWeight, Position } from '../enums'
import { Icon } from '@auxiliary/icon/enums'
import { localize } from '@core/i18n'
import { proposalsState } from '@core/governance/stores'

export let proposal: IProposal

$: proposalState = $proposalsState[proposal?.id]

function handleProposalClick(): void {
$selectedProposal = proposal
$governanceRouter.goTo(GovernanceRoute.Details)
Expand All @@ -20,7 +23,7 @@
<proposal-card
on:click={handleProposalClick}
class="flex flex-col p-6 border border-solid border-gray-200 rounded-xl cursor-pointer h-32
{proposal.status === ProposalStatus.Closed ? 'bg-transparent' : 'bg-white'}"
{proposal.status === ProposalStatus.Ended ? 'bg-transparent' : 'bg-white'}"
>
<div class="flex items-center gap-1.5 mb-5">
{#if proposal.organization}
Expand All @@ -38,7 +41,7 @@
<Text fontWeight={FontWeight.semibold} fontSize="14" classes="truncate">{proposal.title}</Text>
</div>
<div class="flex justify-between items-center">
<ProposalStatusInfo status={proposal.status} milestones={proposal.milestones} />
<ProposalStatusInfo status={proposalState?.status} milestones={proposal.milestones} />
{#if proposal.hasVoted}
<TooltipIcon icon={Icon.Voted} size="small" position={Position.Left} iconClasses="text-gray-500">
<Text smaller overrideColor fontWeight={FontWeight.semibold} classes="text-gray-600">
Expand Down
Expand Up @@ -7,7 +7,7 @@
const proposalInformation = {
countingEnds: formatDate(
milestoneToDate($networkStatus.currentMilestone, $selectedProposal.milestones?.closed),
milestoneToDate($networkStatus.currentMilestone, $selectedProposal.milestones?.ended),
DATE_FORMAT
),
eventId: truncateString($selectedProposal?.id, 9, 9),
Expand Down
1 change: 1 addition & 0 deletions packages/shared/lib/core/governance/actions/index.ts
@@ -1 +1,2 @@
export * from './proposalsStatePolling'
export * from './setVotingPower'
@@ -0,0 +1,13 @@
import { PROPOSAL_STATUS_POLL_INTERVAL } from '../constants'
import { updateProposalsState } from '../stores'

let pollInterval

export async function pollProposalsState(): Promise<void> {
await updateProposalsState()
pollInterval = setInterval(() => void updateProposalsState(), PROPOSAL_STATUS_POLL_INTERVAL)
}

export function clearPollProposalsStateInterval(): void {
clearInterval(pollInterval)
}
1 change: 1 addition & 0 deletions packages/shared/lib/core/governance/constants/index.ts
@@ -0,0 +1 @@
export * from './proposal-status-poll-interval.constant'
@@ -0,0 +1,4 @@
import { SECONDS_PER_MILESTONE } from '@core/network/constants'
import { MILLISECONDS_PER_SECOND } from '@core/utils/constants'

export const PROPOSAL_STATUS_POLL_INTERVAL = SECONDS_PER_MILESTONE * MILLISECONDS_PER_SECOND
@@ -1,6 +1,6 @@
export enum ProposalStatus {
Announcement = 'announcement',
VotingOpen = 'votingOpen',
Counting = 'counting',
Closed = 'closed',
Upcoming = 'upcoming',
Commencing = 'commencing',
Holding = 'holding',
Ended = 'ended',
}
1 change: 1 addition & 0 deletions packages/shared/lib/core/governance/stores/index.ts
@@ -1 +1,2 @@
export * from './proposals-state.store'
export * from './selected-proposal.store'
@@ -0,0 +1,34 @@
import { get } from 'svelte/store'
import type { EventStatus } from '@iota/wallet'
import { getVotingProposalState } from '@core/profile-manager/api'
import { persistent } from '@core/utils/store'

export const proposalsState = persistent<{ [key in string]: EventStatus }>('proposalsState', {})

export async function addProposalState(eventId: string): Promise<void> {
const _proposalsState = get(proposalsState)
const hasRegisteredProposalStatus = Object.keys(_proposalsState).includes(eventId)
if (!hasRegisteredProposalStatus) {
const proposalStatus = await getVotingProposalState(eventId)
_proposalsState[eventId] = proposalStatus
proposalsState.set(_proposalsState)
}
}

export function removeProposalState(eventId: string): void {
const _proposalsState = get(proposalsState)
const hasRegisteredProposalStatus = Object.keys(_proposalsState).includes(eventId)
if (hasRegisteredProposalStatus) {
delete _proposalsState[eventId]
proposalsState.set(_proposalsState)
}
}

export async function updateProposalsState(): Promise<void> {
const _proposalsState = get(proposalsState)
for (const eventId in _proposalsState) {
const proposalStatus = await getVotingProposalState(eventId)
_proposalsState[eventId] = proposalStatus
}
proposalsState.set(_proposalsState)
}
Expand Up @@ -12,12 +12,12 @@ export function createProposalsFromEvents(events: Event[]): IProposal[] {
const proposal = {
id,
title: data.name,
status: ProposalStatus.Announcement,
status: ProposalStatus.Upcoming,
milestones: {
[ProposalStatus.Announcement]: 0, // TODO: fix this
[ProposalStatus.VotingOpen]: data.milestoneIndexCommence,
[ProposalStatus.Counting]: data.milestoneIndexStart,
[ProposalStatus.Closed]: data.milestoneIndexEnd,
[ProposalStatus.Upcoming]: 0, // TODO: fix this
[ProposalStatus.Commencing]: data.milestoneIndexCommence,
[ProposalStatus.Holding]: data.milestoneIndexStart,
[ProposalStatus.Ended]: data.milestoneIndexEnd,
},
// TODO: figure out a better way to get the node URLs
nodeUrls: get(activeProfile)?.clientOptions?.nodes,
Expand Down
@@ -1,8 +1,10 @@
import { profileManager } from '@core/profile-manager/stores'
import type { EventId } from '@iota/wallet'
import { get } from 'svelte/store'
import type { EventId } from '@iota/wallet'
import { removeProposalState } from '@core/governance'
import { profileManager } from '../stores'

export function deregisterParticipationEvent(eventId: EventId): Promise<void> {
const manager = get(profileManager)
removeProposalState(eventId)
return manager.deregisterParticipationEvent(eventId)
}
@@ -0,0 +1,8 @@
import { get } from 'svelte/store'
import { EventStatus, EventId } from '@iota/wallet'
import { profileManager } from '../stores'

export function getVotingProposalState(eventId: EventId): Promise<EventStatus> {
const manager = get(profileManager)
return manager.getParticipationEventStatus(eventId)
}
1 change: 1 addition & 0 deletions packages/shared/lib/core/profile-manager/api/index.ts
Expand Up @@ -11,6 +11,7 @@ export * from './getLedgerNanoStatus'
export * from './getNodeInfo'
export * from './getVotingProposals'
export * from './getVotingProposal'
export * from './getVotingProposalState'
export * from './isStrongholdUnlocked'
export * from './recoverAccounts'
export * from './registerParticipationEvent'
Expand Down
@@ -1,8 +1,11 @@
import { addProposalState } from '@core/governance'
import { profileManager } from '@core/profile-manager/stores'
import type { Event, EventId, Node } from '@iota/wallet'
import { get } from 'svelte/store'

export function registerParticipationEvent(eventId: EventId, nodes: Node[]): Promise<Event> {
export async function registerParticipationEvent(eventId: EventId, nodes: Node[]): Promise<Event> {
const manager = get(profileManager)
return manager.registerParticipationEvent(eventId, nodes)
const event = await manager.registerParticipationEvent(eventId, nodes)
await addProposalState(eventId)
return event
}
Expand Up @@ -9,6 +9,7 @@ import type {
Node,
NodeInfoWrapper,
WalletEvent,
EventStatus,
} from '@iota/wallet'

import { IAuth } from '@core/network'
Expand Down Expand Up @@ -40,6 +41,7 @@ export interface IProfileManager {
getLedgerNanoStatus(): Promise<LedgerNanoStatus>
getParticipationEvent(eventId: EventId): Promise<Event>
getParticipationEvents(): Promise<Event[]>
getParticipationEventStatus(eventId: EventId): Promise<EventStatus>
hexToBech32(hex: string, bech32Hrp?: string): Promise<string>
isStrongholdPasswordAvailable(): Promise<boolean>
listen(eventTypes: EventType[], callback: WalletApiEventHandler): void
Expand Down
@@ -1,5 +1,6 @@
import { closePopup } from '@auxiliary/popup'
import { resetSelectedAccount } from '@core/account'
import { clearPollProposalsStateInterval } from '@core/governance'
import { isPollingLedgerDeviceStatus, stopPollingLedgerNanoStatus } from '@core/ledger'
import { clearPollMarketPrices } from '@core/market/actions'
import { clearPollNetworkInterval } from '@core/network'
Expand Down Expand Up @@ -33,6 +34,7 @@ export function logout(clearActiveProfile: boolean = true, _lockStronghold: bool

clearPollNetworkInterval()
clearPollMarketPrices()
clearPollProposalsStateInterval()
const _activeProfile = get(activeProfile)
if (_activeProfile) {
const manager = get(profileManager)
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/lib/tests/__mocks__/profile-manager.mock.ts
Expand Up @@ -12,6 +12,7 @@ import type {
Event,
Node,
EventId,
EventStatus,
} from '@iota/wallet'

import { IAccount } from '@core/account'
Expand Down Expand Up @@ -160,6 +161,10 @@ export class ProfileManagerMock implements IProfileManager {
throw new Error('Method not implemented.')
}

getParticipationEventStatus(eventId: EventId): Promise<EventStatus> {
throw new Error('Method not implemented.')
}

hexToBech32(hex: string, bech32Hrp?: string): Promise<string> {
throw new Error('Method not implemented.')
}
Expand Down
16 changes: 8 additions & 8 deletions packages/shared/locales/en.json
Expand Up @@ -583,10 +583,10 @@
"successRemove": "Proposal successfully removed"
},
"statusTimeline": {
"announcement": "Announcement",
"votingOpen": "Voting open",
"counting": "Counting starts",
"closed": "Counting stops"
"upcoming": "Announcement",
"commencing": "Voting open",
"holding": "Counting starts",
"ended": "Counting stops"
},
"details": {
"fullProposal": "Read the full proposal",
Expand Down Expand Up @@ -1983,10 +1983,10 @@
"locked": "locked",
"smartContract": "smart contract",
"proposalStatus": {
"announcement": "Announcement",
"votingOpen": "Voting open",
"counting": "Counting",
"closed": "Closed"
"upcoming": "Announcement",
"commencing": "Voting open",
"holding": "Counting",
"ended": "Closed"
}
},
"menus": {
Expand Down