From 863b76fcfcb69af54f5825cd9e8111e34f4f2e1f Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Sat, 14 Dec 2024 11:34:06 -0800 Subject: [PATCH] Very basic proposals loading per-account --- src/lib/state/client/account.svelte.ts | 3 ++ src/lib/types.ts | 2 ++ .../(explorer)/account/[name]/+layout.svelte | 4 +++ .../account/[name]/proposals/+page.svelte | 15 ++++++++ .../account/[name]/proposals/+page.ts | 21 ++++++++++++ .../[network]/api/account/[[name]]/+server.ts | 8 +++-- .../[network]/api/msig/[proposer]/+server.ts | 34 +++++++++++++++++++ 7 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/routes/[network]/(explorer)/account/[name]/proposals/+page.svelte create mode 100644 src/routes/[network]/(explorer)/account/[name]/proposals/+page.ts create mode 100644 src/routes/[network]/api/msig/[proposer]/+server.ts diff --git a/src/lib/state/client/account.svelte.ts b/src/lib/state/client/account.svelte.ts index c8d918e5..06ef329a 100644 --- a/src/lib/state/client/account.svelte.ts +++ b/src/lib/state/client/account.svelte.ts @@ -24,6 +24,7 @@ const defaultDataSources = { get_account: undefined, light_account: [], delegated: [], + proposals: [], rex: undefined, rexfund: undefined }; @@ -77,6 +78,7 @@ export class AccountState { public net = $derived.by(() => (this.account ? this.account.resource('net') : undefined)); public ram = $derived.by(() => (this.account ? this.account.resource('ram') : undefined)); public permissions = $derived.by(() => (this.account ? this.account.permissions : undefined)); + public proposals = $derived.by(() => this.sources.proposals); public value = $derived.by(() => { return this.network && this.balance && this.ram ? getAccountValue(this.network, this.balance, this.ram) @@ -108,6 +110,7 @@ export class AccountState { get_account: json.account_data, light_account: json.balances, delegated: json.delegated, + proposals: json.proposals, rex: json.rex, rexfund: json.rexfund }; diff --git a/src/lib/types.ts b/src/lib/types.ts index 12940422..c7a43238 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -12,6 +12,7 @@ import { Asset } from '@wharfkit/antelope'; +import * as MsigContract from '$lib/wharf/contracts/msig'; import * as SystemContract from '$lib/wharf/contracts/system'; export interface Activity { @@ -50,6 +51,7 @@ export interface DataSources { get_account?: API.v1.AccountObject | undefined; light_account: LightAPIBalanceRow[]; delegated: SystemContract.Types.delegated_bandwidth[]; + proposals: MsigContract.Types.proposal[]; rex?: SystemContract.Types.rex_balance; rexfund?: SystemContract.Types.rex_fund; } diff --git a/src/routes/[network]/(explorer)/account/[name]/+layout.svelte b/src/routes/[network]/(explorer)/account/[name]/+layout.svelte index 697a1c2a..25558f0f 100644 --- a/src/routes/[network]/(explorer)/account/[name]/+layout.svelte +++ b/src/routes/[network]/(explorer)/account/[name]/+layout.svelte @@ -19,6 +19,10 @@ if (context.settings.data.advancedMode) { items.push({ href: `/${network}/account/${account}/permissions`, text: 'Permissions' }); items.push({ href: `/${network}/account/${account}/votes`, text: 'Votes' }); + + if (data.account.proposals.length > 0) { + items.push({ href: `/${network}/account/${account}/proposals`, text: 'Proposals' }); + } } if (context.settings.data.debugMode) { diff --git a/src/routes/[network]/(explorer)/account/[name]/proposals/+page.svelte b/src/routes/[network]/(explorer)/account/[name]/proposals/+page.svelte new file mode 100644 index 00000000..1995b4c9 --- /dev/null +++ b/src/routes/[network]/(explorer)/account/[name]/proposals/+page.svelte @@ -0,0 +1,15 @@ + + +{#each data.proposals as proposal} + +

+ {proposal.proposal_name} +

+
+{/each} diff --git a/src/routes/[network]/(explorer)/account/[name]/proposals/+page.ts b/src/routes/[network]/(explorer)/account/[name]/proposals/+page.ts new file mode 100644 index 00000000..8b5eca0b --- /dev/null +++ b/src/routes/[network]/(explorer)/account/[name]/proposals/+page.ts @@ -0,0 +1,21 @@ +import { error } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ fetch, params, parent }) => { + const { network } = await parent(); + const response = await fetch(`/${params.network}/api/msig/${params.name}`); + const json = await response.json(); + + if ('error' in json) { + error(404, json.error); + } + + return { + proposals: json.proposals, + subtitle: `Multisig proposals by ${params.name} on the ${network.chain.name} Network.`, + pageMetaTags: { + title: `Multisig Proposals | ${params.name} | ${network.chain.name} Network`, + description: `Multisig proposals by ${params.name} on the ${network.chain.name} Network.` + } + }; +}; diff --git a/src/routes/[network]/api/account/[[name]]/+server.ts b/src/routes/[network]/api/account/[[name]]/+server.ts index effbaf8d..a274c644 100644 --- a/src/routes/[network]/api/account/[[name]]/+server.ts +++ b/src/routes/[network]/api/account/[[name]]/+server.ts @@ -17,14 +17,15 @@ export const GET: RequestHandler = async ({ fetch, params }) => { } const network = getBackendNetwork(chain, fetch); - const { system: systemContract } = network.contracts; + const { system: systemContract, msig: msigContract } = network.contracts; try { const headers = getCacheHeaders(5); - const [account_data, delegated] = await Promise.all([ + const [account_data, delegated, proposals] = await Promise.all([ network.client.v1.chain.get_account(params.name), - systemContract.table('delband').all({ scope: params.name }) + systemContract.table('delband').all({ scope: params.name }), + msigContract.table('proposal', params.name).all() ]); let rexbal, rexfund; @@ -57,6 +58,7 @@ export const GET: RequestHandler = async ({ fetch, params }) => { account_data, balances, delegated, + proposals, rex: rexbal, rexfund: rexfund }, diff --git a/src/routes/[network]/api/msig/[proposer]/+server.ts b/src/routes/[network]/api/msig/[proposer]/+server.ts new file mode 100644 index 00000000..d19996f7 --- /dev/null +++ b/src/routes/[network]/api/msig/[proposer]/+server.ts @@ -0,0 +1,34 @@ +import { json, type RequestEvent } from '@sveltejs/kit'; + +import { getChainDefinitionFromParams } from '$lib/state/network.svelte'; +import { Name } from '@wharfkit/antelope'; +import { getCacheHeaders } from '$lib/utils'; +import { getBackendNetwork } from '$lib/wharf/client/ssr.js'; + +export async function GET({ fetch, params }: RequestEvent) { + const chain = getChainDefinitionFromParams(String(params.network)); + if (!chain) { + return json({ error: 'Invalid chain specified' }, { status: 400 }); + } + if (!params.proposer) { + return json({ error: 'Proposer must be specified' }, { status: 400 }); + } + + const network = getBackendNetwork(chain, fetch); + + const scope = Name.from(params.proposer); + + const proposals = await network.contracts.msig.table('proposal', scope).all(); + + return json( + { + ts: new Date(), + proposer: params.proposer, + name: params.proposal, + proposals + }, + { + headers: getCacheHeaders(5) + } + ); +}