-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: sync popover * fix: sync bar * refactor: change `useConnect` to use signals * feat: change state manager to Zustand * refactor: remove signals lib usage * Mobx spike * Post review updates --------- Co-authored-by: Max Korsunov <[email protected]>
- Loading branch information
Showing
21 changed files
with
406 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,16 @@ | ||
import { Button } from '@penumbra-zone/ui/Button'; | ||
import { useConnect } from '@/utils/penumbra/useConnect.ts'; | ||
import { ProviderPopover } from './provider-popover.tsx'; | ||
import { ProviderPopover } from './provider-popover'; | ||
import { connectionStore } from '@/state/connection'; | ||
import { observer } from 'mobx-react-lite'; | ||
|
||
export const Connection = () => { | ||
const { connected, connect } = useConnect(); | ||
|
||
if (!connected) { | ||
export const Connection = observer(() => { | ||
if (!connectionStore.connected) { | ||
return ( | ||
<Button actionType='accent' onClick={() => void connect()}>Connect</Button> | ||
<Button actionType='accent' onClick={() => void connectionStore.connect()}> | ||
Connect | ||
</Button> | ||
); | ||
} | ||
|
||
return <ProviderPopover /> | ||
}; | ||
return <ProviderPopover />; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { useMemo } from 'react'; | ||
import { Blocks } from 'lucide-react'; | ||
import { Popover } from '@penumbra-zone/ui/Popover'; | ||
import { Button } from '@penumbra-zone/ui/Button'; | ||
import { Density } from '@penumbra-zone/ui/Density'; | ||
import { Pill } from '@penumbra-zone/ui/Pill'; | ||
import { Text } from '@penumbra-zone/ui/Text'; | ||
import { statusStore } from '@/state/status'; | ||
import { connectionStore } from '@/state/connection'; | ||
import { observer } from 'mobx-react-lite'; | ||
|
||
export const StatusPopover = observer(() => { | ||
const { loading, error, syncing, fullSyncHeight, latestKnownBlockHeight } = statusStore; | ||
|
||
// a ReactNode displaying the sync status in form of a pill | ||
const pill = useMemo(() => { | ||
if (error) { | ||
return <Pill context='technical-destructive'>Block Sync Error</Pill>; | ||
} | ||
|
||
if (loading) { | ||
return null; | ||
} | ||
|
||
if (!syncing) { | ||
return <Pill context='technical-success'>Blocks Synced</Pill>; | ||
} | ||
|
||
return <Pill context='technical-caution'>Block Syncing</Pill>; | ||
}, [error, loading, syncing]); | ||
|
||
if (!connectionStore.connected) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Popover> | ||
<Popover.Trigger> | ||
<Button icon={Blocks} iconOnly> | ||
Status | ||
</Button> | ||
</Popover.Trigger> | ||
<Popover.Content align='end' side='bottom'> | ||
<Density compact> | ||
<div className='flex flex-col gap-4'> | ||
<div className='flex flex-col gap-2'> | ||
<Text technical>Status</Text> | ||
{pill} | ||
{error} | ||
</div> | ||
{!loading && ( | ||
<div className='flex flex-col gap-2'> | ||
<Text technical>Block Height</Text> | ||
<Pill context='technical-default'> | ||
{latestKnownBlockHeight !== fullSyncHeight | ||
? `${fullSyncHeight} of ${latestKnownBlockHeight}` | ||
: `${latestKnownBlockHeight}`} | ||
</Pill> | ||
</div> | ||
)} | ||
</div> | ||
</Density> | ||
</Popover.Content> | ||
</Popover> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Progress } from '@penumbra-zone/ui/Progress'; | ||
import { statusStore } from '@/state/status'; | ||
import { observer } from 'mobx-react-lite'; | ||
|
||
export const SyncBar = observer(() => { | ||
const { loading, error, syncPercent, updating } = statusStore; | ||
|
||
return ( | ||
<div className='fixed left-0 top-0 h-1 w-full'> | ||
{loading ? ( | ||
<Progress value={0} loading error={Boolean(error)} /> | ||
) : ( | ||
<Progress value={syncPercent} loading={updating} error={Boolean(error)} /> | ||
)} | ||
</div> | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { PenumbraRequestFailure, PenumbraState, PenumbraManifest } from '@penumbra-zone/client'; | ||
import { penumbra, PRAX_ORIGIN } from '@/utils/penumbra'; | ||
import { makeAutoObservable } from 'mobx'; | ||
|
||
class ConnectionStateStore { | ||
connected = false; | ||
manifest: PenumbraManifest | undefined; | ||
|
||
constructor() { | ||
makeAutoObservable(this); | ||
|
||
if (typeof window !== 'undefined') { | ||
this.setup(); | ||
} | ||
} | ||
|
||
private setManifest(manifest: PenumbraManifest | undefined) { | ||
this.manifest = manifest; | ||
} | ||
|
||
private setConnected(connected: boolean) { | ||
this.connected = connected; | ||
} | ||
|
||
async reconnect() { | ||
await penumbra.attach(PRAX_ORIGIN); | ||
if (!penumbra.connected) { | ||
return; | ||
} | ||
|
||
try { | ||
await penumbra.connect(); | ||
this.setConnected(true); | ||
} catch (error) { | ||
/* no-op */ | ||
} | ||
} | ||
|
||
async connect() { | ||
try { | ||
await penumbra.connect(); | ||
} catch (error) { | ||
if (error instanceof Error && error.cause) { | ||
if (error.cause === PenumbraRequestFailure.Denied) { | ||
// TODO: replace these alerts with toasts | ||
alert( | ||
'Connection denied: you may need to un-ignore this site in your extension settings.', | ||
); | ||
} | ||
if (error.cause === PenumbraRequestFailure.NeedsLogin) { | ||
alert('Not logged in: please login into the extension and try again'); | ||
} | ||
} | ||
} | ||
} | ||
|
||
async disconnect() { | ||
if (!penumbra.connected) { | ||
return; | ||
} | ||
|
||
try { | ||
await penumbra.disconnect(); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
} | ||
|
||
setup() { | ||
this.setManifest(penumbra.manifest); | ||
|
||
// If Prax is connected on page load, reconnect to ensure the connection is still active | ||
void this.reconnect(); | ||
|
||
penumbra.onConnectionStateChange(event => { | ||
this.setManifest(penumbra.manifest); | ||
this.setConnected(event.state === PenumbraState.Connected); | ||
}); | ||
} | ||
} | ||
|
||
export const connectionStore = new ConnectionStateStore(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
export const getSyncPercent = ( | ||
fullSyncHeight: bigint, | ||
latestKnownBlockHeight: bigint, | ||
): { syncPercent: number, syncPercentStringified: string } => { | ||
let percentSyncedNumber = 0; | ||
if (latestKnownBlockHeight) { | ||
percentSyncedNumber = Number(fullSyncHeight) / Number(latestKnownBlockHeight); | ||
if (percentSyncedNumber > 1) { | ||
percentSyncedNumber = 1; | ||
} | ||
} | ||
|
||
// Round down to ensure whole numbers | ||
const roundedPercentSyncedNumber = Math.floor(percentSyncedNumber * 100); | ||
|
||
return { | ||
syncPercent: roundedPercentSyncedNumber / 100, | ||
syncPercentStringified: `${roundedPercentSyncedNumber}%`, | ||
} | ||
}; |
Oops, something went wrong.