Skip to content

Commit

Permalink
Voting: Multiple transaction steps (#1152)
Browse files Browse the repository at this point in the history
  • Loading branch information
delfipolito authored and ßingen committed Jun 15, 2020
1 parent 37b7189 commit 95f09f5
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 79 deletions.
130 changes: 130 additions & 0 deletions apps/voting/app/src/components/DetailedDescription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React, { useMemo } from 'react'
import { GU, useTheme } from '@aragon/ui'
import LocalIdentityBadge from './LocalIdentityBadge/LocalIdentityBadge'

function DetailedDescription({ path }) {
return (
<div
css={`
// overflow-wrap:anywhere and hyphens:auto are not supported yet by
// the latest versions of Safari (as of June 2020), which
// is why word-break:break-word has been added here.
hyphens: auto;
overflow-wrap: anywhere;
word-break: break-word;
`}
>
{path
? path.map((step, index) => <DescriptionStep key={index} step={step} />)
: ''}
</div>
)
}

function DescriptionStep({ step }) {
const theme = useTheme()

const description = []

const appName =
step.name && step.identifier
? `${step.name} (${step.identifier})`
: step.name || step.identifier

// Add app
description.push(
<React.Fragment key={0}>
{appName || (
<LocalIdentityBadge
compact
entity={step.to}
css={`
padding-right: 0;
`}
/>
)}
<span>:</span>
</React.Fragment>
)

if (step.annotatedDescription) {
description.push(
step.annotatedDescription.map(({ type, value }, index) => {
// The app has already been pushed as the first element, so we increment the index by 1 for
// these keys
const key = index + 1

if (type === 'address' || type === 'any-account') {
return (
<span key={key}>
{' '}
<LocalIdentityBadge
compact
entity={type === 'any-account' ? 'Any account' : value}
/>
</span>
)
}

if (type === 'role' || type === 'kernelNamespace' || type === 'app') {
return <span key={key}>{value.name}</span>
}

if (type === 'apmPackage') {
return <span key={key}>{value.appName}</span>
}

return <span key={key}> {value.description || value}</span>
})
)
} else {
description.push(
<span key={description.length + 1}>
{step.description || 'No description'}
</span>
)
}
description.push(<br key={description.lenth + 1} />)

const childrenDescriptions = (step.children || []).map((child, index) => {
return <DescriptionStep step={child} key={index} />
})

return (
<React.Fragment>
<span>{description}</span>
{childrenDescriptions.length > 0 && (
<ul
css={`
list-style-type: none;
margin-left: 0;
padding-left: ${0.5 * GU}px;
text-indent: -${0.5 * GU}px;
`}
>
<li
css={`
padding-left: ${2 * GU}px;
&:before {
content: '';
width: ${0.5 * GU}px;
height: ${0.5 * GU}px;
background: ${theme.accent};
border-radius: 50%;
display: inline-block;
}
span {
display: inline;
color: ${theme.surfaceContentSecondary};
}
`}
>
{childrenDescriptions}
</li>
</ul>
)}
</React.Fragment>
)
}

export default DetailedDescription
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import { useNetwork } from '@aragon/api-react'
import { IdentityBadge } from '@aragon/ui'
import { useIdentity } from '../IdentityManager/IdentityManager'
import { useIdentity } from '../../identity-manager'
import LocalLabelPopoverTitle from './LocalLabelPopoverTitle'
import LocalLabelPopoverActionLabel from './LocalLabelPopoverActionLabel'

Expand Down
6 changes: 3 additions & 3 deletions apps/voting/app/src/components/VoteCard/VoteCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import LocalLabelAppBadge from '..//LocalIdentityBadge/LocalLabelAppBadge'
import VoteOptions from './VoteOptions'
import VotedIndicator from './VotedIndicator'
import VoteStatus from '../VoteStatus'
import VoteText from '../VoteText'
import VoteDescription from '../VoteDescription'
import You from '../You'

function VoteCard({ vote, onOpen }) {
Expand Down Expand Up @@ -89,10 +89,10 @@ function VoteCard({ vote, onOpen }) {
)}
{hasConnectedAccountVoted && <VotedIndicator expand={highlighted} />}
</div>
<VoteText
<VoteDescription
disabled
prefix={<span css="font-weight: bold">#{voteId}: </span>}
text={description || metadata}
description={description || metadata}
title={`#${voteId}: ${description || metadata}`}
css={`
overflow: hidden;
Expand Down
52 changes: 52 additions & 0 deletions apps/voting/app/src/components/VoteDescription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react'
import PropTypes from 'prop-types'
import AutoLink from '../components/AutoLink'

// Render a description associated to a vote.
// Usually vote.data.metadata and vote.data.description.
const VoteDescription = React.memo(function VoteDescription({
disabled,
description,
prefix,
...props
}) {
// If there is no description, the component doesn’t render anything.
if (!description) {
return null
}

return (
<div
{...props}
css={`
// overflow-wrap:anywhere and hyphens:auto are not supported yet by
// the latest versions of Safari (as of June 2020), which
// is why word-break:break-word has been added here.
hyphens: auto;
overflow-wrap: anywhere;
word-break: break-word;
`}
>
{prefix}
{disabled ? (
<span>{description}</span>
) : (
<AutoLink>
<span>{description}</span>
</AutoLink>
)}
</div>
)
})

VoteDescription.propTypes = {
description: PropTypes.node,
disabled: PropTypes.bool,
prefix: PropTypes.node,
}

VoteDescription.defaultProps = {
description: '',
}

export default VoteDescription
65 changes: 0 additions & 65 deletions apps/voting/app/src/components/VoteText.js

This file was deleted.

18 changes: 11 additions & 7 deletions apps/voting/app/src/screens/VoteDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import {
} from '@aragon/ui'
import { useAppState, useConnectedAccount, useNetwork } from '@aragon/api-react'
import { format } from 'date-fns'
import DetailedDescription from '../components/DetailedDescription'
import LocalIdentityBadge from '../components/LocalIdentityBadge/LocalIdentityBadge'
import LocalLabelAppBadge from '../components/LocalIdentityBadge/LocalLabelAppBadge'
import SummaryBar from '../components/SummaryBar'
import SummaryRows from '../components/SummaryRows'
import VoteActions from '../components/VoteActions'
import VoteCast from '../components/VoteCast'
import VoteDescription from '../components/VoteDescription'
import VoteStatus from '../components/VoteStatus'
import VoteText from '../components/VoteText'
import { percentageList, round, safeDiv } from '../math-utils'
import { getQuorumProgress } from '../vote-utils'
import { VOTE_NAY, VOTE_YEA } from '../vote-types'
Expand All @@ -49,7 +50,7 @@ function VoteDetail({ vote, onBack, onVote, onExecute }) {
voteId,
} = vote
const { minAcceptQuorum, supportRequired, yea, nay } = numData
const { creator, description, metadata, open } = data
const { creator, description, metadata, open, path: executionPath } = data
const quorumProgress = getQuorumProgress(vote)
const totalVotes = yea + nay
const votesYeaVotersSize = safeDiv(yea, totalVotes)
Expand Down Expand Up @@ -132,11 +133,14 @@ function VoteDetail({ vote, onBack, onVote, onExecute }) {
>
Description
</h2>
<VoteText
text={description || metadata || DEFAULT_DESCRIPTION}
css={`
${textStyle('body2')};
`}
<VoteDescription
description={
Array.isArray(executionPath) ? (
<DetailedDescription path={executionPath} />
) : (
description || metadata || DEFAULT_DESCRIPTION
)
}
/>
</div>
<div>
Expand Down
7 changes: 4 additions & 3 deletions apps/voting/app/src/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,16 +300,17 @@ async function loadVoteDescription(vote) {
}

try {
const path = await app.describeScript(vote.script).toPromise()
const path = (await app.describeScript(vote.script).toPromise()) || []

// Get unique list of targets
vote.executionTargets = [...new Set(path.map(({ to }) => to))]
vote.description = path
vote.path = path
// TODO: consider removing description as it can be rendered from the path in the frontend
vote.description = path.length
? path
.map(step => {
const identifier = step.identifier ? ` (${step.identifier})` : ''
const app = step.name ? `${step.name}${identifier}` : `${step.to}`

return `${app}: ${step.description || 'No description'}`
})
.join('\n')
Expand Down

0 comments on commit 95f09f5

Please sign in to comment.