Skip to content

Commit

Permalink
Merge pull request #137 from okjodom/gui-fixes
Browse files Browse the repository at this point in the history
Fixes and maintenance
  • Loading branch information
EthnTuttle authored Aug 15, 2023
2 parents 0b4314d + b25de14 commit 30972ac
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 206 deletions.
16 changes: 8 additions & 8 deletions apps/guardian-ui/src/GuardianApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { JsonRpcError, JsonRpcWebsocket } from 'jsonrpc-client-websocket';
import { ConfigGenParams, ConsensusState, PeerHashMap } from './setup/types';
import {
ConfigResponse,
ConsensusStatus,
FederationStatus,
ServerStatus,
StatusResponse,
Versions,
Expand Down Expand Up @@ -204,8 +204,8 @@ export interface SetupApiInterface extends SharedApiInterface {
enum AdminRpc {
version = 'version',
fetchEpochCount = 'fetch_epoch_count',
consensusStatus = 'consensus_status',
connectionCode = 'connection_code',
federationStatus = 'consensus_status',
inviteCode = 'invite_code',
config = 'config',
module = 'module',
}
Expand All @@ -219,7 +219,7 @@ type ModuleRpc = LightningModuleRpc;
export interface AdminApiInterface extends SharedApiInterface {
version: () => Promise<Versions>;
fetchEpochCount: () => Promise<number>;
connectionCode: () => Promise<string>;
inviteCode: () => Promise<string>;
config: (connection: string) => Promise<ConfigResponse>;
moduleApiCall: <T>(moduleId: number, rpc: ModuleRpc) => Promise<T>;
}
Expand Down Expand Up @@ -354,12 +354,12 @@ export class GuardianApi
return this.base.call(AdminRpc.fetchEpochCount);
};

consensusStatus = (): Promise<ConsensusStatus> => {
return this.base.call(AdminRpc.consensusStatus);
federationStatus = (): Promise<FederationStatus> => {
return this.base.call(AdminRpc.federationStatus);
};

connectionCode = (): Promise<string> => {
return this.base.call(AdminRpc.connectionCode);
inviteCode = (): Promise<string> => {
return this.base.call(AdminRpc.inviteCode);
};

config = (connection: string): Promise<ConfigResponse> => {
Expand Down
99 changes: 81 additions & 18 deletions apps/guardian-ui/src/admin/FederationAdmin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,42 @@ import {
Td,
Thead,
Th,
Box,
Icon,
Text,
} from '@chakra-ui/react';
import { CopyInput } from '@fedimint/ui';
import { useTranslation } from '@fedimint/utils';
import { useAdminContext } from '../hooks';
import { ConfigResponse, Gateway, StatusResponse, Versions } from '../types';
import { AdminHeader } from '../components/AdminHeader';
import { AdminMain } from '../components/AdminMain';
import { ConnectedNodes } from '../components/ConnectedNodes';
import { LightningModuleRpc } from '../GuardianApi';
import { ReactComponent as CopyIcon } from '../assets/svgs/copy.svg';
import { Pill } from '../components/Pill';

export const FederationAdmin: React.FC = () => {
const { api } = useAdminContext();
const [versions, setVersions] = useState<Versions>();
const [epochCount, setEpochCount] = useState<number>();
const [status, setStatus] = useState<StatusResponse>();
const [connectionCode, setConnectionCode] = useState<string>('');
const [inviteCode, setInviteCode] = useState<string>('');
const [config, setConfig] = useState<ConfigResponse>();
const [gateways, setGateways] = useState<Gateway[]>([]);
const [guardians, setGuardians] = useState<string | undefined>();
const { t } = useTranslation();

useEffect(() => {
api.version().then(setVersions).catch(console.error);
api.fetchEpochCount().then(setEpochCount).catch(console.error);
// TODO: poll server status
api.status().then(setStatus).catch(console.error);
api.connectionCode().then(setConnectionCode).catch(console.error);
api.inviteCode().then(setInviteCode).catch(console.error);
}, [api]);

useEffect(() => {
connectionCode &&
api.config(connectionCode).then(setConfig).catch(console.error);
}, [connectionCode, api]);
inviteCode && api.config(inviteCode).then(setConfig).catch(console.error);
}, [inviteCode, api]);

useEffect(() => {
if (config) {
Expand All @@ -56,60 +64,115 @@ export const FederationAdmin: React.FC = () => {
}
}, [config, api]);

useEffect(() => {
const online = status?.federation ? status.federation.peers_online + 1 : 1;
const offline = status?.federation ? status.federation.peers_offline : 0;

const totalPeers = online + offline;
setGuardians(`${online} / ${totalPeers}`);
}, [status]);

const apiVersion = versions?.core.api.length
? `${versions.core.api[0].major}.${versions.core.api[0].minor}`
: '';
const consensusVersion =
versions?.core.consensus !== undefined ? `${versions.core.consensus}` : '';
versions?.core.core_consensus !== undefined
? `${versions.core.core_consensus}`
: '';

return (
<Flex gap='32px' flexDirection='row'>
<Flex gap={4} flexDirection='column' w='100%'>
<AdminHeader connectionCode={connectionCode} />
<Flex>
<Box>
<Text
color='#111827'
fontSize='24px'
fontWeight='600'
lineHeight='32px'
textTransform='capitalize'
>
{config?.client_config.meta.federation_name}
</Text>
<Text color='#111827' fontSize='14px' lineHeight='32px'>
{t('federation-dashboard.placeholder-fed-description')}
</Text>
<Flex gap='12px' mt='13px'>
<Pill text='Guardians' status={`${guardians}`} />
<Pill text='Server' status='Healthy' />
<Pill text='Uptime' status='100%' />
</Flex>
<Box mt='38px'>
<Text mb='6px' fontSize='14px' fontWeight='500' color='#344054'>
{t('federation-dashboard.invite-members')}
</Text>
<CopyInput
value={inviteCode}
buttonLeftIcon={<Icon as={CopyIcon} />}
/>
<Text mt='6px' mb='25px' fontSize='14px' color='#6B7280'>
{t('federation-dashboard.invite-members-prompt')}
</Text>
</Box>
</Box>
</Flex>
<AdminMain />
<Flex gap={4}>
<Card flex='1'>
<CardHeader>Federation info</CardHeader>
<CardHeader>{t('federation-dashboard.fed-info.label')}</CardHeader>
<CardBody>
<Table>
<Tbody>
<Tr>
<Td>Your status</Td>
<Td>
{t('federation-dashboard.fed-info.your-status-label')}
</Td>
<Td>{status?.server}</Td>
</Tr>
<Tr>
<Td>Epoch count</Td>
<Td>
{t('federation-dashboard.fed-info.epoch-count-label')}
</Td>
<Td>{epochCount}</Td>
</Tr>
<Tr>
<Td>API Version</Td>
<Td>
{t('federation-dashboard.fed-info.api-version-label')}
</Td>
<Td>{apiVersion}</Td>
</Tr>
<Tr>
<Td>Consensus version</Td>
<Td>
{t(
'federation-dashboard.fed-info.consensus-version-label'
)}
</Td>
<Td>{consensusVersion}</Td>
</Tr>
</Tbody>
</Table>
</CardBody>
</Card>
<Card flex='1'>
<CardHeader>Peer info</CardHeader>
<CardHeader>{t('federation-dashboard.peer-info.label')}</CardHeader>
<CardBody>
<Table>
<Thead>
<Tr>
<Th>Name</Th>
<Th>Status</Th>
<Th>{t('federation-dashboard.peer-info.name-label')}</Th>
<Th>{t('federation-dashboard.peer-info.status-label')}</Th>
</Tr>
</Thead>
{status && (
<Tbody>
{Object.entries(
status?.consensus?.status_by_peer || {}
status?.federation?.status_by_peer || {}
).map(([peerId, peerStatus]) => (
<Tr key={peerId}>
<Td>Peer {peerId}</Td>
<Td>
{t('federation-dashboard.peer-info.peer-id-prefix')}{' '}
{peerId}
</Td>
<Td>{peerStatus.connection_status}</Td>
</Tr>
))}
Expand Down
97 changes: 0 additions & 97 deletions apps/guardian-ui/src/components/AdminHeader.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions apps/guardian-ui/src/components/AdminMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { ReactComponent as BitcoinIcon } from '../assets/svgs/bitcoin-white.svg'
import { ReactComponent as EcashIcon } from '../assets/svgs/ecash.svg';
import { ReactComponent as BankNotesIcon } from '../assets/svgs/banknotes.svg';
import { ReactComponent as InfoIcon } from '../assets/svgs/info.svg';
import { Epochs } from './Epochs';

interface FederationBalanceProps {
title: string;
Expand Down Expand Up @@ -107,7 +106,6 @@ export const AdminMain = () => {
icon={<BankNotesIcon color={theme.colors.white} />}
/>
</Flex>
<Epochs />
</Flex>
);
};
54 changes: 54 additions & 0 deletions apps/guardian-ui/src/components/NumberFormControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState } from 'react';
import {
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
NumberInputProps,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
} from '@chakra-ui/react';
import { isValidNumber } from '../utils/validators';

interface NumberFormControlProps extends NumberInputProps {
labelText: string;
errorText: string;
helperText: string;
}

export const NumberFormControl = React.memo<NumberFormControlProps>(
function NumInput({
labelText,
errorText,
helperText,
min,
max,
value,
onChange,
}: NumberFormControlProps) {
const [invalid, setInvalid] = useState(false);

const onValueChange = (value: string) => {
setInvalid(!isValidNumber(value));
onChange && onChange(value, Number(value));
};

return (
<FormControl isInvalid={invalid}>
<FormLabel>{labelText}</FormLabel>
<NumberInput min={min} max={max} value={value} onChange={onValueChange}>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
<FormErrorMessage>{errorText}</FormErrorMessage>
<FormHelperText>{helperText}</FormHelperText>
</FormControl>
);
}
);
Loading

0 comments on commit 30972ac

Please sign in to comment.