From b4c99d8ea735bb21869d0f4b6a700cd4dee2465a Mon Sep 17 00:00:00 2001 From: Niranjan Ramadas Date: Tue, 7 Feb 2023 10:18:22 -0600 Subject: [PATCH] Add a form to edit wallet rules (#1345) --- actions/createProposal.ts | 5 +- .../WalletDetails/Info/Rules/index.tsx | 40 +- hooks/useTreasuryInfo/getRulesFromAccount.ts | 1 + hub/.eslintrc.json | 18 +- hub/App.tsx | 25 +- hub/components/AuthorAvatar/index.tsx | 2 + .../DiscoverPage/NotableNFTs/index.tsx | 2 - .../Sidebar/Announcements/Post/index.tsx | 1 - hub/components/EditDiscoverPage/index.tsx | 4 +- .../EditMetadata/EditForms/FAQ/index.tsx | 1 + .../EditMetadata/EditForms/Gallery/index.tsx | 5 +- .../EditMetadata/EditForms/Overview/index.tsx | 2 + .../EditMetadata/EditForms/Roadmap/index.tsx | 1 + .../EditMetadata/EditForms/Team/index.tsx | 1 + .../EditMetadata/EditForms/index.tsx | 3 + .../EditWalletRules/AdvancedOptions/index.tsx | 66 ++ .../CommunityDetails/index.tsx | 362 +++++++++++ .../EditWalletRules/CouncilDetails/index.tsx | 406 +++++++++++++ hub/components/EditWalletRules/Form/index.tsx | 163 +++++ .../EditWalletRules/ProposalDetails/index.tsx | 52 ++ .../ProposalVoteType/index.tsx | 170 ++++++ .../EditWalletRules/SectionBlock/index.tsx | 16 + .../EditWalletRules/SectionHeader/index.tsx | 28 + .../EditWalletRules/SliderValue/index.tsx | 54 ++ .../EditWalletRules/Summary/index.tsx | 95 +++ .../EditWalletRules/SummaryItem/index.tsx | 23 + .../EditWalletRules/UpdatesList/index.tsx | 575 ++++++++++++++++++ .../EditWalletRules/ValueBlock/index.tsx | 19 + .../ValueDescription/index.tsx | 14 + .../EditWalletRules/ValueLabel/index.tsx | 14 + .../VoteTippingSelector/index.tsx | 119 ++++ .../EditWalletRules/VotingDuration/index.tsx | 161 +++++ .../WalletDescription/index.tsx | 43 ++ hub/components/EditWalletRules/constants.ts | 3 + .../EditWalletRules/createTransaction.ts | 119 ++++ hub/components/EditWalletRules/gql.ts | 92 +++ hub/components/EditWalletRules/index.tsx | 384 ++++++++++++ hub/components/EditWalletRules/types.ts | 9 + hub/components/GlobalHeader/Links/index.tsx | 2 + .../GlobalHeader/LinksDropdown/index.tsx | 6 + hub/components/GlobalHeader/MinimalHeader.tsx | 6 +- hub/components/GlobalHeader/User/Connect.tsx | 6 +- .../DialectNotifications.tsx | 2 - .../Notifications.constants.ts | 26 +- .../solanaWalletToDialectWallet.ts | 2 +- .../GlobalHeader/User/DropdownButton.tsx | 6 + .../GlobalHeader/User/UserDropdown.tsx | 7 +- hub/components/GlobalHeader/index.tsx | 6 +- .../Home/Feed/AdditionalPage/index.tsx | 1 - .../Hub/SideCard/Bounties/index.tsx | 2 - hub/components/MyFeed/Page/index.tsx | 1 - hub/components/NewPostEditor/index.tsx | 1 + .../ProposalCreationProgress/index.tsx | 96 +++ hub/components/RealmIcon/index.tsx | 2 + .../RealmSearchNavigation/index.tsx | 33 +- .../ImageNode/index.tsx | 1 + hub/components/branding/RealmsLogo.tsx | 12 +- hub/components/controls/Button/Primary.tsx | 4 + hub/components/controls/Button/PrimaryAlt.tsx | 68 +++ hub/components/controls/Button/Secondary.tsx | 4 + .../controls/Button/SecondaryAlt.tsx | 73 +++ hub/components/controls/Button/index.tsx | 2 + .../controls/ButtonToggle/index.tsx | 65 ++ .../controls/CopyAddressButton/index.tsx | 38 ++ hub/components/controls/Input/index.tsx | 6 + hub/components/controls/Slider/index.tsx | 81 +++ hub/components/controls/Textarea/index.tsx | 4 + hub/hooks/useCachedValue.ts | 1 + hub/hooks/useProposal.ts | 7 + hub/hooks/useProposalCreationProgress.ts | 101 +++ hub/hooks/useWallet.ts | 18 +- hub/providers/Cluster/index.tsx | 19 +- hub/providers/GraphQL/exchanges/auth.ts | 71 ++- hub/providers/GraphQL/exchanges/graphcache.ts | 2 + hub/providers/Proposal/createProposal.ts | 263 ++++++++ hub/providers/Proposal/fetchPlugins.ts | 43 ++ hub/providers/Proposal/index.tsx | 94 +++ hub/providers/Root.tsx | 5 +- hub/providers/Toast/index.tsx | 12 +- hub/providers/Wallet/index.tsx | 14 +- hub/providers/WalletSelector/index.tsx | 15 +- hub/types/FormCallbacks.ts | 5 + hub/types/FormProps.ts | 3 + hub/types/GovernanceTokenType.ts | 4 + hub/types/GovernanceVoteTipping.ts | 5 + hub/types/decoders/GovernanceTokenType.ts | 15 + hub/types/decoders/GovernanceVoteTipping.ts | 19 + models/treasury/Wallet.ts | 1 + package.json | 1 + pages/_app.tsx | 3 +- .../governance/[governanceId]/edit/index.tsx | 43 ++ tailwind.config.js | 1 + yarn.lock | 18 + 93 files changed, 4369 insertions(+), 75 deletions(-) create mode 100644 hub/components/EditWalletRules/AdvancedOptions/index.tsx create mode 100644 hub/components/EditWalletRules/CommunityDetails/index.tsx create mode 100644 hub/components/EditWalletRules/CouncilDetails/index.tsx create mode 100644 hub/components/EditWalletRules/Form/index.tsx create mode 100644 hub/components/EditWalletRules/ProposalDetails/index.tsx create mode 100644 hub/components/EditWalletRules/ProposalVoteType/index.tsx create mode 100644 hub/components/EditWalletRules/SectionBlock/index.tsx create mode 100644 hub/components/EditWalletRules/SectionHeader/index.tsx create mode 100644 hub/components/EditWalletRules/SliderValue/index.tsx create mode 100644 hub/components/EditWalletRules/Summary/index.tsx create mode 100644 hub/components/EditWalletRules/SummaryItem/index.tsx create mode 100644 hub/components/EditWalletRules/UpdatesList/index.tsx create mode 100644 hub/components/EditWalletRules/ValueBlock/index.tsx create mode 100644 hub/components/EditWalletRules/ValueDescription/index.tsx create mode 100644 hub/components/EditWalletRules/ValueLabel/index.tsx create mode 100644 hub/components/EditWalletRules/VoteTippingSelector/index.tsx create mode 100644 hub/components/EditWalletRules/VotingDuration/index.tsx create mode 100644 hub/components/EditWalletRules/WalletDescription/index.tsx create mode 100644 hub/components/EditWalletRules/constants.ts create mode 100644 hub/components/EditWalletRules/createTransaction.ts create mode 100644 hub/components/EditWalletRules/gql.ts create mode 100644 hub/components/EditWalletRules/index.tsx create mode 100644 hub/components/EditWalletRules/types.ts create mode 100644 hub/components/ProposalCreationProgress/index.tsx create mode 100644 hub/components/controls/Button/PrimaryAlt.tsx create mode 100644 hub/components/controls/Button/SecondaryAlt.tsx create mode 100644 hub/components/controls/ButtonToggle/index.tsx create mode 100644 hub/components/controls/CopyAddressButton/index.tsx create mode 100644 hub/components/controls/Slider/index.tsx create mode 100644 hub/hooks/useProposal.ts create mode 100644 hub/hooks/useProposalCreationProgress.ts create mode 100644 hub/providers/Proposal/createProposal.ts create mode 100644 hub/providers/Proposal/fetchPlugins.ts create mode 100644 hub/providers/Proposal/index.tsx create mode 100644 hub/types/FormCallbacks.ts create mode 100644 hub/types/FormProps.ts create mode 100644 hub/types/GovernanceTokenType.ts create mode 100644 hub/types/GovernanceVoteTipping.ts create mode 100644 hub/types/decoders/GovernanceTokenType.ts create mode 100644 hub/types/decoders/GovernanceVoteTipping.ts create mode 100644 pages/realm/[id]/governance/[governanceId]/edit/index.tsx diff --git a/actions/createProposal.ts b/actions/createProposal.ts index ad0818fe7d..4a71abf9d5 100644 --- a/actions/createProposal.ts +++ b/actions/createProposal.ts @@ -71,7 +71,8 @@ export const createProposal = async ( proposalIndex: number, instructionsData: InstructionDataWithHoldUpTime[], isDraft: boolean, - client?: VotingClient + client?: VotingClient, + callbacks?: Parameters[0]['callbacks'] ): Promise => { const instructions: TransactionInstruction[] = [] @@ -227,6 +228,7 @@ export const createProposal = async ( }) await sendTransactionsV3({ + callbacks, connection, wallet, transactionInstructions: txes, @@ -279,6 +281,7 @@ export const createProposal = async ( }) await sendTransactionsV3({ + callbacks, connection, wallet, transactionInstructions: txes, diff --git a/components/treasuryV2/Details/WalletDetails/Info/Rules/index.tsx b/components/treasuryV2/Details/WalletDetails/Info/Rules/index.tsx index 2a7b32cb97..aa022f2933 100644 --- a/components/treasuryV2/Details/WalletDetails/Info/Rules/index.tsx +++ b/components/treasuryV2/Details/WalletDetails/Info/Rules/index.tsx @@ -12,6 +12,7 @@ import { VoteTipping } from '@solana/spl-governance' import cx from 'classnames' import React, { useState } from 'react' import { BigNumber } from 'bignumber.js' +import { useRouter } from 'next/router' import { formatNumber } from '@utils/formatNumber' import { ntext } from '@utils/ntext' @@ -21,6 +22,7 @@ import useRealm from '@hooks/useRealm' import Tooltip from '@components/Tooltip' import { DISABLED_VOTER_WEIGHT } from '@tools/constants' import Address from '@components/Address' +import useQueryContext from '@hooks/useQueryContext' import Section from '../../../Section' import TokenIcon from '../../../../icons/TokenIcon' @@ -66,6 +68,17 @@ export function durationStr(duration: number, short = false) { return count + (short ? 's' : ' ' + ntext(count, 'second')) } +function votingLengthText(time: number) { + const hours = time / UNIX_HOUR + const days = Math.floor(hours / 24) + const remainingHours = (time - days * UNIX_DAY) / UNIX_HOUR + + return ( + durationStr(days * UNIX_DAY) + + (remainingHours ? ` ${durationStr(remainingHours * UNIX_HOUR)}` : '') + ) +} + interface Props { className?: string wallet: Wallet @@ -73,7 +86,9 @@ interface Props { export default function Rules(props: Props) { const [editRulesOpen, setEditRulesOpen] = useState(false) - const { ownVoterWeight } = useRealm() + const { ownVoterWeight, symbol } = useRealm() + const router = useRouter() + const { fmtUrlWithCluster } = useQueryContext() const programVersion = useProgramVersion() @@ -123,7 +138,15 @@ export default function Rules(props: Props) { 'disabled:opacity-50' )} disabled={!canEditRules} - onClick={() => setEditRulesOpen(true)} + onClick={() => { + if (props.wallet.governanceAccount) { + router.push( + fmtUrlWithCluster( + `/realm/${symbol}/governance/${props.wallet.governanceAccount.pubkey.toBase58()}/edit` + ) + ) + } + }} >
Edit Rules
@@ -138,8 +161,17 @@ export default function Rules(props: Props) {
} - name="Max Voting Time" - value={durationStr(props.wallet.rules.common.maxVotingTime)} + name="Unrestricted Voting Time" + value={votingLengthText( + props.wallet.rules.common.maxVotingTime + )} + /> +
} + name="Voting Cool-Off Time" + value={durationStr( + props.wallet.rules.common.votingCoolOffSeconds + )} />
} diff --git a/hooks/useTreasuryInfo/getRulesFromAccount.ts b/hooks/useTreasuryInfo/getRulesFromAccount.ts index 5a8f046da5..4f8818f019 100644 --- a/hooks/useTreasuryInfo/getRulesFromAccount.ts +++ b/hooks/useTreasuryInfo/getRulesFromAccount.ts @@ -17,6 +17,7 @@ export function getRulesFromAccount( rules.common = { maxVotingTime: govConfig.maxVotingTime, minInstructionHoldupTime: govConfig.minInstructionHoldUpTime, + votingCoolOffSeconds: govConfig.votingCoolOffTime, } } diff --git a/hub/.eslintrc.json b/hub/.eslintrc.json index f35f06c9c1..a796cbd634 100644 --- a/hub/.eslintrc.json +++ b/hub/.eslintrc.json @@ -5,7 +5,10 @@ "tsconfigRootDir": ".", "sourceType": "module" }, - "plugins": ["@typescript-eslint/eslint-plugin", "import"], + "plugins": [ + "@typescript-eslint/eslint-plugin", + "import" + ], "extends": [ "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended" @@ -15,7 +18,10 @@ "node": true, "jest": true }, - "ignorePatterns": [".eslintrc.js", "migrations"], + "ignorePatterns": [ + ".eslintrc.js", + "migrations" + ], "rules": { "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/explicit-function-return-type": "off", @@ -27,7 +33,9 @@ "error", { "newlines-between": "always-and-inside-groups", - "pathGroupsExcludedImportTypes": ["builtin"], + "pathGroupsExcludedImportTypes": [ + "builtin" + ], "pathGroups": [ { "pattern": "@hub/**/**", @@ -52,6 +60,10 @@ { "pattern": "@verify-wallet/**/**", "group": "parent" + }, + { + "pattern": "@hooks/**/**", + "group": "parent" } ], "alphabetize": { diff --git a/hub/App.tsx b/hub/App.tsx index ad09290645..b3e730f218 100644 --- a/hub/App.tsx +++ b/hub/App.tsx @@ -1,6 +1,7 @@ import Head from 'next/head'; +import { useRouter } from 'next/router'; import Script from 'next/script'; -import React from 'react'; +import React, { useEffect } from 'react'; import { GlobalHeader } from '@hub/components/GlobalHeader'; import { MinimalHeader } from '@hub/components/GlobalHeader/MinimalHeader'; @@ -56,9 +57,31 @@ interface Props { } export function App(props: Props) { + const router = useRouter(); + const isDarkMode = router.pathname.startsWith('/realm/[id]/governance'); + + useEffect(() => { + if (isDarkMode) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }, [isDarkMode]); + return ( + {isDarkMode && ( +