Skip to content

Commit af77a2a

Browse files
authored
[xc-admin] improve xc-admin-frontend UI/UX (#673)
* add expired status * add proposal status filter * allow proposals to be proposed from ops key * check if ops keypair file exists * update mappings * fix UpdatePermissions * trigger deployment * fix precommit * address comments * use SECRETS_BASE_PATH * fix path * fix
1 parent cafb0eb commit af77a2a

File tree

9 files changed

+327
-104
lines changed

9 files changed

+327
-104
lines changed

governance/xc_admin/packages/xc_admin_frontend/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ next-env.d.ts
3737

3838

3939
# mappings
40-
publishers.json
40+
publishers-*.json
4141
signers.json
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Menu, Transition } from '@headlessui/react'
2+
import { useRouter } from 'next/router'
3+
import { Fragment, useCallback, useContext, useEffect } from 'react'
4+
import {
5+
DEFAULT_STATUS_FILTER,
6+
StatusFilterContext,
7+
} from '../contexts/StatusFilterContext'
8+
import Arrow from '../images/icons/down.inline.svg'
9+
10+
const ProposalStatusFilter = () => {
11+
const router = useRouter()
12+
const { statusFilter, setStatusFilter } = useContext(StatusFilterContext)
13+
14+
const handleChange = useCallback(
15+
(event: any) => {
16+
if (event.target.value) {
17+
router.query.status = event.target.value
18+
setStatusFilter(event.target.value)
19+
router.push(
20+
{
21+
pathname: router.pathname,
22+
query: router.query,
23+
},
24+
undefined,
25+
{ scroll: false }
26+
)
27+
}
28+
},
29+
[setStatusFilter, router]
30+
)
31+
32+
useEffect(() => {
33+
router.query && router.query.status
34+
? setStatusFilter(router.query.status as string)
35+
: setStatusFilter(DEFAULT_STATUS_FILTER)
36+
}, [setStatusFilter, router])
37+
38+
const statuses = [
39+
'all',
40+
'active',
41+
'executed',
42+
'executeReady',
43+
'cancelled',
44+
'rejected',
45+
'draft',
46+
'expired',
47+
]
48+
49+
return (
50+
<Menu as="div" className="relative z-[3] block w-[180px] text-left">
51+
{({ open }) => (
52+
<>
53+
<Menu.Button
54+
className={`inline-flex w-full items-center justify-between bg-darkGray2 py-3 px-6 text-sm outline-0`}
55+
>
56+
<span className="mr-3">{statusFilter}</span>
57+
<Arrow className={`${open && 'rotate-180'}`} />
58+
</Menu.Button>
59+
<Transition
60+
as={Fragment}
61+
enter="transition ease-out duration-100"
62+
enterFrom="transform opacity-0 scale-95"
63+
enterTo="transform opacity-100 scale-100"
64+
leave="transition ease-in duration-75"
65+
leaveFrom="transform opacity-100 scale-100"
66+
leaveTo="transform opacity-0 scale-95"
67+
>
68+
<Menu.Items className="absolute right-0 mt-2 w-full origin-top-right">
69+
{statuses.map((s) => (
70+
<Menu.Item key={s}>
71+
<button
72+
className={`block w-full bg-darkGray py-3 px-6 text-left text-sm hover:bg-darkGray2`}
73+
value={s}
74+
onClick={handleChange}
75+
>
76+
{s}
77+
</button>
78+
</Menu.Item>
79+
))}
80+
</Menu.Items>
81+
</Transition>
82+
</>
83+
)}
84+
</Menu>
85+
)
86+
}
87+
88+
export default ProposalStatusFilter

governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor'
1+
import { AnchorProvider, Program } from '@coral-xyz/anchor'
22
import { AccountType, getPythProgramKeyForCluster } from '@pythnetwork/client'
33
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
4-
import { useAnchorWallet, useWallet } from '@solana/wallet-adapter-react'
4+
import { useWallet } from '@solana/wallet-adapter-react'
55
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
66
import { Cluster, PublicKey, TransactionInstruction } from '@solana/web3.js'
77
import { useCallback, useContext, useEffect, useState } from 'react'
@@ -15,8 +15,9 @@ import {
1515
WORMHOLE_ADDRESS,
1616
} from 'xc_admin_common'
1717
import { ClusterContext } from '../../contexts/ClusterContext'
18+
import { useMultisigContext } from '../../contexts/MultisigContext'
1819
import { usePythContext } from '../../contexts/PythContext'
19-
import { PRICE_FEED_MULTISIG, useMultisig } from '../../hooks/useMultisig'
20+
import { PRICE_FEED_MULTISIG } from '../../hooks/useMultisig'
2021
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
2122
import ClusterSwitch from '../ClusterSwitch'
2223
import Modal from '../common/Modal'
@@ -35,11 +36,7 @@ const General = () => {
3536
const isRemote: boolean = isRemoteCluster(cluster) // Move to multisig context
3637
const multisigCluster: Cluster | 'localnet' = getMultisigCluster(cluster) // Move to multisig context
3738
const wormholeAddress = WORMHOLE_ADDRESS[multisigCluster] // Move to multisig context
38-
39-
const anchorWallet = useAnchorWallet()
40-
const { isLoading: isMultisigLoading, squads } = useMultisig(
41-
anchorWallet as Wallet
42-
)
39+
const { isLoading: isMultisigLoading, proposeSquads } = useMultisigContext()
4340
const { rawConfig, dataIsLoading, connection } = usePythContext()
4441
const { connected } = useWallet()
4542
const [pythProgramClient, setPythProgramClient] =
@@ -268,10 +265,15 @@ const General = () => {
268265
}
269266

270267
const handleSendProposalButtonClick = async () => {
271-
if (pythProgramClient && dataChanges && !isMultisigLoading && squads) {
268+
if (
269+
pythProgramClient &&
270+
dataChanges &&
271+
!isMultisigLoading &&
272+
proposeSquads
273+
) {
272274
const instructions: TransactionInstruction[] = []
273275
for (const symbol of Object.keys(dataChanges)) {
274-
const multisigAuthority = squads.getAuthorityPDA(
276+
const multisigAuthority = proposeSquads.getAuthorityPDA(
275277
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)],
276278
1
277279
)
@@ -447,7 +449,7 @@ const General = () => {
447449
setIsSendProposalButtonLoading(true)
448450
try {
449451
const proposalPubkey = await proposeInstructions(
450-
squads,
452+
proposeSquads,
451453
PRICE_FEED_MULTISIG[getMultisigCluster(cluster)],
452454
instructions,
453455
isRemote,
@@ -714,17 +716,17 @@ const General = () => {
714716

715717
// create anchor wallet when connected
716718
useEffect(() => {
717-
if (connected) {
719+
if (connected && proposeSquads) {
718720
const provider = new AnchorProvider(
719721
connection,
720-
anchorWallet as Wallet,
722+
proposeSquads.wallet,
721723
AnchorProvider.defaultOptions()
722724
)
723725
setPythProgramClient(
724726
pythOracleProgram(getPythProgramKeyForCluster(cluster), provider)
725727
)
726728
}
727-
}, [anchorWallet, connection, connected, cluster])
729+
}, [connection, connected, cluster, proposeSquads])
728730

729731
return (
730732
<div className="relative">
@@ -749,12 +751,12 @@ const General = () => {
749751
<PermissionDepermissionKey
750752
isPermission={true}
751753
pythProgramClient={pythProgramClient}
752-
squads={squads}
754+
squads={proposeSquads}
753755
/>
754756
<PermissionDepermissionKey
755757
isPermission={false}
756758
pythProgramClient={pythProgramClient}
757-
squads={squads}
759+
squads={proposeSquads}
758760
/>
759761
</div>
760762
<div className="relative mt-6">

0 commit comments

Comments
 (0)