Skip to content

Commit

Permalink
🚀 Release patch 2.5.0 (#4760)
Browse files Browse the repository at this point in the history
  • Loading branch information
thesan authored Feb 5, 2024
2 parents 8efdfa5 + 42b9983 commit cd5a6a2
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 22 deletions.
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.5.0] - 2024-02-05

### Added
- Cancel proposal button.

### Changed
- Display weekly opening rewards instead of daily.

## [2.4.2] - 2024-01-29

### Fixed
- Fix infinite proposal page reload for CMs.

## [2.4.1] - 2024-01-29

### Fixed
Expand Down Expand Up @@ -292,7 +305,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.1.1] - 2022-12-02

[unreleased]: https://github.com/Joystream/pioneer/compare/v2.4.1...HEAD
[unreleased]: https://github.com/Joystream/pioneer/compare/v2.5.0...HEAD
[2.5.0]: https://github.com/Joystream/pioneer/compare/v2.4.2...v2.5.0
[2.4.2]: https://github.com/Joystream/pioneer/compare/v2.4.1...v2.4.2
[2.4.1]: https://github.com/Joystream/pioneer/compare/v2.4.0...v2.4.1
[2.4.0]: https://github.com/Joystream/pioneer/compare/v2.3.1...v2.4.0
[2.3.1]: https://github.com/Joystream/pioneer/compare/v2.3.0...v2.3.1
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@joystream/pioneer",
"version": "2.4.1",
"version": "2.5.0",
"license": "GPL-3.0-only",
"scripts": {
"build": "node --max_old_space_size=4096 ./build.js",
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/app/GlobalModals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { SwitchMemberModal, SwitchMemberModalCall } from '@/memberships/modals/S
import { TransferInviteModal, TransferInvitesModalCall } from '@/memberships/modals/TransferInviteModal'
import { UpdateMembershipModal, UpdateMembershipModalCall } from '@/memberships/modals/UpdateMembershipModal'
import { AddNewProposalModal, AddNewProposalModalCall } from '@/proposals/modals/AddNewProposal'
import { CancelProposalModal, CancelProposalModalCall } from '@/proposals/modals/CancelProposal'
import { VoteForProposalModal, VoteForProposalModalCall } from '@/proposals/modals/VoteForProposal'
import { VoteRationaleModalCall } from '@/proposals/modals/VoteRationale/types'
import { VoteRationale } from '@/proposals/modals/VoteRationale/VoteRationale'
Expand Down Expand Up @@ -133,6 +134,7 @@ export type ModalNames =
| ModalName<EmailSubscriptionModalCall>
| ModalName<EmailConfirmationModalCall>
| ModalName<NominatingRedirectModalCall>
| ModalName<CancelProposalModalCall>

const modals: Record<ModalNames, ReactElement> = {
Member: <MemberProfile />,
Expand Down Expand Up @@ -186,6 +188,7 @@ const modals: Record<ModalNames, ReactElement> = {
EmailSubscriptionModal: <EmailSubscriptionModal />,
EmailConfirmationModal: <EmailConfirmationModal />,
NominatingRedirect: <NominatingRedirectModal />,
CancelProposalModal: <CancelProposalModal />,
}

const GUEST_ACCESSIBLE_MODALS: ModalNames[] = [
Expand Down
37 changes: 37 additions & 0 deletions packages/ui/src/app/pages/Proposals/ProposalPreview.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Args = {
vote2: VoteArg
vote3: VoteArg
onVote: jest.Mock
onCancel: jest.Mock
}
type Story = StoryObj<FC<Args>>

Expand All @@ -65,6 +66,7 @@ export default {
vote2: { control: { type: 'inline-radio' }, options: voteArgs },
vote3: { control: { type: 'inline-radio' }, options: voteArgs },
onVote: { action: 'ProposalsEngine.Voted' },
onCancel: { action: 'ProposalsEngine.Cancelled' },
},

args: {
Expand Down Expand Up @@ -142,6 +144,11 @@ export default {
onSend: args.onVote,
failure: parameters.txFailure,
},
cancelProposal: {
event: 'Cancelled',
onSend: args.onCancel,
failure: parameters.txFailure,
},
},
},
},
Expand Down Expand Up @@ -608,3 +615,33 @@ export const TestVoteTxFailure: Story = {
expect(await modal.findByText('Some error message'))
},
}

export const TestCancelProposalHappy: Story = {
args: { type: 'SignalProposalDetails', isCouncilMember: false, isProposer: true },

name: 'Test CancelProposal Happy',

play: async ({ canvasElement, step, args: { onCancel } }) => {
const activeMember = member('alice')

const screen = within(canvasElement)
const modal = withinModal(canvasElement)

await step('Cancel', async () => {
await userEvent.click(screen.getByText('Cancel Proposal'))

await step('Sign', async () => {
expect(await modal.findByText('Authorize transaction'))
expect(modal.getByText('You intend to cancel your proposal.'))

await userEvent.click(modal.getByText(/^Sign And Cancel Proposal/))
})

await step('Confirm', async () => {
expect(await modal.findByText('Your propsal has been cancelled.'))

expect(onCancel).toHaveBeenLastCalledWith(activeMember.id, PROPOSAL_DATA.id)
})
})
},
}
6 changes: 6 additions & 0 deletions packages/ui/src/app/pages/Proposals/ProposalPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { getUrl } from '@/common/utils/getUrl'
import { useElectedCouncil } from '@/council/hooks/useElectedCouncil'
import { MemberInfo } from '@/memberships/components'
import { useMyMemberships } from '@/memberships/hooks/useMyMemberships'
import { CancelProposalButton } from '@/proposals/components/CancelProposalButton'
import { ProposalDetails } from '@/proposals/components/ProposalDetails/ProposalDetails'
import { ProposalDiscussions } from '@/proposals/components/ProposalDiscussions'
import { ProposalHistory } from '@/proposals/components/ProposalHistory'
Expand Down Expand Up @@ -117,6 +118,11 @@ export const ProposalPreview = () => {
<PageTitle>{proposal.title}</PageTitle>
</PreviousPage>
<ButtonsGroup>
{active?.id === proposal.proposer.id &&
proposal.votes.length === 0 &&
(proposal.status === 'deciding' || proposal.status === 'dormant') && (
<CancelProposalButton member={active} proposalId={proposal.id} />
)}
{active?.isCouncilMember &&
proposal.status === 'deciding' &&
(!hasVoted ? (
Expand Down
8 changes: 2 additions & 6 deletions packages/ui/src/app/pages/WorkingGroups/UpcomingOpening.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ import { NumericValueStat } from '@/common/components/statistics/NumericValueSta
import { TextSmall } from '@/common/components/typography'
import { ApplicationStatusWrapper } from '@/working-groups/components/ApplicationStatusWrapper'
import { OpeningIcon } from '@/working-groups/components/OpeningIcon'
import { useRewardPeriod } from '@/working-groups/hooks/useRewardPeriod'
import { useUpcomingOpening } from '@/working-groups/hooks/useUpcomingOpening'
import { asWeeklyRewards } from '@/working-groups/model/asWeeklyRewards'

export const UpcomingOpening = () => {
const { id } = useParams<{ id: string }>()
const { isLoading, opening } = useUpcomingOpening(id)
const rewardPeriod = useRewardPeriod(opening?.groupId)

if (isLoading || !opening) {
return (
Expand Down Expand Up @@ -82,10 +81,7 @@ export const UpcomingOpening = () => {
value={opening.expectedEnding}
from={opening.expectedStart}
/>
<TokenValueStat
title={`Reward per ${rewardPeriod?.toString()} blocks`}
value={rewardPeriod?.mul(opening.rewardPerBlock)}
/>
<TokenValueStat title={'Reward per week'} value={asWeeklyRewards(opening.rewardPerBlock)} />
{opening.hiringLimit ? (
<NumericValueStat title="Hiring limit" value={opening.hiringLimit} />
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import { ApplicationStatusWrapper } from '@/working-groups/components/Applicatio
import { OpeningIcon } from '@/working-groups/components/OpeningIcon'
import { MappedStatuses, OpeningStatuses, WorkingGroupsRoutes } from '@/working-groups/constants'
import { useOpening } from '@/working-groups/hooks/useOpening'
import { useRewardPeriod } from '@/working-groups/hooks/useRewardPeriod'
import { ApplyForRoleModalCall } from '@/working-groups/modals/ApplyForRoleModal'
import { asWeeklyRewards } from '@/working-groups/model/asWeeklyRewards'
import { urlParamToOpeningId } from '@/working-groups/model/workingGroupName'
import { WorkingGroupOpening as WorkingGroupOpeningType } from '@/working-groups/types'

Expand All @@ -62,7 +62,6 @@ export const WorkingGroupOpening = () => {
return activeApplications.find(({ id }) => id === activeMembership?.id)
}
}, [opening?.id, activeMembership?.id])
const rewardPeriod = useRewardPeriod(opening?.groupId)

if (isLoading || !opening) {
return (
Expand Down Expand Up @@ -150,10 +149,7 @@ export const WorkingGroupOpening = () => {
</BadgesRow>
<StatisticsStyle>
<DurationStatistics title="Time Left" value={opening.expectedEnding} />
<TokenValueStat
title={`Reward per ${rewardPeriod?.toString()} blocks`}
value={rewardPeriod?.mul(opening.rewardPerBlock)}
/>
<TokenValueStat title={'Reward per week'} value={asWeeklyRewards(opening.rewardPerBlock)} />
<TokenValueStat
title="Minimal stake"
tooltipText="Minimum tokens free of rivalrous locks required as application stake to this role."
Expand Down
27 changes: 27 additions & 0 deletions packages/ui/src/proposals/components/CancelProposalButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useCallback } from 'react'

import { ButtonSecondary } from '@/common/components/buttons'
import { useModal } from '@/common/hooks/useModal'
import { Member } from '@/memberships/types'

import { CancelProposalModalCall } from '../modals/CancelProposal'

interface Props {
member: Member
proposalId: string
}

export const CancelProposalButton = ({ member, proposalId }: Props) => {
const { showModal } = useModal()
const cancelProposalModal = useCallback(() => {
showModal<CancelProposalModalCall>({
modal: 'CancelProposalModal',
data: { member, proposalId },
})
}, [])
return (
<ButtonSecondary onClick={cancelProposalModal} size="medium">
Cancel Proposal
</ButtonSecondary>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useEffect, useMemo } from 'react'

import { useTransactionFee } from '@/accounts/hooks/useTransactionFee'
import { InsufficientFundsModal } from '@/accounts/modals/InsufficientFundsModal'
import { useApi } from '@/api/hooks/useApi'
import { TextMedium } from '@/common/components/typography'
import { useMachine } from '@/common/hooks/useMachine'
import { useModal } from '@/common/hooks/useModal'
import { SignTransactionModal } from '@/common/modals/SignTransactionModal/SignTransactionModal'
import { defaultTransactionModalMachine } from '@/common/model/machines/defaultTransactionModalMachine'

import { CancelProposalModalCall } from './types'

export const CancelProposalModal = () => {
const { hideModal, modalData } = useModal<CancelProposalModalCall>()
const { member, proposalId } = modalData
const machine = useMemo(
() =>
defaultTransactionModalMachine(
'There was a problem cancelling your proposal.',
'Your propsal has been cancelled.'
),
[]
)
const [state, send] = useMachine(machine, { context: { validateBeforeTransaction: true } })
const { api, isConnected } = useApi()

const { transaction, feeInfo } = useTransactionFee(
member.controllerAccount,
() => {
if (api && isConnected) {
return api.tx.proposalsEngine.cancelProposal(member.id, proposalId)
}
},
[modalData, isConnected]
)

useEffect(() => {
if (state.matches('requirementsVerification')) {
if (transaction && feeInfo) {
feeInfo.canAfford && send('PASS')
!feeInfo.canAfford && send('FAIL')
}
}

if (state.matches('beforeTransaction')) {
send(feeInfo?.canAfford ? 'PASS' : 'FAIL')
}
}, [state.value, member, transaction, feeInfo?.canAfford])

if (state.matches('transaction') && transaction && member) {
return (
<SignTransactionModal
buttonText="Sign And Cancel Proposal"
transaction={transaction}
signer={member.controllerAccount}
service={state.children.transaction}
>
<TextMedium>You intend to cancel your proposal.</TextMedium>
</SignTransactionModal>
)
}

if (state.matches('requirementsFailed') && member && feeInfo) {
return (
<InsufficientFundsModal onClose={hideModal} address={member.controllerAccount} amount={feeInfo.transactionFee} />
)
}
return null
}
2 changes: 2 additions & 0 deletions packages/ui/src/proposals/modals/CancelProposal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type { CancelProposalModalCall } from './types'
export * from './CancelProposalModal'
4 changes: 4 additions & 0 deletions packages/ui/src/proposals/modals/CancelProposal/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ModalWithDataCall } from '@/common/providers/modal/types'
import { Member } from '@/memberships/types'

export type CancelProposalModalCall = ModalWithDataCall<'CancelProposalModal', { member: Member; proposalId: string }>
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ import {
OpenedTop,
OpenedWrapper,
} from '@/working-groups/components/ToggleableItemStyledComponents'
import { useRewardPeriod } from '@/working-groups/hooks/useRewardPeriod'
import { ApplyForRoleModalCall } from '@/working-groups/modals/ApplyForRoleModal'
import { asWeeklyRewards } from '@/working-groups/model/asWeeklyRewards'
import { isOpeningOpen } from '@/working-groups/model/isOpeningOpen'
import { groupNameToURLParam } from '@/working-groups/model/workingGroupName'

export const OpeningDetails = ({ opening, onClick, past }: OpeningListItemProps) => {
const { showModal } = useModal()
const rewardPeriod = useRewardPeriod(opening.groupId)
const groupName = groupNameToURLParam(nameMapping(opening.groupName))
const openingRoute = `/working-groups/openings/${groupName}-${opening.runtimeId}`

Expand All @@ -42,9 +41,9 @@ export const OpeningDetails = ({ opening, onClick, past }: OpeningListItemProps)
<StatisticsStyle withMargin>
<StatsBlock size="m" centered>
<TextBig>
<TokenValue value={rewardPeriod?.mul(opening.rewardPerBlock)} />
<TokenValue value={asWeeklyRewards(opening.rewardPerBlock)} />
</TextBig>
<Subscription>Reward per {rewardPeriod?.toString()} blocks</Subscription>
<Subscription>Reward per week</Subscription>
</StatsBlock>
<StatsBlock size="m" centered>
<MultiColumnsStatistic>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
ToggleableItemWrap,
OpenItemSummaryColumn,
} from '@/working-groups/components/ToggleableItemStyledComponents'
import { useRewardPeriod } from '@/working-groups/hooks/useRewardPeriod'
import { asWeeklyRewards } from '@/working-groups/model/asWeeklyRewards'
import { WorkingGroupOpening } from '@/working-groups/types'

export type OpeningListItemProps = {
Expand All @@ -25,7 +25,6 @@ export type OpeningListItemProps = {
}

export const OpeningListItem = ({ opening, past, onClick }: OpeningListItemProps) => {
const rewardPeriod = useRewardPeriod(opening.groupId)
const hiringTarget = opening.hiring.limit || 1

return (
Expand All @@ -44,9 +43,9 @@ export const OpeningListItem = ({ opening, past, onClick }: OpeningListItemProps
<ToggleableItemSummary>
<OpenItemSummaryColumn>
<TextInlineBig>
<TokenValue value={rewardPeriod?.mul(opening.rewardPerBlock)} />
<TokenValue value={asWeeklyRewards(opening.rewardPerBlock)} />
</TextInlineBig>
<ToggleableSubscriptionWide>Reward per {rewardPeriod?.toString()} blocks.</ToggleableSubscriptionWide>
<ToggleableSubscriptionWide>Reward per week.</ToggleableSubscriptionWide>
</OpenItemSummaryColumn>
<OpenItemSummaryColumn>
<TextBig>{opening.applicants}</TextBig>
Expand Down
9 changes: 9 additions & 0 deletions packages/ui/src/working-groups/model/asWeeklyRewards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import BN from 'bn.js'

import { A_WEEK } from '@/common/constants'
import { MILLISECONDS_PER_BLOCK } from '@/common/model/formatters'

export const asWeeklyRewards = (rewardPerBlock: BN) => {
const BLOCKS_PER_WEEK = A_WEEK / MILLISECONDS_PER_BLOCK
return rewardPerBlock.muln(BLOCKS_PER_WEEK)
}

0 comments on commit cd5a6a2

Please sign in to comment.