mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-20 13:34:30 +01:00
feat: ✨ stats view (#54)
* feat: ✨ channel stats * chore: 🔧 add node resolver * chore: 🔧 add monitored time * chore: 🔧 and queries to front * fix: 🐛 floats to ints * chore: 🔧 add progress bars * chore: 🔧 add channel resolver * chore: 🔧 refactor forwards frontend * refactor: ♻️ channel resolvers * chore: 🔧 refactor channel queries * refactor: ♻️ peer resolver * refactor: ♻️ peer query * fix: 🐛 small changes * fix: 🐛 typo * chore: 🔧 stats view wip * chore: 🔧 add update script * chore: 🔧 improve ui * chore: 🔧 move buttons * fix: 🐛 home path * chore: 🔧 add public key to node resolver * refactor: ♻️ resume resolver * chore: 🔧 remove test account * chore: 🔧 change logger for lnpay * feat: ✨ github version Co-authored-by: apotdevin <apotdevincab@gmail.com>
This commit is contained in:
parent
f80492b80a
commit
009195c86f
85 changed files with 3320 additions and 851 deletions
52
README.md
52
README.md
|
@ -13,10 +13,14 @@
|
|||
- [Development](#development)
|
||||
- [Docker deployment](#docker)
|
||||
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
ThunderHub is an **open-source** LND node manager where you can manage and monitor your node on any device or browser. It allows you to take control of the lightning network with a simple and intuitive UX and the most up-to-date tech stack.
|
||||
|
||||
---
|
||||
|
||||
### Integrations
|
||||
|
||||
**BTCPay Server**
|
||||
|
@ -25,6 +29,8 @@ ThunderHub is currently integrated into BTCPay for easier deployment. If you alr
|
|||
**Raspiblitz**
|
||||
For Raspiblitz users you can also get ThunderHub running by following this [gist](https://gist.github.com/openoms/8ba963915c786ce01892f2c9fa2707bc)
|
||||
|
||||
---
|
||||
|
||||
### Tech Stack
|
||||
|
||||
This repository consists of a **NextJS** server that handles both the backend **Graphql Server** and the frontend **React App**. ThunderHub connects to your Lightning Network node by using the gRPC ports.
|
||||
|
@ -38,6 +44,8 @@ This repository consists of a **NextJS** server that handles both the backend **
|
|||
- GraphQL
|
||||
- Ln-Service
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Monitoring
|
||||
|
@ -89,6 +97,8 @@ This repository consists of a **NextJS** server that handles both the backend **
|
|||
- Loop In and Out to provide liquidity or remove it from your channels.
|
||||
- Storefront interface
|
||||
|
||||
---
|
||||
|
||||
## **Requirements**
|
||||
|
||||
- Yarn/npm installed
|
||||
|
@ -109,6 +119,8 @@ npm run dev -> npm run dev:compatible
|
|||
|
||||
**HodlHodl integration will not work with older versions of Node!**
|
||||
|
||||
---
|
||||
|
||||
## Config
|
||||
|
||||
You can define some environment variables that ThunderHub can start with. To do this create a `.env` file in the root directory with the following parameters:
|
||||
|
@ -190,6 +202,8 @@ location /thub/ {
|
|||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
To run ThunderHub you first need to clone this repository.
|
||||
|
@ -224,26 +238,56 @@ yarn start -p 4000
|
|||
npm start -- -p 4000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
|
||||
To update ThunderHub to the latest version follow these commands.
|
||||
There are multiple ways to update ThunderHub to it's latest version.
|
||||
|
||||
_Commands have to be called inside the thunderhub repository folder._
|
||||
|
||||
```js
|
||||
**1. Script Shortcut**
|
||||
|
||||
```sh
|
||||
// Yarn
|
||||
yarn update
|
||||
|
||||
// NPM
|
||||
npm run update
|
||||
```
|
||||
|
||||
**2. Script**
|
||||
|
||||
```sh
|
||||
sh ./scripts/updateToLatest.sh
|
||||
```
|
||||
|
||||
**3. Step by Step**
|
||||
|
||||
```sh
|
||||
// Yarn
|
||||
git pull
|
||||
yarn
|
||||
yarn build
|
||||
yarn start
|
||||
|
||||
// NPM
|
||||
git pull
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Then you can start your server:**
|
||||
|
||||
```sh
|
||||
// Yarn
|
||||
yarn start
|
||||
|
||||
// NPM
|
||||
npm run start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
If you want to develop on ThunderHub and want hot reloading when you do changes, use the following commands:
|
||||
|
@ -256,6 +300,8 @@ yarn dev
|
|||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker
|
||||
|
||||
ThunderHub also provides docker images for easier deployment. [Docker Hub](https://hub.docker.com/repository/docker/apotdevin/thunderhub)
|
||||
|
|
|
@ -2,6 +2,9 @@ overwrite: true
|
|||
schema: 'http://localhost:3000/api/v1'
|
||||
documents: 'src/graphql/**/*.ts'
|
||||
generates:
|
||||
src/graphql/fragmentTypes.json:
|
||||
plugins:
|
||||
- fragment-matcher
|
||||
src/graphql/types.ts:
|
||||
- typescript
|
||||
src/graphql/:
|
||||
|
|
|
@ -3,8 +3,16 @@ import * as React from 'react';
|
|||
import Head from 'next/head';
|
||||
import { ApolloProvider } from '@apollo/react-hooks';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import {
|
||||
InMemoryCache,
|
||||
IntrospectionFragmentMatcher,
|
||||
} from 'apollo-cache-inmemory';
|
||||
import getConfig from 'next/config';
|
||||
import introspectionQueryResultData from 'src/graphql/fragmentTypes.json';
|
||||
|
||||
const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
introspectionQueryResultData,
|
||||
});
|
||||
|
||||
let globalApolloClient = null;
|
||||
|
||||
|
@ -32,7 +40,7 @@ function createIsomorphLink(ctx) {
|
|||
*/
|
||||
function createApolloClient(ctx = {}, initialState = {}) {
|
||||
const ssrMode = typeof window === 'undefined';
|
||||
const cache = new InMemoryCache().restore(initialState);
|
||||
const cache = new InMemoryCache({ fragmentMatcher }).restore(initialState);
|
||||
|
||||
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
|
||||
return new ApolloClient({
|
||||
|
|
41
package-lock.json
generated
41
package-lock.json
generated
|
@ -2105,6 +2105,42 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@graphql-codegen/fragment-matcher": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/fragment-matcher/-/fragment-matcher-1.15.1.tgz",
|
||||
"integrity": "sha512-30oLLPRYLuAo+OvJLPBsBEYEswAaXddOGDYL4QxGQsYnml0IhQMj//24rnLEUmYEV6zy2BAXCPK5whmV/DOnNw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@graphql-codegen/plugin-helpers": "1.15.1",
|
||||
"tslib": "~2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@graphql-codegen/plugin-helpers": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-1.15.1.tgz",
|
||||
"integrity": "sha512-DnLD+s4ng+rqbqrcHtV0/jtn/bYSUTqL3tpqPDeIhsqmdDSAtOtelVCeTtPHAJGOO7RI6BQB6rXm/ZgaCObIAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@graphql-tools/utils": "^6.0.0",
|
||||
"camel-case": "4.1.1",
|
||||
"common-tags": "1.8.0",
|
||||
"constant-case": "3.0.3",
|
||||
"import-from": "3.0.0",
|
||||
"lower-case": "2.0.1",
|
||||
"param-case": "3.0.3",
|
||||
"pascal-case": "3.1.1",
|
||||
"tslib": "~2.0.0",
|
||||
"upper-case": "2.0.1"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.0.tgz",
|
||||
"integrity": "sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@graphql-codegen/introspection": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-1.15.0.tgz",
|
||||
|
@ -20094,6 +20130,11 @@
|
|||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"react-circular-progressbar": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-circular-progressbar/-/react-circular-progressbar-2.0.3.tgz",
|
||||
"integrity": "sha512-YKN+xAShXA3gYihevbQZbavfiJxo83Dt1cUxqg/cltj4VVsRQpDr7Fg1mvjDG3x1KHGtd9NmYKvJ2mMrPwbKyw=="
|
||||
},
|
||||
"react-copy-to-clipboard": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.2.tgz",
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"build:64": "docker build -f arm64v8.Dockerfile -t apotdevin/thunderhub:test-arm64v8 .",
|
||||
"build:manifest": "docker manifest create apotdevin/thunderhub:test apotdevin/thunderhub:test-amd64 apotdevin/thunderhub:test-arm32v7 apotdevin/thunderhub:test-arm64v8",
|
||||
"upgrade-latest": "npx npm-check -u",
|
||||
"tsc": "tsc"
|
||||
"tsc": "tsc",
|
||||
"update": "sh ./scripts/updateToLatest.sh"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
@ -63,6 +64,7 @@
|
|||
"numeral": "^2.0.6",
|
||||
"qrcode.react": "^1.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-circular-progressbar": "^2.0.3",
|
||||
"react-copy-to-clipboard": "^5.0.2",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-feather": "^2.0.8",
|
||||
|
@ -86,6 +88,7 @@
|
|||
"@commitlint/cli": "^8.3.5",
|
||||
"@commitlint/config-conventional": "^8.3.4",
|
||||
"@graphql-codegen/cli": "^1.15.0",
|
||||
"@graphql-codegen/fragment-matcher": "^1.15.1",
|
||||
"@graphql-codegen/introspection": "^1.15.0",
|
||||
"@graphql-codegen/near-operation-file-preset": "^1.15.0",
|
||||
"@graphql-codegen/typescript": "^1.15.0",
|
||||
|
|
|
@ -12,6 +12,7 @@ import { Footer } from '../src/layouts/footer/Footer';
|
|||
import 'react-toastify/dist/ReactToastify.css';
|
||||
import { PageWrapper, HeaderBodyWrapper } from '../src/layouts/Layout.styled';
|
||||
import { parseCookies } from '../src/utils/cookies';
|
||||
import 'react-circular-progressbar/dist/styles.css';
|
||||
|
||||
toast.configure({ draggable: false, pauseOnFocusLoss: false });
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ const ForwardsView = () => {
|
|||
</CardTitle>
|
||||
{data.getForwards.forwards.length <= 0 && renderNoForwards()}
|
||||
<Card mobileCardPadding={'0'} mobileNoBackground={true}>
|
||||
{data.getForwards.forwards.map((forward: any, index: number) => (
|
||||
{data.getForwards.forwards.map((forward, index: number) => (
|
||||
<ForwardCard
|
||||
forward={forward}
|
||||
key={index}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { GridWrapper } from 'src/components/gridWrapper/GridWrapper';
|
||||
import { withApollo } from 'config/client';
|
||||
import { Version } from 'src/components/version/Version';
|
||||
import { NetworkInfo } from '../src/views/home/networkInfo/NetworkInfo';
|
||||
import { AccountInfo } from '../src/views/home/account/AccountInfo';
|
||||
import { QuickActions } from '../src/views/home/quickActions/QuickActions';
|
||||
|
@ -13,6 +14,7 @@ import { NodeBar } from '../src/components/nodeInfo/NodeBar';
|
|||
const HomeView = () => {
|
||||
return (
|
||||
<>
|
||||
<Version />
|
||||
<AccountInfo />
|
||||
<NodeBar />
|
||||
<ConnectCard />
|
||||
|
|
|
@ -35,7 +35,7 @@ const SettingsView = () => {
|
|||
};
|
||||
|
||||
const Wrapped = () => (
|
||||
<GridWrapper>
|
||||
<GridWrapper noNavigation={true}>
|
||||
<SettingsView />
|
||||
</GridWrapper>
|
||||
);
|
||||
|
|
40
pages/stats.tsx
Normal file
40
pages/stats.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { GridWrapper } from 'src/components/gridWrapper/GridWrapper';
|
||||
import { withApollo } from 'config/client';
|
||||
import { VolumeStats } from 'src/views/stats/VolumeStats';
|
||||
import { TimeStats } from 'src/views/stats/TimeStats';
|
||||
import { FeeStats } from 'src/views/stats/FeeStats';
|
||||
import { StatResume } from 'src/views/stats/StatResume';
|
||||
import { StatsProvider } from 'src/views/stats/context';
|
||||
import { SingleLine } from '../src/components/generic/Styled';
|
||||
|
||||
export const ButtonRow = styled.div`
|
||||
width: auto;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
export const SettingsLine = styled(SingleLine)`
|
||||
margin: 8px 0;
|
||||
`;
|
||||
|
||||
const StatsView = () => {
|
||||
return (
|
||||
<>
|
||||
<StatResume />
|
||||
<VolumeStats />
|
||||
<TimeStats />
|
||||
<FeeStats />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Wrapped = () => (
|
||||
<GridWrapper>
|
||||
<StatsProvider>
|
||||
<StatsView />
|
||||
</StatsProvider>
|
||||
</GridWrapper>
|
||||
);
|
||||
|
||||
export default withApollo(Wrapped);
|
|
@ -22,7 +22,6 @@ import { FlowBox } from '../src/views/home/reports/flow';
|
|||
const TransactionsView = () => {
|
||||
const [indexOpen, setIndexOpen] = useState(0);
|
||||
const [token, setToken] = useState('');
|
||||
const [fetching, setFetching] = useState(false);
|
||||
|
||||
const { auth } = useAccountState();
|
||||
|
||||
|
@ -42,7 +41,7 @@ const TransactionsView = () => {
|
|||
return <LoadingCard title={'Transactions'} />;
|
||||
}
|
||||
|
||||
const resumeList = JSON.parse(data.getResume.resume);
|
||||
const resumeList = data.getResume.resume;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -75,10 +74,7 @@ const TransactionsView = () => {
|
|||
<ColorButton
|
||||
fullWidth={true}
|
||||
withMargin={'16px 0 0'}
|
||||
loading={fetching}
|
||||
disabled={fetching}
|
||||
onClick={() => {
|
||||
setFetching(true);
|
||||
fetchMore({
|
||||
variables: { auth, token },
|
||||
updateQuery: (
|
||||
|
@ -89,18 +85,17 @@ const TransactionsView = () => {
|
|||
) => {
|
||||
if (!result) return prev;
|
||||
const newToken = result.getResume.token || '';
|
||||
const prevEntries = JSON.parse(prev.getResume.resume);
|
||||
const newEntries = JSON.parse(result.getResume.resume);
|
||||
const prevEntries = prev.getResume.resume;
|
||||
const newEntries = result.getResume.resume;
|
||||
|
||||
const allTransactions = newToken
|
||||
? [...prevEntries, ...newEntries]
|
||||
: prevEntries;
|
||||
|
||||
setFetching(false);
|
||||
return {
|
||||
getResume: {
|
||||
token: newToken,
|
||||
resume: JSON.stringify(allTransactions),
|
||||
resume: allTransactions,
|
||||
__typename: 'getResumeType',
|
||||
},
|
||||
};
|
||||
|
|
26
scripts/updateToLatest.sh
Normal file
26
scripts/updateToLatest.sh
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
|
||||
UPSTREAM=${1:-'@{u}'}
|
||||
LOCAL=$(git rev-parse @)
|
||||
REMOTE=$(git rev-parse "$UPSTREAM")
|
||||
|
||||
if [ $LOCAL = $REMOTE ]; then
|
||||
TAG=$(git tag | sort -V | tail -1)
|
||||
echo "You are up-to-date on version" $TAG
|
||||
else
|
||||
# fetch latest master
|
||||
echo "Pulling latest changes..."
|
||||
git fetch
|
||||
git pull -p
|
||||
|
||||
# install deps
|
||||
echo "Installing dependencies..."
|
||||
npm install --quiet
|
||||
|
||||
# build nextjs
|
||||
echo "Building application..."
|
||||
npm run build
|
||||
|
||||
TAG=$(git tag | sort -V | tail -1)
|
||||
echo "Updated to version" $TAG
|
||||
fi
|
|
@ -36,6 +36,13 @@ export const getCorrectAuth = (
|
|||
auth: AuthType,
|
||||
context: ContextType
|
||||
): LndAuthType => {
|
||||
if (auth.type === 'test' && nodeEnv === 'development') {
|
||||
return {
|
||||
host: process.env.TEST_HOST,
|
||||
macaroon: process.env.TEST_MACAROON,
|
||||
cert: process.env.TEST_CERT,
|
||||
};
|
||||
}
|
||||
if (auth.type === SERVER_ACCOUNT) {
|
||||
const { account, accounts } = context;
|
||||
if (!account) {
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { logger } from 'server/helpers/logger';
|
||||
import { toWithError } from 'server/helpers/async';
|
||||
import { getChannel } from 'ln-service';
|
||||
import { openChannel } from './resolvers/mutation/openChannel';
|
||||
import { closeChannel } from './resolvers/mutation/closeChannel';
|
||||
import { updateFees } from './resolvers/mutation/updateFees';
|
||||
|
@ -20,4 +23,44 @@ export const channelResolvers = {
|
|||
closeChannel,
|
||||
updateFees,
|
||||
},
|
||||
Channel: {
|
||||
channel: async parent => {
|
||||
const { lnd, id, withNodes = true, localKey, dontResolveKey } = parent;
|
||||
|
||||
if (!lnd) {
|
||||
logger.debug('ExpectedLNDToGetChannel');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
logger.debug('ExpectedIdToGetChannel');
|
||||
return null;
|
||||
}
|
||||
|
||||
const [channel, error] = await toWithError(getChannel({ lnd, id }));
|
||||
|
||||
if (error) {
|
||||
logger.debug(`Error getting channel with id ${id}: %o`, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodeProps = (publicKey: string) =>
|
||||
withNodes ? { node: { lnd, publicKey } } : {};
|
||||
|
||||
const policiesWithNodes = channel.policies
|
||||
.map(policy => {
|
||||
if (dontResolveKey && dontResolveKey === policy.public_key) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
...policy,
|
||||
...nodeProps(policy.public_key),
|
||||
...(localKey ? { my_node: policy.public_key === localKey } : {}),
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
return { ...channel, policies: policiesWithNodes };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import {
|
||||
getChannels as getLnChannels,
|
||||
getNode,
|
||||
getChannel,
|
||||
getWalletInfo,
|
||||
} from 'ln-service';
|
||||
import { getChannels as getLnChannels, getWalletInfo } from 'ln-service';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { toWithError, to } from 'server/helpers/async';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { getAuthLnd, getCorrectAuth } from 'server/helpers/helpers';
|
||||
|
||||
|
@ -20,77 +14,20 @@ export const getChannels = async (
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const [walletInfo, walletError] = await toWithError(getWalletInfo({ lnd }));
|
||||
const publicKey = walletInfo?.public_key;
|
||||
const { public_key } = await to(getWalletInfo({ lnd }));
|
||||
|
||||
walletError &&
|
||||
logger.debug('Error getting wallet info in getChannels: %o', walletError);
|
||||
|
||||
const channelList = await to(
|
||||
const { channels } = await to(
|
||||
getLnChannels({
|
||||
lnd,
|
||||
is_active: params.active,
|
||||
})
|
||||
);
|
||||
|
||||
const getChannelList = () =>
|
||||
Promise.all(
|
||||
channelList.channels.map(async channel => {
|
||||
const [nodeInfo, nodeError] = await toWithError(
|
||||
getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: channel.partner_public_key,
|
||||
})
|
||||
);
|
||||
|
||||
const [channelInfo, channelError] = await toWithError(
|
||||
getChannel({
|
||||
lnd,
|
||||
id: channel.id,
|
||||
})
|
||||
);
|
||||
|
||||
nodeError &&
|
||||
logger.debug(
|
||||
`Error getting node with public key ${channel.partner_public_key}: %o`,
|
||||
nodeError
|
||||
);
|
||||
|
||||
channelError &&
|
||||
logger.debug(
|
||||
`Error getting channel with id ${channel.id}: %o`,
|
||||
channelError
|
||||
);
|
||||
|
||||
let partnerFees = {};
|
||||
if (!channelError && publicKey) {
|
||||
const partnerPolicy = channelInfo.policies.filter(
|
||||
policy => policy.public_key !== publicKey
|
||||
);
|
||||
if (partnerPolicy && partnerPolicy.length >= 1) {
|
||||
partnerFees = {
|
||||
base_fee: partnerPolicy[0].base_fee_mtokens || 0,
|
||||
fee_rate: partnerPolicy[0].fee_rate || 0,
|
||||
cltv_delta: partnerPolicy[0].cltv_delta || 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const partner_node_info = {
|
||||
...(!nodeError && nodeInfo),
|
||||
...partnerFees,
|
||||
};
|
||||
|
||||
return {
|
||||
...channel,
|
||||
time_offline: Math.round((channel.time_offline || 0) / 1000),
|
||||
time_online: Math.round((channel.time_online || 0) / 1000),
|
||||
partner_node_info,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const channels = await getChannelList();
|
||||
return channels;
|
||||
return channels.map(channel => ({
|
||||
...channel,
|
||||
time_offline: Math.round((channel.time_offline || 0) / 1000),
|
||||
time_online: Math.round((channel.time_online || 0) / 1000),
|
||||
partner_node_info: { lnd, publicKey: channel.partner_public_key },
|
||||
partner_fee_info: { lnd, id: channel.id, dontResolve: public_key },
|
||||
}));
|
||||
};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { getClosedChannels as getLnClosedChannels, getNode } from 'ln-service';
|
||||
import { getClosedChannels as getLnClosedChannels } from 'ln-service';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { to, toWithError } from 'server/helpers/async';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { getAuthLnd, getCorrectAuth } from 'server/helpers/helpers';
|
||||
|
||||
|
@ -36,31 +35,13 @@ export const getClosedChannels = async (
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const closedChannels: ChannelListProps = await to(
|
||||
getLnClosedChannels({ lnd })
|
||||
);
|
||||
const { channels }: ChannelListProps = await to(getLnClosedChannels({ lnd }));
|
||||
|
||||
const channels = closedChannels.channels.map(async channel => {
|
||||
const [nodeInfo, nodeError] = await toWithError(
|
||||
getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: channel.partner_public_key,
|
||||
})
|
||||
);
|
||||
|
||||
nodeError &&
|
||||
logger.debug(
|
||||
`Error getting node with public key ${channel.partner_public_key}: %o`,
|
||||
nodeError
|
||||
);
|
||||
|
||||
return {
|
||||
...channel,
|
||||
partner_node_info: {
|
||||
...(!nodeError && nodeInfo),
|
||||
},
|
||||
};
|
||||
});
|
||||
return channels;
|
||||
return channels.map(channel => ({
|
||||
...channel,
|
||||
partner_node_info: {
|
||||
lnd,
|
||||
publicKey: channel.partner_public_key,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import {
|
||||
getPendingChannels as getLnPendingChannels,
|
||||
getNode,
|
||||
} from 'ln-service';
|
||||
import { getPendingChannels as getLnPendingChannels } from 'ln-service';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { to, toWithError } from 'server/helpers/async';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { getAuthLnd, getCorrectAuth } from 'server/helpers/helpers';
|
||||
|
||||
|
@ -39,31 +35,15 @@ export const getPendingChannels = async (
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const pendingChannels: PendingChannelListProps = await to(
|
||||
const { pending_channels }: PendingChannelListProps = await to(
|
||||
getLnPendingChannels({ lnd })
|
||||
);
|
||||
|
||||
const channels = pendingChannels.pending_channels.map(async channel => {
|
||||
const [nodeInfo, nodeError] = await toWithError(
|
||||
getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: channel.partner_public_key,
|
||||
})
|
||||
);
|
||||
|
||||
nodeError &&
|
||||
logger.debug(
|
||||
`Error getting node with public key ${channel.partner_public_key}: %o`,
|
||||
nodeError
|
||||
);
|
||||
|
||||
return {
|
||||
...channel,
|
||||
partner_node_info: {
|
||||
...(!nodeError && nodeInfo),
|
||||
},
|
||||
};
|
||||
});
|
||||
return channels;
|
||||
return pending_channels.map(channel => ({
|
||||
...channel,
|
||||
partner_node_info: {
|
||||
lnd,
|
||||
publicKey: channel.partner_public_key,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
|
|
@ -1,6 +1,32 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const channelTypes = gql`
|
||||
type policyType {
|
||||
base_fee_mtokens: String
|
||||
cltv_delta: Int
|
||||
fee_rate: Int
|
||||
is_disabled: Boolean
|
||||
max_htlc_mtokens: String
|
||||
min_htlc_mtokens: String
|
||||
public_key: String!
|
||||
updated_at: String
|
||||
my_node: Boolean
|
||||
node: Node
|
||||
}
|
||||
|
||||
type singleChannelType {
|
||||
capacity: Int!
|
||||
id: String!
|
||||
policies: [policyType!]!
|
||||
transaction_id: String!
|
||||
transaction_vout: Int!
|
||||
updated_at: String
|
||||
}
|
||||
|
||||
type Channel {
|
||||
channel: singleChannelType
|
||||
}
|
||||
|
||||
type channelFeeType {
|
||||
alias: String
|
||||
color: String
|
||||
|
@ -46,7 +72,8 @@ export const channelTypes = gql`
|
|||
transaction_id: String
|
||||
transaction_vout: Int
|
||||
unsettled_balance: Int
|
||||
partner_node_info: nodeType
|
||||
partner_node_info: Node
|
||||
partner_fee_info: Channel
|
||||
}
|
||||
|
||||
type closeChannelType {
|
||||
|
@ -69,7 +96,7 @@ export const channelTypes = gql`
|
|||
partner_public_key: String
|
||||
transaction_id: String
|
||||
transaction_vout: Int
|
||||
partner_node_info: nodeType
|
||||
partner_node_info: Node
|
||||
}
|
||||
|
||||
type openChannelType {
|
||||
|
@ -92,6 +119,6 @@ export const channelTypes = gql`
|
|||
transaction_fee: Int
|
||||
transaction_id: String
|
||||
transaction_vout: Int
|
||||
partner_node_info: nodeType
|
||||
partner_node_info: Node
|
||||
}
|
||||
`;
|
||||
|
|
28
server/schema/github/resolvers.ts
Normal file
28
server/schema/github/resolvers.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { toWithError } from 'server/helpers/async';
|
||||
import { appUrls } from 'server/utils/appUrls';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
|
||||
export const githubResolvers = {
|
||||
Query: {
|
||||
getLatestVersion: async (
|
||||
_: undefined,
|
||||
params: any,
|
||||
context: ContextType
|
||||
) => {
|
||||
await requestLimiter(context.ip, 'getLnPay');
|
||||
|
||||
const [response, error] = await toWithError(fetch(appUrls.github));
|
||||
|
||||
if (error) {
|
||||
logger.debug('Unable to get latest github version');
|
||||
throw new Error('NoGithubVersion');
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
return json.tag_name;
|
||||
},
|
||||
},
|
||||
};
|
72
server/schema/health/helpers.ts
Normal file
72
server/schema/health/helpers.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { groupBy } from 'underscore';
|
||||
|
||||
export const getChannelVolume = forwards => {
|
||||
const orderedIncoming = groupBy(forwards, f => f.incoming_channel);
|
||||
const orderedOutgoing = groupBy(forwards, f => f.outgoing_channel);
|
||||
|
||||
const reducedIncoming = reduceTokens(orderedIncoming);
|
||||
const reducedOutgoing = reduceTokens(orderedOutgoing);
|
||||
|
||||
const together = groupBy(
|
||||
[...reducedIncoming, ...reducedOutgoing],
|
||||
c => c.channel
|
||||
);
|
||||
return reduceTokens(together);
|
||||
};
|
||||
|
||||
const reduceTokens = array => {
|
||||
const reducedArray = [];
|
||||
for (const key in array) {
|
||||
if (Object.prototype.hasOwnProperty.call(array, key)) {
|
||||
const channel = array[key];
|
||||
const reduced = channel.reduce((a, b) => a + b.tokens, 0);
|
||||
reducedArray.push({ channel: key, tokens: reduced });
|
||||
}
|
||||
}
|
||||
return reducedArray;
|
||||
};
|
||||
|
||||
export const getChannelIdInfo = (
|
||||
id: string
|
||||
): { blockHeight: number; transaction: number; output: number } | null => {
|
||||
const format = /^\d*x\d*x\d*$/;
|
||||
|
||||
if (!format.test(id)) return null;
|
||||
|
||||
const separate = id.split('x');
|
||||
|
||||
return {
|
||||
blockHeight: Number(separate[0]),
|
||||
transaction: Number(separate[1]),
|
||||
output: Number(separate[2]),
|
||||
};
|
||||
};
|
||||
|
||||
export const getAverage = (array: number[]): number => {
|
||||
const sum = array.reduce((a, b) => a + b, 0);
|
||||
return sum / array.length || 0;
|
||||
};
|
||||
|
||||
export const getFeeScore = (max: number, current: number): number => {
|
||||
const score = Math.round(((max - current) / max) * 100);
|
||||
return Math.max(0, Math.min(100, score));
|
||||
};
|
||||
|
||||
export const getMyFeeScore = (
|
||||
max: number,
|
||||
current: number,
|
||||
min: number
|
||||
): { over: boolean; score: number } => {
|
||||
if (current === min) {
|
||||
return { over: false, score: 100 };
|
||||
}
|
||||
if (current < min) {
|
||||
const score = Math.round(((min - current) / min) * 100);
|
||||
return { over: false, score: 100 - Math.max(0, Math.min(100, score)) };
|
||||
}
|
||||
const minimum = current - min;
|
||||
const maximum = max - min;
|
||||
const score = Math.round(((maximum - minimum) / maximum) * 100);
|
||||
|
||||
return { over: true, score: Math.max(0, Math.min(100, score)) };
|
||||
};
|
11
server/schema/health/resolvers.ts
Normal file
11
server/schema/health/resolvers.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import getVolumeHealth from './resolvers/getVolumeHealth';
|
||||
import getTimeHealth from './resolvers/getTimeHealth';
|
||||
import getFeeHealth from './resolvers/getFeeHealth';
|
||||
|
||||
export const healthResolvers = {
|
||||
Query: {
|
||||
getVolumeHealth,
|
||||
getTimeHealth,
|
||||
getFeeHealth,
|
||||
},
|
||||
};
|
132
server/schema/health/resolvers/getFeeHealth.ts
Normal file
132
server/schema/health/resolvers/getFeeHealth.ts
Normal file
|
@ -0,0 +1,132 @@
|
|||
import { getChannels, getChannel, getWalletInfo } from 'ln-service';
|
||||
import { getCorrectAuth, getAuthLnd } from 'server/helpers/helpers';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { to, toWithError } from 'server/helpers/async';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { getFeeScore, getAverage, getMyFeeScore } from '../helpers';
|
||||
|
||||
type ChannelFeesType = {
|
||||
id: string;
|
||||
publicKey: string;
|
||||
partnerBaseFee: number;
|
||||
partnerFeeRate: number;
|
||||
myBaseFee: number;
|
||||
myFeeRate: number;
|
||||
};
|
||||
|
||||
export default async (_: undefined, params: any, context: ContextType) => {
|
||||
await requestLimiter(context.ip, 'getFeeHealth');
|
||||
|
||||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const { public_key } = await to(getWalletInfo({ lnd }));
|
||||
const { channels } = await to(getChannels({ lnd }));
|
||||
|
||||
const getChannelList = () =>
|
||||
Promise.all(
|
||||
channels
|
||||
.map(async channel => {
|
||||
const { id, partner_public_key: publicKey } = channel;
|
||||
const [{ policies }, channelError] = await toWithError(
|
||||
getChannel({
|
||||
lnd,
|
||||
id,
|
||||
})
|
||||
);
|
||||
|
||||
if (channelError) {
|
||||
logger.debug(
|
||||
`Error getting channel with id ${id}: %o`,
|
||||
channelError
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let partnerBaseFee = 0;
|
||||
let partnerFeeRate = 0;
|
||||
let myBaseFee = 0;
|
||||
let myFeeRate = 0;
|
||||
|
||||
if (!channelError && policies) {
|
||||
for (let i = 0; i < policies.length; i++) {
|
||||
const policy = policies[i];
|
||||
|
||||
if (policy.public_key === public_key) {
|
||||
myBaseFee = Number(policy.base_fee_mtokens);
|
||||
myFeeRate = policy.fee_rate;
|
||||
} else {
|
||||
partnerBaseFee = Number(policy.base_fee_mtokens);
|
||||
partnerFeeRate = policy.fee_rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
publicKey,
|
||||
partnerBaseFee,
|
||||
partnerFeeRate,
|
||||
myBaseFee,
|
||||
myFeeRate,
|
||||
};
|
||||
})
|
||||
.filter(Boolean)
|
||||
);
|
||||
|
||||
const list = await getChannelList();
|
||||
|
||||
const health = list.map((channel: ChannelFeesType) => {
|
||||
const partnerRateScore = getFeeScore(2000, channel.partnerFeeRate);
|
||||
const partnerBaseScore = getFeeScore(100000, channel.partnerBaseFee);
|
||||
const myRateScore = getMyFeeScore(2000, channel.myFeeRate, 200);
|
||||
const myBaseScore = getMyFeeScore(100000, channel.myBaseFee, 1000);
|
||||
|
||||
const partnerScore = Math.round(
|
||||
getAverage([partnerBaseScore, partnerRateScore])
|
||||
);
|
||||
const myScore = Math.round(
|
||||
getAverage([myRateScore.score, myBaseScore.score])
|
||||
);
|
||||
|
||||
const mySide = {
|
||||
score: myScore,
|
||||
rate: channel.myFeeRate,
|
||||
base: Math.round(channel.myBaseFee / 1000),
|
||||
rateScore: myRateScore.score,
|
||||
baseScore: myBaseScore.score,
|
||||
rateOver: myRateScore.over,
|
||||
baseOver: myBaseScore.over,
|
||||
};
|
||||
|
||||
const partnerSide = {
|
||||
score: partnerScore,
|
||||
rate: channel.partnerFeeRate,
|
||||
base: Math.round(channel.partnerBaseFee / 1000),
|
||||
rateScore: partnerRateScore,
|
||||
baseScore: partnerBaseScore,
|
||||
rateOver: true,
|
||||
baseOver: true,
|
||||
};
|
||||
|
||||
return {
|
||||
id: channel.id,
|
||||
partnerSide,
|
||||
mySide,
|
||||
partner: { publicKey: channel.publicKey, lnd },
|
||||
};
|
||||
});
|
||||
|
||||
const score = Math.round(
|
||||
getAverage([
|
||||
...health.map(c => c.partnerSide.score),
|
||||
...health.map(c => c.mySide.score),
|
||||
])
|
||||
);
|
||||
|
||||
return {
|
||||
score,
|
||||
channels: health,
|
||||
};
|
||||
};
|
51
server/schema/health/resolvers/getTimeHealth.ts
Normal file
51
server/schema/health/resolvers/getTimeHealth.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { getChannels } from 'ln-service';
|
||||
import { getCorrectAuth, getAuthLnd } from 'server/helpers/helpers';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { getAverage } from '../helpers';
|
||||
|
||||
const halfMonthInMilliSeconds = 1296000000;
|
||||
|
||||
export default async (_: undefined, params: any, context: ContextType) => {
|
||||
await requestLimiter(context.ip, 'getTimeHealth');
|
||||
|
||||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const { channels } = await to(getChannels({ lnd }));
|
||||
|
||||
const health = channels.map(channel => {
|
||||
const {
|
||||
time_offline = 1,
|
||||
time_online = 1,
|
||||
id,
|
||||
partner_public_key,
|
||||
} = channel;
|
||||
|
||||
const significant = time_offline + time_online > halfMonthInMilliSeconds;
|
||||
|
||||
const defaultProps = {
|
||||
id,
|
||||
significant,
|
||||
monitoredTime: Math.round((time_online + time_offline) / 1000),
|
||||
monitoredUptime: Math.round(time_online / 1000),
|
||||
monitoredDowntime: Math.round(time_offline / 1000),
|
||||
partner: { publicKey: partner_public_key, lnd },
|
||||
};
|
||||
|
||||
const percentOnline = time_online / (time_online + time_offline);
|
||||
|
||||
return {
|
||||
score: Math.round(percentOnline * 100),
|
||||
...defaultProps,
|
||||
};
|
||||
});
|
||||
|
||||
const average = Math.round(getAverage(health.map(c => c.score)));
|
||||
|
||||
return {
|
||||
score: average,
|
||||
channels: health,
|
||||
};
|
||||
};
|
68
server/schema/health/resolvers/getVolumeHealth.ts
Normal file
68
server/schema/health/resolvers/getVolumeHealth.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import { getForwards, getChannels, getWalletInfo } from 'ln-service';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { getCorrectAuth, getAuthLnd } from 'server/helpers/helpers';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { subMonths } from 'date-fns';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { getChannelVolume, getChannelIdInfo, getAverage } from '../helpers';
|
||||
|
||||
const monthInBlocks = 4380;
|
||||
|
||||
export default async (_: undefined, params: any, context: ContextType) => {
|
||||
await requestLimiter(context.ip, 'getVolumeHealth');
|
||||
|
||||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
const before = new Date().toISOString();
|
||||
const after = subMonths(new Date(), 1).toISOString();
|
||||
|
||||
const { current_block_height } = await to(getWalletInfo({ lnd }));
|
||||
const { channels } = await to(getChannels({ lnd }));
|
||||
const { forwards } = await to(getForwards({ lnd, after, before }));
|
||||
|
||||
const channelVolume = getChannelVolume(forwards);
|
||||
|
||||
const channelDetails = channels
|
||||
.map(channel => {
|
||||
const { tokens } =
|
||||
channelVolume.find(c => c.channel === channel.id) || {};
|
||||
const info = getChannelIdInfo(channel.id);
|
||||
|
||||
if (!info) return;
|
||||
|
||||
const age = Math.min(
|
||||
current_block_height - info.blockHeight,
|
||||
monthInBlocks
|
||||
);
|
||||
|
||||
return {
|
||||
id: channel.id,
|
||||
volume: tokens,
|
||||
volumeNormalized: Math.round(tokens / age) || 0,
|
||||
publicKey: channel.partner_public_key,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
const average = getAverage(channelDetails.map(c => c.volumeNormalized));
|
||||
|
||||
const health = channelDetails.map(channel => {
|
||||
const diff = (channel.volumeNormalized - average) / average || -1;
|
||||
const score = Math.round((diff + 1) * 100);
|
||||
|
||||
return {
|
||||
id: channel.id,
|
||||
score,
|
||||
volumeNormalized: channel.volumeNormalized,
|
||||
averageVolumeNormalized: average,
|
||||
partner: { publicKey: channel.publicKey, lnd },
|
||||
};
|
||||
});
|
||||
|
||||
const globalAverage = Math.round(
|
||||
getAverage(health.map(c => Math.min(c.score, 100)))
|
||||
);
|
||||
|
||||
return { score: globalAverage, channels: health };
|
||||
};
|
53
server/schema/health/types.ts
Normal file
53
server/schema/health/types.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const healthTypes = gql`
|
||||
type channelHealth {
|
||||
id: String
|
||||
score: Int
|
||||
volumeNormalized: String
|
||||
averageVolumeNormalized: String
|
||||
partner: Node
|
||||
}
|
||||
|
||||
type channelsHealth {
|
||||
score: Int
|
||||
channels: [channelHealth]
|
||||
}
|
||||
|
||||
type channelTimeHealth {
|
||||
id: String
|
||||
score: Int
|
||||
significant: Boolean
|
||||
monitoredTime: Int
|
||||
monitoredUptime: Int
|
||||
monitoredDowntime: Int
|
||||
partner: Node
|
||||
}
|
||||
|
||||
type channelsTimeHealth {
|
||||
score: Int
|
||||
channels: [channelTimeHealth]
|
||||
}
|
||||
|
||||
type feeHealth {
|
||||
score: Int
|
||||
rate: Int
|
||||
base: String
|
||||
rateScore: Int
|
||||
baseScore: Int
|
||||
rateOver: Boolean
|
||||
baseOver: Boolean
|
||||
}
|
||||
|
||||
type channelFeeHealth {
|
||||
id: String
|
||||
partnerSide: feeHealth
|
||||
mySide: feeHealth
|
||||
partner: Node
|
||||
}
|
||||
|
||||
type channelsFeeHealth {
|
||||
score: Int
|
||||
channels: [channelFeeHealth]
|
||||
}
|
||||
`;
|
|
@ -32,6 +32,9 @@ import { walletTypes } from './wallet/types';
|
|||
import { invoiceTypes } from './invoice/types';
|
||||
import { networkTypes } from './network/types';
|
||||
import { transactionTypes } from './transactions/types';
|
||||
import { healthResolvers } from './health/resolvers';
|
||||
import { healthTypes } from './health/types';
|
||||
import { githubResolvers } from './github/resolvers';
|
||||
|
||||
const typeDefs = [
|
||||
generalTypes,
|
||||
|
@ -52,6 +55,7 @@ const typeDefs = [
|
|||
invoiceTypes,
|
||||
networkTypes,
|
||||
transactionTypes,
|
||||
healthTypes,
|
||||
];
|
||||
|
||||
const resolvers = merge(
|
||||
|
@ -70,7 +74,9 @@ const resolvers = merge(
|
|||
invoiceResolvers,
|
||||
channelResolvers,
|
||||
walletResolvers,
|
||||
transactionResolvers
|
||||
transactionResolvers,
|
||||
healthResolvers,
|
||||
githubResolvers
|
||||
);
|
||||
|
||||
export default makeExecutableSchema({ typeDefs, resolvers });
|
||||
|
|
|
@ -47,7 +47,7 @@ export const invoiceTypes = gql`
|
|||
timeout: Int
|
||||
}
|
||||
|
||||
type invoiceType {
|
||||
type newInvoiceType {
|
||||
chainAddress: String
|
||||
createdAt: DateTime
|
||||
description: String
|
||||
|
|
|
@ -27,7 +27,7 @@ export const lnpayResolvers = {
|
|||
const [response, error] = await toWithError(fetch(appUrls.lnpay));
|
||||
|
||||
if (error) {
|
||||
logger.debug('Unable to get lnpay: %o', error);
|
||||
logger.debug('Unable to connect to ThunderHub LNPAY');
|
||||
throw new Error('NoLnPay');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@ import {
|
|||
getWalletInfo,
|
||||
getClosedChannels,
|
||||
} from 'ln-service';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { to, toWithError } from 'server/helpers/async';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import { getAuthLnd, getErrorMsg, getCorrectAuth } from '../../helpers/helpers';
|
||||
import { ContextType } from '../../types/apiTypes';
|
||||
import { logger } from '../../helpers/logger';
|
||||
|
||||
const errorNode = { alias: 'Node not found' };
|
||||
|
||||
export const nodeResolvers = {
|
||||
Query: {
|
||||
getNode: async (_: undefined, params: any, context: ContextType) => {
|
||||
|
@ -53,4 +55,34 @@ export const nodeResolvers = {
|
|||
};
|
||||
},
|
||||
},
|
||||
Node: {
|
||||
node: async parent => {
|
||||
const { lnd, withChannels, publicKey } = parent;
|
||||
|
||||
if (!lnd) {
|
||||
logger.debug('ExpectedLNDToGetNode');
|
||||
return errorNode;
|
||||
}
|
||||
|
||||
if (!publicKey) {
|
||||
logger.debug('ExpectedPublicKeyToGetNode');
|
||||
return errorNode;
|
||||
}
|
||||
|
||||
const [info, error] = await toWithError(
|
||||
getLnNode({
|
||||
lnd,
|
||||
is_omitting_channels: !withChannels,
|
||||
public_key: publicKey,
|
||||
})
|
||||
);
|
||||
|
||||
if (error) {
|
||||
logger.debug(`Error getting node with key: ${publicKey}`);
|
||||
return errorNode;
|
||||
}
|
||||
|
||||
return { ...info, public_key: publicKey };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const nodeTypes = gql`
|
||||
type nodeType {
|
||||
alias: String
|
||||
capacity: String
|
||||
channel_count: Int
|
||||
color: String
|
||||
updated_at: String
|
||||
base_fee: Int
|
||||
fee_rate: Int
|
||||
cltv_delta: Int
|
||||
public_key: String
|
||||
}
|
||||
|
||||
type Node {
|
||||
node: nodeType
|
||||
}
|
||||
|
||||
type nodeInfoType {
|
||||
chains: [String]
|
||||
color: String
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getPeers, getNode, removePeer, addPeer } from 'ln-service';
|
||||
import { getPeers, removePeer, addPeer } from 'ln-service';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
|
@ -7,6 +7,7 @@ import {
|
|||
getErrorMsg,
|
||||
getCorrectAuth,
|
||||
} from 'server/helpers/helpers';
|
||||
import { to } from 'server/helpers/async';
|
||||
|
||||
interface PeerProps {
|
||||
bytes_received: number;
|
||||
|
@ -28,39 +29,16 @@ export const peerResolvers = {
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
try {
|
||||
const { peers }: { peers: PeerProps[] } = await getPeers({
|
||||
const { peers }: { peers: PeerProps[] } = await to(
|
||||
getPeers({
|
||||
lnd,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const getPeerList = () =>
|
||||
Promise.all(
|
||||
peers.map(async peer => {
|
||||
try {
|
||||
const nodeInfo = await getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: peer.public_key,
|
||||
});
|
||||
|
||||
return {
|
||||
...peer,
|
||||
partner_node_info: {
|
||||
...nodeInfo,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return { ...peer, partner_node_info: {} };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const peerList = await getPeerList();
|
||||
return peerList;
|
||||
} catch (error) {
|
||||
logger.error('Error getting peers: %o', error);
|
||||
throw new Error(getErrorMsg(error));
|
||||
}
|
||||
return peers.map(peer => ({
|
||||
...peer,
|
||||
partner_node_info: { lnd, publicKey: peer.public_key },
|
||||
}));
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
|
|
|
@ -11,6 +11,6 @@ export const peerTypes = gql`
|
|||
socket: String
|
||||
tokens_received: Int
|
||||
tokens_sent: Int
|
||||
partner_node_info: nodeType
|
||||
partner_node_info: Node
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
import { getNodeFromChannel } from 'server/helpers/getNodeFromChannel';
|
||||
import {
|
||||
getPayments,
|
||||
getInvoices,
|
||||
getNode,
|
||||
getForwards as getLnForwards,
|
||||
getWalletInfo,
|
||||
} from 'ln-service';
|
||||
import { compareDesc, subHours, subDays, subMonths, subYears } from 'date-fns';
|
||||
import { sortBy } from 'underscore';
|
||||
import { ContextType } from 'server/types/apiTypes';
|
||||
import { logger } from 'server/helpers/logger';
|
||||
import { requestLimiter } from 'server/helpers/rateLimiter';
|
||||
import {
|
||||
getAuthLnd,
|
||||
getErrorMsg,
|
||||
getCorrectAuth,
|
||||
} from 'server/helpers/helpers';
|
||||
import { getAuthLnd, getCorrectAuth } from 'server/helpers/helpers';
|
||||
import { to } from 'server/helpers/async';
|
||||
import { ForwardCompleteProps } from '../widgets/resolvers/interface';
|
||||
import { PaymentsProps, InvoicesProps, NodeProps } from './interface';
|
||||
import { PaymentsProps, InvoicesProps } from './interface';
|
||||
|
||||
export const transactionResolvers = {
|
||||
Query: {
|
||||
|
@ -27,41 +21,6 @@ export const transactionResolvers = {
|
|||
const auth = getCorrectAuth(params.auth, context);
|
||||
const lnd = getAuthLnd(auth);
|
||||
|
||||
let payments;
|
||||
let invoices;
|
||||
|
||||
try {
|
||||
const paymentList: PaymentsProps = await getPayments({
|
||||
lnd,
|
||||
});
|
||||
|
||||
const getMappedPayments = () =>
|
||||
Promise.all(
|
||||
paymentList.payments.map(async payment => {
|
||||
let nodeInfo: NodeProps;
|
||||
try {
|
||||
nodeInfo = await getNode({
|
||||
lnd,
|
||||
is_omitting_channels: true,
|
||||
public_key: payment.destination,
|
||||
});
|
||||
} catch (error) {
|
||||
nodeInfo = { alias: payment.destination?.substring(0, 6) };
|
||||
}
|
||||
return {
|
||||
type: 'payment',
|
||||
alias: nodeInfo.alias,
|
||||
date: payment.created_at,
|
||||
...payment,
|
||||
};
|
||||
})
|
||||
);
|
||||
payments = await getMappedPayments();
|
||||
} catch (error) {
|
||||
logger.error('Error getting payments: %o', error);
|
||||
throw new Error(getErrorMsg(error));
|
||||
}
|
||||
|
||||
const invoiceProps = params.token
|
||||
? { token: params.token }
|
||||
: { limit: 25 };
|
||||
|
@ -71,33 +30,46 @@ export const transactionResolvers = {
|
|||
let token = '';
|
||||
let withInvoices = true;
|
||||
|
||||
try {
|
||||
const invoiceList: InvoicesProps = await getInvoices({
|
||||
const invoiceList: InvoicesProps = await to(
|
||||
getInvoices({
|
||||
lnd,
|
||||
...invoiceProps,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
invoices = invoiceList.invoices.map(invoice => {
|
||||
return {
|
||||
type: 'invoice',
|
||||
date: invoice.confirmed_at || invoice.created_at,
|
||||
...invoice,
|
||||
};
|
||||
});
|
||||
const invoices = invoiceList.invoices.map(invoice => {
|
||||
return {
|
||||
type: 'invoice',
|
||||
date: invoice.confirmed_at || invoice.created_at,
|
||||
...invoice,
|
||||
isTypeOf: 'InvoiceType',
|
||||
};
|
||||
});
|
||||
|
||||
if (invoices.length <= 0) {
|
||||
withInvoices = false;
|
||||
} else {
|
||||
const { date } = invoices[invoices.length - 1];
|
||||
firstInvoiceDate = invoices[0].date;
|
||||
lastInvoiceDate = date;
|
||||
token = invoiceList.next;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error getting invoices: %o', error);
|
||||
throw new Error(getErrorMsg(error));
|
||||
if (invoices.length <= 0) {
|
||||
withInvoices = false;
|
||||
} else {
|
||||
const { date } = invoices[invoices.length - 1];
|
||||
firstInvoiceDate = invoices[0].date;
|
||||
lastInvoiceDate = date;
|
||||
token = invoiceList.next;
|
||||
}
|
||||
|
||||
const paymentList: PaymentsProps = await to(
|
||||
getPayments({
|
||||
lnd,
|
||||
})
|
||||
);
|
||||
|
||||
const payments = paymentList.payments.map(payment => ({
|
||||
...payment,
|
||||
type: 'payment',
|
||||
date: payment.created_at,
|
||||
destination_node: { lnd, publicKey: payment.destination },
|
||||
hops: [...payment.hops.map(hop => ({ lnd, publicKey: hop }))],
|
||||
isTypeOf: 'PaymentType',
|
||||
}));
|
||||
|
||||
const filterArray = payment => {
|
||||
const last =
|
||||
compareDesc(new Date(lastInvoiceDate), new Date(payment.date)) === 1;
|
||||
|
@ -112,14 +84,14 @@ export const transactionResolvers = {
|
|||
? payments.filter(filterArray)
|
||||
: payments;
|
||||
|
||||
const resumeArray = sortBy(
|
||||
const resume = sortBy(
|
||||
[...invoices, ...filteredPayments],
|
||||
'date'
|
||||
).reverse();
|
||||
|
||||
return {
|
||||
token,
|
||||
resume: JSON.stringify(resumeArray),
|
||||
resume,
|
||||
};
|
||||
},
|
||||
getForwards: async (_: undefined, params: any, context: ContextType) => {
|
||||
|
@ -145,54 +117,44 @@ export const transactionResolvers = {
|
|||
startDate = subHours(endDate, 24);
|
||||
}
|
||||
|
||||
const walletInfo: { public_key: string } = await getWalletInfo({
|
||||
lnd,
|
||||
});
|
||||
const { public_key } = await to(
|
||||
getWalletInfo({
|
||||
lnd,
|
||||
})
|
||||
);
|
||||
|
||||
const getAlias = (array: any[], publicKey: string) =>
|
||||
Promise.all(
|
||||
array.map(async forward => {
|
||||
const inNodeAlias = await getNodeFromChannel(
|
||||
forward.incoming_channel,
|
||||
publicKey,
|
||||
lnd
|
||||
);
|
||||
const outNodeAlias = await getNodeFromChannel(
|
||||
forward.outgoing_channel,
|
||||
publicKey,
|
||||
lnd
|
||||
);
|
||||
return {
|
||||
incoming_alias: inNodeAlias.alias,
|
||||
incoming_color: inNodeAlias.color,
|
||||
outgoing_alias: outNodeAlias.alias,
|
||||
outgoing_color: outNodeAlias.color,
|
||||
...forward,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
try {
|
||||
const forwardsList: ForwardCompleteProps = await getLnForwards({
|
||||
const forwardsList: ForwardCompleteProps = await to(
|
||||
getLnForwards({
|
||||
lnd,
|
||||
after: startDate,
|
||||
before: endDate,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
const list = await getAlias(
|
||||
forwardsList.forwards,
|
||||
walletInfo.public_key
|
||||
);
|
||||
const list = forwardsList.forwards.map(forward => ({
|
||||
...forward,
|
||||
incoming_channel_info: {
|
||||
lnd,
|
||||
id: forward.incoming_channel,
|
||||
dontResolveKey: public_key,
|
||||
},
|
||||
outgoing_channel_info: {
|
||||
lnd,
|
||||
id: forward.outgoing_channel,
|
||||
dontResolveKey: public_key,
|
||||
},
|
||||
}));
|
||||
|
||||
const forwards = sortBy(list, 'created_at').reverse();
|
||||
return {
|
||||
token: forwardsList.next,
|
||||
forwards,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('Error getting forwards: %o', error);
|
||||
throw new Error(getErrorMsg(error));
|
||||
}
|
||||
const forwards = sortBy(list, 'created_at').reverse();
|
||||
return {
|
||||
token: forwardsList.next,
|
||||
forwards,
|
||||
};
|
||||
},
|
||||
},
|
||||
Transaction: {
|
||||
__resolveType(parent) {
|
||||
return parent.isTypeOf;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -11,17 +11,60 @@ export const transactionTypes = gql`
|
|||
fee: Int
|
||||
fee_mtokens: String
|
||||
incoming_channel: String
|
||||
incoming_alias: String
|
||||
incoming_color: String
|
||||
mtokens: String
|
||||
outgoing_channel: String
|
||||
outgoing_alias: String
|
||||
outgoing_color: String
|
||||
tokens: Int
|
||||
incoming_channel_info: Channel
|
||||
outgoing_channel_info: Channel
|
||||
}
|
||||
|
||||
type PaymentType {
|
||||
created_at: String!
|
||||
destination: String!
|
||||
destination_node: Node
|
||||
fee: Int!
|
||||
fee_mtokens: String!
|
||||
hops: [Node]
|
||||
id: String!
|
||||
index: Int
|
||||
is_confirmed: Boolean!
|
||||
is_outgoing: Boolean!
|
||||
mtokens: String!
|
||||
request: String
|
||||
safe_fee: Int!
|
||||
safe_tokens: Int
|
||||
secret: String!
|
||||
tokens: Int!
|
||||
type: String!
|
||||
date: String!
|
||||
}
|
||||
|
||||
type InvoiceType {
|
||||
chain_address: String
|
||||
confirmed_at: String
|
||||
created_at: String!
|
||||
description: String!
|
||||
description_hash: String
|
||||
expires_at: String!
|
||||
id: String!
|
||||
is_canceled: Boolean
|
||||
is_confirmed: Boolean!
|
||||
is_held: Boolean
|
||||
is_private: Boolean!
|
||||
is_push: Boolean
|
||||
received: Int!
|
||||
received_mtokens: String!
|
||||
request: String
|
||||
secret: String!
|
||||
tokens: Int!
|
||||
type: String!
|
||||
date: String!
|
||||
}
|
||||
|
||||
union Transaction = InvoiceType | PaymentType
|
||||
|
||||
type getResumeType {
|
||||
token: String
|
||||
resume: String
|
||||
resume: [Transaction]
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -9,17 +9,6 @@ export const generalTypes = gql`
|
|||
cert: String
|
||||
}
|
||||
|
||||
type nodeType {
|
||||
alias: String
|
||||
capacity: String
|
||||
channel_count: Int
|
||||
color: String
|
||||
updated_at: String
|
||||
base_fee: Int
|
||||
fee_rate: Int
|
||||
cltv_delta: Int
|
||||
}
|
||||
|
||||
# A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the
|
||||
# date-time format outlined in section 5.6 of the RFC 3339 profile of the ISO
|
||||
# 8601 standard for representation of dates and times using the Gregorian calendar.
|
||||
|
@ -28,6 +17,9 @@ export const generalTypes = gql`
|
|||
|
||||
export const queryTypes = gql`
|
||||
type Query {
|
||||
getVolumeHealth(auth: authType!): channelsHealth
|
||||
getTimeHealth(auth: authType!): channelsTimeHealth
|
||||
getFeeHealth(auth: authType!): channelsFeeHealth
|
||||
getChannelBalance(auth: authType!): channelBalanceType
|
||||
getChannels(auth: authType!, active: Boolean): [channelType]
|
||||
getClosedChannels(auth: authType!, type: String): [closedChannelType]
|
||||
|
@ -87,6 +79,7 @@ export const queryTypes = gql`
|
|||
getServerAccounts: [serverAccountType]
|
||||
getLnPayInfo: lnPayInfoType
|
||||
getLnPay(amount: Int): String
|
||||
getLatestVersion: String
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -115,7 +108,7 @@ export const mutationTypes = gql`
|
|||
): Boolean
|
||||
parsePayment(auth: authType!, request: String!): parsePaymentType
|
||||
pay(auth: authType!, request: String!, tokens: Int): payType
|
||||
createInvoice(auth: authType!, amount: Int!): invoiceType
|
||||
createInvoice(auth: authType!, amount: Int!): newInvoiceType
|
||||
payViaRoute(auth: authType!, route: String!): Boolean
|
||||
createAddress(auth: authType!, nested: Boolean): String
|
||||
sendToAddress(
|
||||
|
|
|
@ -4,8 +4,10 @@ const lnpay =
|
|||
: 'https://thunderhub.io/api/lnpay';
|
||||
|
||||
export const appUrls = {
|
||||
lnpay,
|
||||
fees: 'https://bitcoinfees.earn.com/api/v1/fees/recommended',
|
||||
ticker: 'https://blockchain.info/ticker',
|
||||
hodlhodl: 'https://hodlhodl.com/api',
|
||||
lnpay,
|
||||
github: 'https://api.github.com/repos/apotdevin/thunderhub/releases/latest',
|
||||
update: 'https://github.com/apotdevin/thunderhub#updating',
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
colorButtonBackground,
|
||||
colorButtonBorder,
|
||||
hoverTextColor,
|
||||
themeColors,
|
||||
} from '../../styles/Themes';
|
||||
|
||||
export const CardWithTitle = styled.div`
|
||||
|
@ -238,3 +239,15 @@ export const ResponsiveSingle = styled(SingleLine)`
|
|||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const CopyIcon = styled.span`
|
||||
cursor: pointer;
|
||||
margin-left: 4px;
|
||||
padding: 0 4px;
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover {
|
||||
background-color: ${themeColors.blue2};
|
||||
color: white;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -5,8 +5,16 @@ import {
|
|||
differenceInCalendarDays,
|
||||
isToday,
|
||||
} from 'date-fns';
|
||||
import { X } from 'react-feather';
|
||||
import { SmallLink, DarkSubTitle, OverflowText, SingleLine } from './Styled';
|
||||
import { X, Copy } from 'react-feather';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { toast } from 'react-toastify';
|
||||
import {
|
||||
SmallLink,
|
||||
DarkSubTitle,
|
||||
OverflowText,
|
||||
SingleLine,
|
||||
CopyIcon,
|
||||
} from './Styled';
|
||||
import { StatusDot, DetailLine } from './CardGeneric';
|
||||
|
||||
const shorten = (text: string): string => {
|
||||
|
@ -26,12 +34,22 @@ export const getTransactionLink = (transaction: string) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const getNodeLink = (publicKey: string) => {
|
||||
export const getNodeLink = (publicKey: string, alias?: string) => {
|
||||
if (alias && alias === 'Node not found') {
|
||||
return 'Node not found';
|
||||
}
|
||||
const link = `https://1ml.com/node/${publicKey}`;
|
||||
return (
|
||||
<SmallLink href={link} target="_blank">
|
||||
{shorten(publicKey)}
|
||||
</SmallLink>
|
||||
<>
|
||||
<SmallLink href={link} target="_blank">
|
||||
{alias ? alias : shorten(publicKey)}
|
||||
</SmallLink>
|
||||
<CopyToClipboard text={publicKey} onCopy={() => toast.success('Copied')}>
|
||||
<CopyIcon>
|
||||
<Copy size={12} />
|
||||
</CopyIcon>
|
||||
</CopyToClipboard>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { BitcoinFees } from 'src/components/bitcoinInfo/BitcoinFees';
|
||||
import { BitcoinPrice } from 'src/components/bitcoinInfo/BitcoinPrice';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
|
@ -10,11 +10,20 @@ import { StatusCheck } from '../statusCheck/StatusCheck';
|
|||
import { LoadingCard } from '../loading/LoadingCard';
|
||||
import { ServerAccounts } from '../accounts/ServerAccounts';
|
||||
|
||||
const Container = styled.div`
|
||||
type GridProps = {
|
||||
noNavigation?: boolean;
|
||||
};
|
||||
|
||||
const Container = styled.div<GridProps>`
|
||||
display: grid;
|
||||
grid-template-areas: 'nav content content';
|
||||
grid-template-columns: auto 1fr 200px;
|
||||
gap: 16px;
|
||||
|
||||
${({ noNavigation }) =>
|
||||
!noNavigation &&
|
||||
css`
|
||||
gap: 16px;
|
||||
`}
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
display: flex;
|
||||
|
@ -26,7 +35,10 @@ const ContentStyle = styled.div`
|
|||
grid-area: content;
|
||||
`;
|
||||
|
||||
export const GridWrapper: React.FC = ({ children }) => {
|
||||
export const GridWrapper: React.FC<GridProps> = ({
|
||||
children,
|
||||
noNavigation,
|
||||
}) => {
|
||||
const { hasAccount, auth } = useAccountState();
|
||||
const renderContent = () => {
|
||||
if (hasAccount === 'false') {
|
||||
|
@ -36,12 +48,12 @@ export const GridWrapper: React.FC = ({ children }) => {
|
|||
};
|
||||
return (
|
||||
<Section padding={'16px 0 32px'}>
|
||||
<Container>
|
||||
<Container noNavigation={noNavigation}>
|
||||
<ServerAccounts />
|
||||
<BitcoinPrice />
|
||||
<BitcoinFees />
|
||||
{auth && <StatusCheck />}
|
||||
<Navigation />
|
||||
{!noNavigation && <Navigation />}
|
||||
<ContentStyle>{renderContent()}</ContentStyle>
|
||||
</Container>
|
||||
</Section>
|
||||
|
|
|
@ -36,6 +36,7 @@ const StyledLink = styled.a`
|
|||
`;
|
||||
|
||||
const NoStyling = styled.a`
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
`;
|
||||
|
||||
|
@ -48,6 +49,7 @@ interface LinkProps {
|
|||
inheritColor?: boolean;
|
||||
fullWidth?: boolean;
|
||||
noStyling?: boolean;
|
||||
newTab?: boolean;
|
||||
}
|
||||
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
@ -62,6 +64,7 @@ export const Link = ({
|
|||
inheritColor,
|
||||
fullWidth,
|
||||
noStyling,
|
||||
newTab,
|
||||
}: LinkProps) => {
|
||||
const props = { fontColor: color, underline, inheritColor, fullWidth };
|
||||
|
||||
|
@ -71,7 +74,11 @@ export const Link = ({
|
|||
|
||||
if (href) {
|
||||
return (
|
||||
<CorrectLink href={href} {...props}>
|
||||
<CorrectLink
|
||||
href={href}
|
||||
{...props}
|
||||
{...(newTab && { target: '_blank', rel: 'noreferrer' })}
|
||||
>
|
||||
{children}
|
||||
</CorrectLink>
|
||||
);
|
||||
|
|
49
src/components/version/Version.tsx
Normal file
49
src/components/version/Version.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import * as React from 'react';
|
||||
import { useGetLatestVersionQuery } from 'src/graphql/queries/__generated__/getLatestVersion.generated';
|
||||
import getConfig from 'next/config';
|
||||
import styled from 'styled-components';
|
||||
import { appUrls } from 'server/utils/appUrls';
|
||||
import { Link } from '../link/Link';
|
||||
|
||||
const VersionBox = styled.div`
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
opacity: 0.3;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
color: white;
|
||||
}
|
||||
`;
|
||||
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
const { npmVersion } = publicRuntimeConfig;
|
||||
|
||||
export const Version = () => {
|
||||
const { data, loading, error } = useGetLatestVersionQuery();
|
||||
|
||||
if (error || !data || loading || !data?.getLatestVersion) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const githubVersion = data.getLatestVersion.replace('v', '');
|
||||
const version = githubVersion.split('.');
|
||||
const localVersion = npmVersion.split('.').map(Number);
|
||||
|
||||
const newVersionAvailable =
|
||||
version[0] > localVersion[0] ||
|
||||
version[1] > localVersion[1] ||
|
||||
version[2] > localVersion[2];
|
||||
|
||||
if (!newVersionAvailable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={appUrls.update} newTab={true}>
|
||||
<VersionBox>{`Version ${githubVersion} is available. You are on version ${npmVersion}`}</VersionBox>
|
||||
</Link>
|
||||
);
|
||||
};
|
|
@ -7,7 +7,7 @@ import {
|
|||
getAuthFromAccount,
|
||||
} from './helpers/context';
|
||||
|
||||
export type SERVER_ACCOUNT_TYPE = 'sso' | 'server';
|
||||
export type SERVER_ACCOUNT_TYPE = 'sso' | 'server' | 'test';
|
||||
export type ACCOUNT_TYPE = 'client';
|
||||
|
||||
export const CLIENT_ACCOUNT: ACCOUNT_TYPE = 'client';
|
||||
|
|
18
src/graphql/fragmentTypes.json
Normal file
18
src/graphql/fragmentTypes.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"__schema": {
|
||||
"types": [
|
||||
{
|
||||
"kind": "UNION",
|
||||
"name": "Transaction",
|
||||
"possibleTypes": [
|
||||
{
|
||||
"name": "InvoiceType"
|
||||
},
|
||||
{
|
||||
"name": "PaymentType"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ export type CreateInvoiceMutationVariables = {
|
|||
|
||||
export type CreateInvoiceMutation = { __typename?: 'Mutation' } & {
|
||||
createInvoice?: Types.Maybe<
|
||||
{ __typename?: 'invoiceType' } & Pick<Types.InvoiceType, 'request'>
|
||||
{ __typename?: 'newInvoiceType' } & Pick<Types.NewInvoiceType, 'request'>
|
||||
>;
|
||||
};
|
||||
|
||||
|
|
|
@ -38,17 +38,40 @@ export type GetChannelsQuery = { __typename?: 'Query' } & {
|
|||
| 'unsettled_balance'
|
||||
> & {
|
||||
partner_node_info?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
| 'base_fee'
|
||||
| 'fee_rate'
|
||||
| 'cltv_delta'
|
||||
>
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
partner_fee_info?: Types.Maybe<
|
||||
{ __typename?: 'Channel' } & {
|
||||
channel?: Types.Maybe<
|
||||
{ __typename?: 'singleChannelType' } & {
|
||||
policies: Array<
|
||||
{ __typename?: 'policyType' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'base_fee' | 'fee_rate' | 'cltv_delta'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
|
@ -82,14 +105,26 @@ export const GetChannelsDocument = gql`
|
|||
transaction_vout
|
||||
unsettled_balance
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
partner_fee_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,18 @@ export type GetClosedChannelsQuery = { __typename?: 'Query' } & {
|
|||
| 'transaction_vout'
|
||||
> & {
|
||||
partner_node_info?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
'alias' | 'capacity' | 'channel_count' | 'color' | 'updated_at'
|
||||
>
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
|
@ -58,11 +66,13 @@ export const GetClosedChannelsDocument = gql`
|
|||
transaction_id
|
||||
transaction_vout
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
146
src/graphql/queries/__generated__/getFeeHealth.generated.tsx
generated
Normal file
146
src/graphql/queries/__generated__/getFeeHealth.generated.tsx
generated
Normal file
|
@ -0,0 +1,146 @@
|
|||
import gql from 'graphql-tag';
|
||||
import * as ApolloReactCommon from '@apollo/react-common';
|
||||
import * as ApolloReactHooks from '@apollo/react-hooks';
|
||||
import * as Types from '../../types';
|
||||
|
||||
export type GetFeeHealthQueryVariables = {
|
||||
auth: Types.AuthType;
|
||||
};
|
||||
|
||||
export type GetFeeHealthQuery = { __typename?: 'Query' } & {
|
||||
getFeeHealth?: Types.Maybe<
|
||||
{ __typename?: 'channelsFeeHealth' } & Pick<
|
||||
Types.ChannelsFeeHealth,
|
||||
'score'
|
||||
> & {
|
||||
channels?: Types.Maybe<
|
||||
Array<
|
||||
Types.Maybe<
|
||||
{ __typename?: 'channelFeeHealth' } & Pick<
|
||||
Types.ChannelFeeHealth,
|
||||
'id'
|
||||
> & {
|
||||
partnerSide?: Types.Maybe<
|
||||
{ __typename?: 'feeHealth' } & Pick<
|
||||
Types.FeeHealth,
|
||||
| 'score'
|
||||
| 'rate'
|
||||
| 'base'
|
||||
| 'rateScore'
|
||||
| 'baseScore'
|
||||
| 'rateOver'
|
||||
| 'baseOver'
|
||||
>
|
||||
>;
|
||||
mySide?: Types.Maybe<
|
||||
{ __typename?: 'feeHealth' } & Pick<
|
||||
Types.FeeHealth,
|
||||
| 'score'
|
||||
| 'rate'
|
||||
| 'base'
|
||||
| 'rateScore'
|
||||
| 'baseScore'
|
||||
| 'rateOver'
|
||||
| 'baseOver'
|
||||
>
|
||||
>;
|
||||
partner?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export const GetFeeHealthDocument = gql`
|
||||
query GetFeeHealth($auth: authType!) {
|
||||
getFeeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
partnerSide {
|
||||
score
|
||||
rate
|
||||
base
|
||||
rateScore
|
||||
baseScore
|
||||
rateOver
|
||||
baseOver
|
||||
}
|
||||
mySide {
|
||||
score
|
||||
rate
|
||||
base
|
||||
rateScore
|
||||
baseScore
|
||||
rateOver
|
||||
baseOver
|
||||
}
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetFeeHealthQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetFeeHealthQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetFeeHealthQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetFeeHealthQuery({
|
||||
* variables: {
|
||||
* auth: // value for 'auth'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetFeeHealthQuery(
|
||||
baseOptions?: ApolloReactHooks.QueryHookOptions<
|
||||
GetFeeHealthQuery,
|
||||
GetFeeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useQuery<
|
||||
GetFeeHealthQuery,
|
||||
GetFeeHealthQueryVariables
|
||||
>(GetFeeHealthDocument, baseOptions);
|
||||
}
|
||||
export function useGetFeeHealthLazyQuery(
|
||||
baseOptions?: ApolloReactHooks.LazyQueryHookOptions<
|
||||
GetFeeHealthQuery,
|
||||
GetFeeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useLazyQuery<
|
||||
GetFeeHealthQuery,
|
||||
GetFeeHealthQueryVariables
|
||||
>(GetFeeHealthDocument, baseOptions);
|
||||
}
|
||||
export type GetFeeHealthQueryHookResult = ReturnType<
|
||||
typeof useGetFeeHealthQuery
|
||||
>;
|
||||
export type GetFeeHealthLazyQueryHookResult = ReturnType<
|
||||
typeof useGetFeeHealthLazyQuery
|
||||
>;
|
||||
export type GetFeeHealthQueryResult = ApolloReactCommon.QueryResult<
|
||||
GetFeeHealthQuery,
|
||||
GetFeeHealthQueryVariables
|
||||
>;
|
|
@ -20,14 +20,55 @@ export type GetForwardsQuery = { __typename?: 'Query' } & {
|
|||
| 'fee'
|
||||
| 'fee_mtokens'
|
||||
| 'incoming_channel'
|
||||
| 'incoming_alias'
|
||||
| 'incoming_color'
|
||||
| 'mtokens'
|
||||
| 'outgoing_channel'
|
||||
| 'outgoing_alias'
|
||||
| 'outgoing_color'
|
||||
| 'tokens'
|
||||
>
|
||||
> & {
|
||||
incoming_channel_info?: Types.Maybe<
|
||||
{ __typename?: 'Channel' } & {
|
||||
channel?: Types.Maybe<
|
||||
{ __typename?: 'singleChannelType' } & {
|
||||
policies: Array<
|
||||
{ __typename?: 'policyType' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias' | 'color'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
outgoing_channel_info?: Types.Maybe<
|
||||
{ __typename?: 'Channel' } & {
|
||||
channel?: Types.Maybe<
|
||||
{ __typename?: 'singleChannelType' } & {
|
||||
policies: Array<
|
||||
{ __typename?: 'policyType' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias' | 'color'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
>
|
||||
>;
|
||||
|
@ -43,13 +84,33 @@ export const GetForwardsDocument = gql`
|
|||
fee
|
||||
fee_mtokens
|
||||
incoming_channel
|
||||
incoming_alias
|
||||
incoming_color
|
||||
mtokens
|
||||
outgoing_channel
|
||||
outgoing_alias
|
||||
outgoing_color
|
||||
tokens
|
||||
incoming_channel_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
alias
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outgoing_channel_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
alias
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
token
|
||||
}
|
||||
|
|
65
src/graphql/queries/__generated__/getLatestVersion.generated.tsx
generated
Normal file
65
src/graphql/queries/__generated__/getLatestVersion.generated.tsx
generated
Normal file
|
@ -0,0 +1,65 @@
|
|||
import gql from 'graphql-tag';
|
||||
import * as ApolloReactCommon from '@apollo/react-common';
|
||||
import * as ApolloReactHooks from '@apollo/react-hooks';
|
||||
import * as Types from '../../types';
|
||||
|
||||
export type GetLatestVersionQueryVariables = {};
|
||||
|
||||
export type GetLatestVersionQuery = { __typename?: 'Query' } & Pick<
|
||||
Types.Query,
|
||||
'getLatestVersion'
|
||||
>;
|
||||
|
||||
export const GetLatestVersionDocument = gql`
|
||||
query GetLatestVersion {
|
||||
getLatestVersion
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetLatestVersionQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetLatestVersionQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetLatestVersionQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetLatestVersionQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetLatestVersionQuery(
|
||||
baseOptions?: ApolloReactHooks.QueryHookOptions<
|
||||
GetLatestVersionQuery,
|
||||
GetLatestVersionQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useQuery<
|
||||
GetLatestVersionQuery,
|
||||
GetLatestVersionQueryVariables
|
||||
>(GetLatestVersionDocument, baseOptions);
|
||||
}
|
||||
export function useGetLatestVersionLazyQuery(
|
||||
baseOptions?: ApolloReactHooks.LazyQueryHookOptions<
|
||||
GetLatestVersionQuery,
|
||||
GetLatestVersionQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useLazyQuery<
|
||||
GetLatestVersionQuery,
|
||||
GetLatestVersionQueryVariables
|
||||
>(GetLatestVersionDocument, baseOptions);
|
||||
}
|
||||
export type GetLatestVersionQueryHookResult = ReturnType<
|
||||
typeof useGetLatestVersionQuery
|
||||
>;
|
||||
export type GetLatestVersionLazyQueryHookResult = ReturnType<
|
||||
typeof useGetLatestVersionLazyQuery
|
||||
>;
|
||||
export type GetLatestVersionQueryResult = ApolloReactCommon.QueryResult<
|
||||
GetLatestVersionQuery,
|
||||
GetLatestVersionQueryVariables
|
||||
>;
|
|
@ -11,8 +11,8 @@ export type GetNodeQueryVariables = {
|
|||
|
||||
export type GetNodeQuery = { __typename?: 'Query' } & {
|
||||
getNode?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias' | 'capacity' | 'channel_count' | 'color' | 'updated_at'
|
||||
>
|
||||
>;
|
||||
|
|
|
@ -24,10 +24,18 @@ export type GetPeersQuery = { __typename?: 'Query' } & {
|
|||
| 'tokens_sent'
|
||||
> & {
|
||||
partner_node_info?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
'alias' | 'capacity' | 'channel_count' | 'color' | 'updated_at'
|
||||
>
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
|
@ -48,11 +56,13 @@ export const GetPeersDocument = gql`
|
|||
tokens_received
|
||||
tokens_sent
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,18 @@ export type GetPendingChannelsQuery = { __typename?: 'Query' } & {
|
|||
| 'transaction_vout'
|
||||
> & {
|
||||
partner_node_info?: Types.Maybe<
|
||||
{ __typename?: 'partnerNodeType' } & Pick<
|
||||
Types.PartnerNodeType,
|
||||
'alias' | 'capacity' | 'channel_count' | 'color' | 'updated_at'
|
||||
>
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
| 'alias'
|
||||
| 'capacity'
|
||||
| 'channel_count'
|
||||
| 'color'
|
||||
| 'updated_at'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
|
@ -58,11 +66,13 @@ export const GetPendingChannelsDocument = gql`
|
|||
transaction_id
|
||||
transaction_vout
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,80 @@ export type GetResumeQueryVariables = {
|
|||
|
||||
export type GetResumeQuery = { __typename?: 'Query' } & {
|
||||
getResume?: Types.Maybe<
|
||||
{ __typename?: 'getResumeType' } & Pick<
|
||||
Types.GetResumeType,
|
||||
'token' | 'resume'
|
||||
>
|
||||
{ __typename?: 'getResumeType' } & Pick<Types.GetResumeType, 'token'> & {
|
||||
resume?: Types.Maybe<
|
||||
Array<
|
||||
Types.Maybe<
|
||||
| ({ __typename?: 'InvoiceType' } & Pick<
|
||||
Types.InvoiceType,
|
||||
| 'chain_address'
|
||||
| 'confirmed_at'
|
||||
| 'created_at'
|
||||
| 'description'
|
||||
| 'description_hash'
|
||||
| 'expires_at'
|
||||
| 'id'
|
||||
| 'is_canceled'
|
||||
| 'is_confirmed'
|
||||
| 'is_held'
|
||||
| 'is_private'
|
||||
| 'is_push'
|
||||
| 'received'
|
||||
| 'received_mtokens'
|
||||
| 'request'
|
||||
| 'secret'
|
||||
| 'tokens'
|
||||
| 'type'
|
||||
| 'date'
|
||||
>)
|
||||
| ({ __typename?: 'PaymentType' } & Pick<
|
||||
Types.PaymentType,
|
||||
| 'created_at'
|
||||
| 'destination'
|
||||
| 'fee'
|
||||
| 'fee_mtokens'
|
||||
| 'id'
|
||||
| 'index'
|
||||
| 'is_confirmed'
|
||||
| 'is_outgoing'
|
||||
| 'mtokens'
|
||||
| 'request'
|
||||
| 'safe_fee'
|
||||
| 'safe_tokens'
|
||||
| 'secret'
|
||||
| 'tokens'
|
||||
| 'type'
|
||||
| 'date'
|
||||
> & {
|
||||
destination_node?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
hops?: Types.Maybe<
|
||||
Array<
|
||||
Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>
|
||||
>
|
||||
>;
|
||||
})
|
||||
>
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
|
@ -21,7 +91,57 @@ export const GetResumeDocument = gql`
|
|||
query GetResume($auth: authType!, $token: String) {
|
||||
getResume(auth: $auth, token: $token) {
|
||||
token
|
||||
resume
|
||||
resume {
|
||||
... on InvoiceType {
|
||||
chain_address
|
||||
confirmed_at
|
||||
created_at
|
||||
description
|
||||
description_hash
|
||||
expires_at
|
||||
id
|
||||
is_canceled
|
||||
is_confirmed
|
||||
is_held
|
||||
is_private
|
||||
is_push
|
||||
received
|
||||
received_mtokens
|
||||
request
|
||||
secret
|
||||
tokens
|
||||
type
|
||||
date
|
||||
}
|
||||
... on PaymentType {
|
||||
created_at
|
||||
destination
|
||||
destination_node {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
fee
|
||||
fee_mtokens
|
||||
hops {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
id
|
||||
index
|
||||
is_confirmed
|
||||
is_outgoing
|
||||
mtokens
|
||||
request
|
||||
safe_fee
|
||||
safe_tokens
|
||||
secret
|
||||
tokens
|
||||
type
|
||||
date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
114
src/graphql/queries/__generated__/getTimeHealth.generated.tsx
generated
Normal file
114
src/graphql/queries/__generated__/getTimeHealth.generated.tsx
generated
Normal file
|
@ -0,0 +1,114 @@
|
|||
import gql from 'graphql-tag';
|
||||
import * as ApolloReactCommon from '@apollo/react-common';
|
||||
import * as ApolloReactHooks from '@apollo/react-hooks';
|
||||
import * as Types from '../../types';
|
||||
|
||||
export type GetTimeHealthQueryVariables = {
|
||||
auth: Types.AuthType;
|
||||
};
|
||||
|
||||
export type GetTimeHealthQuery = { __typename?: 'Query' } & {
|
||||
getTimeHealth?: Types.Maybe<
|
||||
{ __typename?: 'channelsTimeHealth' } & Pick<
|
||||
Types.ChannelsTimeHealth,
|
||||
'score'
|
||||
> & {
|
||||
channels?: Types.Maybe<
|
||||
Array<
|
||||
Types.Maybe<
|
||||
{ __typename?: 'channelTimeHealth' } & Pick<
|
||||
Types.ChannelTimeHealth,
|
||||
| 'id'
|
||||
| 'score'
|
||||
| 'significant'
|
||||
| 'monitoredTime'
|
||||
| 'monitoredUptime'
|
||||
| 'monitoredDowntime'
|
||||
> & {
|
||||
partner?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export const GetTimeHealthDocument = gql`
|
||||
query GetTimeHealth($auth: authType!) {
|
||||
getTimeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
score
|
||||
significant
|
||||
monitoredTime
|
||||
monitoredUptime
|
||||
monitoredDowntime
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetTimeHealthQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetTimeHealthQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetTimeHealthQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetTimeHealthQuery({
|
||||
* variables: {
|
||||
* auth: // value for 'auth'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetTimeHealthQuery(
|
||||
baseOptions?: ApolloReactHooks.QueryHookOptions<
|
||||
GetTimeHealthQuery,
|
||||
GetTimeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useQuery<
|
||||
GetTimeHealthQuery,
|
||||
GetTimeHealthQueryVariables
|
||||
>(GetTimeHealthDocument, baseOptions);
|
||||
}
|
||||
export function useGetTimeHealthLazyQuery(
|
||||
baseOptions?: ApolloReactHooks.LazyQueryHookOptions<
|
||||
GetTimeHealthQuery,
|
||||
GetTimeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useLazyQuery<
|
||||
GetTimeHealthQuery,
|
||||
GetTimeHealthQueryVariables
|
||||
>(GetTimeHealthDocument, baseOptions);
|
||||
}
|
||||
export type GetTimeHealthQueryHookResult = ReturnType<
|
||||
typeof useGetTimeHealthQuery
|
||||
>;
|
||||
export type GetTimeHealthLazyQueryHookResult = ReturnType<
|
||||
typeof useGetTimeHealthLazyQuery
|
||||
>;
|
||||
export type GetTimeHealthQueryResult = ApolloReactCommon.QueryResult<
|
||||
GetTimeHealthQuery,
|
||||
GetTimeHealthQueryVariables
|
||||
>;
|
104
src/graphql/queries/__generated__/getVolumeHealth.generated.tsx
generated
Normal file
104
src/graphql/queries/__generated__/getVolumeHealth.generated.tsx
generated
Normal file
|
@ -0,0 +1,104 @@
|
|||
import gql from 'graphql-tag';
|
||||
import * as ApolloReactCommon from '@apollo/react-common';
|
||||
import * as ApolloReactHooks from '@apollo/react-hooks';
|
||||
import * as Types from '../../types';
|
||||
|
||||
export type GetVolumeHealthQueryVariables = {
|
||||
auth: Types.AuthType;
|
||||
};
|
||||
|
||||
export type GetVolumeHealthQuery = { __typename?: 'Query' } & {
|
||||
getVolumeHealth?: Types.Maybe<
|
||||
{ __typename?: 'channelsHealth' } & Pick<Types.ChannelsHealth, 'score'> & {
|
||||
channels?: Types.Maybe<
|
||||
Array<
|
||||
Types.Maybe<
|
||||
{ __typename?: 'channelHealth' } & Pick<
|
||||
Types.ChannelHealth,
|
||||
'id' | 'score' | 'volumeNormalized' | 'averageVolumeNormalized'
|
||||
> & {
|
||||
partner?: Types.Maybe<
|
||||
{ __typename?: 'Node' } & {
|
||||
node?: Types.Maybe<
|
||||
{ __typename?: 'nodeType' } & Pick<
|
||||
Types.NodeType,
|
||||
'alias'
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
>
|
||||
>
|
||||
>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export const GetVolumeHealthDocument = gql`
|
||||
query GetVolumeHealth($auth: authType!) {
|
||||
getVolumeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
score
|
||||
volumeNormalized
|
||||
averageVolumeNormalized
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetVolumeHealthQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetVolumeHealthQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetVolumeHealthQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetVolumeHealthQuery({
|
||||
* variables: {
|
||||
* auth: // value for 'auth'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetVolumeHealthQuery(
|
||||
baseOptions?: ApolloReactHooks.QueryHookOptions<
|
||||
GetVolumeHealthQuery,
|
||||
GetVolumeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useQuery<
|
||||
GetVolumeHealthQuery,
|
||||
GetVolumeHealthQueryVariables
|
||||
>(GetVolumeHealthDocument, baseOptions);
|
||||
}
|
||||
export function useGetVolumeHealthLazyQuery(
|
||||
baseOptions?: ApolloReactHooks.LazyQueryHookOptions<
|
||||
GetVolumeHealthQuery,
|
||||
GetVolumeHealthQueryVariables
|
||||
>
|
||||
) {
|
||||
return ApolloReactHooks.useLazyQuery<
|
||||
GetVolumeHealthQuery,
|
||||
GetVolumeHealthQueryVariables
|
||||
>(GetVolumeHealthDocument, baseOptions);
|
||||
}
|
||||
export type GetVolumeHealthQueryHookResult = ReturnType<
|
||||
typeof useGetVolumeHealthQuery
|
||||
>;
|
||||
export type GetVolumeHealthLazyQueryHookResult = ReturnType<
|
||||
typeof useGetVolumeHealthLazyQuery
|
||||
>;
|
||||
export type GetVolumeHealthQueryResult = ApolloReactCommon.QueryResult<
|
||||
GetVolumeHealthQuery,
|
||||
GetVolumeHealthQueryVariables
|
||||
>;
|
|
@ -26,14 +26,26 @@ export const GET_CHANNELS = gql`
|
|||
transaction_vout
|
||||
unsettled_balance
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
partner_fee_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
base_fee
|
||||
fee_rate
|
||||
cltv_delta
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,13 @@ export const GET_CLOSED_CHANNELS = gql`
|
|||
transaction_id
|
||||
transaction_vout
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
35
src/graphql/queries/getFeeHealth.ts
Normal file
35
src/graphql/queries/getFeeHealth.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const GET_FEE_HEALTH = gql`
|
||||
query GetFeeHealth($auth: authType!) {
|
||||
getFeeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
partnerSide {
|
||||
score
|
||||
rate
|
||||
base
|
||||
rateScore
|
||||
baseScore
|
||||
rateOver
|
||||
baseOver
|
||||
}
|
||||
mySide {
|
||||
score
|
||||
rate
|
||||
base
|
||||
rateScore
|
||||
baseScore
|
||||
rateOver
|
||||
baseOver
|
||||
}
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -8,13 +8,33 @@ export const GET_FORWARDS = gql`
|
|||
fee
|
||||
fee_mtokens
|
||||
incoming_channel
|
||||
incoming_alias
|
||||
incoming_color
|
||||
mtokens
|
||||
outgoing_channel
|
||||
outgoing_alias
|
||||
outgoing_color
|
||||
tokens
|
||||
incoming_channel_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
alias
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outgoing_channel_info {
|
||||
channel {
|
||||
policies {
|
||||
node {
|
||||
node {
|
||||
alias
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
token
|
||||
}
|
||||
|
|
7
src/graphql/queries/getLatestVersion.ts
Normal file
7
src/graphql/queries/getLatestVersion.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import gql from 'graphql-tag';
|
||||
|
||||
export const GET_LATEST_VERSION = gql`
|
||||
query GetLatestVersion {
|
||||
getLatestVersion
|
||||
}
|
||||
`;
|
|
@ -13,11 +13,13 @@ export const GET_PEERS = gql`
|
|||
tokens_received
|
||||
tokens_sent
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,13 @@ export const GET_PENDING_CHANNELS = gql`
|
|||
transaction_id
|
||||
transaction_vout
|
||||
partner_node_info {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
node {
|
||||
alias
|
||||
capacity
|
||||
channel_count
|
||||
color
|
||||
updated_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,57 @@ export const GET_RESUME = gql`
|
|||
query GetResume($auth: authType!, $token: String) {
|
||||
getResume(auth: $auth, token: $token) {
|
||||
token
|
||||
resume
|
||||
resume {
|
||||
... on InvoiceType {
|
||||
chain_address
|
||||
confirmed_at
|
||||
created_at
|
||||
description
|
||||
description_hash
|
||||
expires_at
|
||||
id
|
||||
is_canceled
|
||||
is_confirmed
|
||||
is_held
|
||||
is_private
|
||||
is_push
|
||||
received
|
||||
received_mtokens
|
||||
request
|
||||
secret
|
||||
tokens
|
||||
type
|
||||
date
|
||||
}
|
||||
... on PaymentType {
|
||||
created_at
|
||||
destination
|
||||
destination_node {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
fee
|
||||
fee_mtokens
|
||||
hops {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
id
|
||||
index
|
||||
is_confirmed
|
||||
is_outgoing
|
||||
mtokens
|
||||
request
|
||||
safe_fee
|
||||
safe_tokens
|
||||
secret
|
||||
tokens
|
||||
type
|
||||
date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
22
src/graphql/queries/getTimeHealth.ts
Normal file
22
src/graphql/queries/getTimeHealth.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const GET_TIME_HEALTH = gql`
|
||||
query GetTimeHealth($auth: authType!) {
|
||||
getTimeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
score
|
||||
significant
|
||||
monitoredTime
|
||||
monitoredUptime
|
||||
monitoredDowntime
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
20
src/graphql/queries/getVolumeHealth.ts
Normal file
20
src/graphql/queries/getVolumeHealth.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { gql } from 'apollo-server-micro';
|
||||
|
||||
export const GET_VOLUME_HEALTH = gql`
|
||||
query GetVolumeHealth($auth: authType!) {
|
||||
getVolumeHealth(auth: $auth) {
|
||||
score
|
||||
channels {
|
||||
id
|
||||
score
|
||||
volumeNormalized
|
||||
averageVolumeNormalized
|
||||
partner {
|
||||
node {
|
||||
alias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -6,12 +6,22 @@ export type Scalars = {
|
|||
Boolean: boolean;
|
||||
Int: number;
|
||||
Float: number;
|
||||
/** A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. */
|
||||
DateTime: any;
|
||||
};
|
||||
|
||||
export type AuthType = {
|
||||
type: Scalars['String'];
|
||||
id?: Maybe<Scalars['String']>;
|
||||
host?: Maybe<Scalars['String']>;
|
||||
macaroon?: Maybe<Scalars['String']>;
|
||||
cert?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
getVolumeHealth?: Maybe<ChannelsHealth>;
|
||||
getTimeHealth?: Maybe<ChannelsTimeHealth>;
|
||||
getFeeHealth?: Maybe<ChannelsFeeHealth>;
|
||||
getChannelBalance?: Maybe<ChannelBalanceType>;
|
||||
getChannels?: Maybe<Array<Maybe<ChannelType>>>;
|
||||
getClosedChannels?: Maybe<Array<Maybe<ClosedChannelType>>>;
|
||||
|
@ -21,7 +31,7 @@ export type Query = {
|
|||
getNetworkInfo?: Maybe<NetworkInfoType>;
|
||||
getNodeInfo?: Maybe<NodeInfoType>;
|
||||
adminCheck?: Maybe<Scalars['Boolean']>;
|
||||
getNode?: Maybe<PartnerNodeType>;
|
||||
getNode?: Maybe<NodeType>;
|
||||
decodeRequest?: Maybe<DecodeType>;
|
||||
getWalletInfo?: Maybe<WalletInfoType>;
|
||||
getResume?: Maybe<GetResumeType>;
|
||||
|
@ -51,6 +61,19 @@ export type Query = {
|
|||
getServerAccounts?: Maybe<Array<Maybe<ServerAccountType>>>;
|
||||
getLnPayInfo?: Maybe<LnPayInfoType>;
|
||||
getLnPay?: Maybe<Scalars['String']>;
|
||||
getLatestVersion?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type QueryGetVolumeHealthArgs = {
|
||||
auth: AuthType;
|
||||
};
|
||||
|
||||
export type QueryGetTimeHealthArgs = {
|
||||
auth: AuthType;
|
||||
};
|
||||
|
||||
export type QueryGetFeeHealthArgs = {
|
||||
auth: AuthType;
|
||||
};
|
||||
|
||||
export type QueryGetChannelBalanceArgs = {
|
||||
|
@ -219,367 +242,6 @@ export type QueryGetLnPayArgs = {
|
|||
amount?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ChannelBalanceType = {
|
||||
__typename?: 'channelBalanceType';
|
||||
confirmedBalance?: Maybe<Scalars['Int']>;
|
||||
pendingBalance?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type AuthType = {
|
||||
type: Scalars['String'];
|
||||
id?: Maybe<Scalars['String']>;
|
||||
host?: Maybe<Scalars['String']>;
|
||||
macaroon?: Maybe<Scalars['String']>;
|
||||
cert?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ChannelType = {
|
||||
__typename?: 'channelType';
|
||||
capacity?: Maybe<Scalars['Int']>;
|
||||
commit_transaction_fee?: Maybe<Scalars['Int']>;
|
||||
commit_transaction_weight?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
is_active?: Maybe<Scalars['Boolean']>;
|
||||
is_closing?: Maybe<Scalars['Boolean']>;
|
||||
is_opening?: Maybe<Scalars['Boolean']>;
|
||||
is_partner_initiated?: Maybe<Scalars['Boolean']>;
|
||||
is_private?: Maybe<Scalars['Boolean']>;
|
||||
is_static_remote_key?: Maybe<Scalars['Boolean']>;
|
||||
local_balance?: Maybe<Scalars['Int']>;
|
||||
local_reserve?: Maybe<Scalars['Int']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
received?: Maybe<Scalars['Int']>;
|
||||
remote_balance?: Maybe<Scalars['Int']>;
|
||||
remote_reserve?: Maybe<Scalars['Int']>;
|
||||
sent?: Maybe<Scalars['Int']>;
|
||||
time_offline?: Maybe<Scalars['Int']>;
|
||||
time_online?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
unsettled_balance?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<PartnerNodeType>;
|
||||
};
|
||||
|
||||
export type PartnerNodeType = {
|
||||
__typename?: 'partnerNodeType';
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
capacity?: Maybe<Scalars['String']>;
|
||||
channel_count?: Maybe<Scalars['Int']>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
updated_at?: Maybe<Scalars['String']>;
|
||||
base_fee?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ClosedChannelType = {
|
||||
__typename?: 'closedChannelType';
|
||||
capacity?: Maybe<Scalars['Int']>;
|
||||
close_confirm_height?: Maybe<Scalars['Int']>;
|
||||
close_transaction_id?: Maybe<Scalars['String']>;
|
||||
final_local_balance?: Maybe<Scalars['Int']>;
|
||||
final_time_locked_balance?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
is_breach_close?: Maybe<Scalars['Boolean']>;
|
||||
is_cooperative_close?: Maybe<Scalars['Boolean']>;
|
||||
is_funding_cancel?: Maybe<Scalars['Boolean']>;
|
||||
is_local_force_close?: Maybe<Scalars['Boolean']>;
|
||||
is_remote_force_close?: Maybe<Scalars['Boolean']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<PartnerNodeType>;
|
||||
};
|
||||
|
||||
export type PendingChannelType = {
|
||||
__typename?: 'pendingChannelType';
|
||||
close_transaction_id?: Maybe<Scalars['String']>;
|
||||
is_active?: Maybe<Scalars['Boolean']>;
|
||||
is_closing?: Maybe<Scalars['Boolean']>;
|
||||
is_opening?: Maybe<Scalars['Boolean']>;
|
||||
local_balance?: Maybe<Scalars['Int']>;
|
||||
local_reserve?: Maybe<Scalars['Int']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
received?: Maybe<Scalars['Int']>;
|
||||
remote_balance?: Maybe<Scalars['Int']>;
|
||||
remote_reserve?: Maybe<Scalars['Int']>;
|
||||
sent?: Maybe<Scalars['Int']>;
|
||||
transaction_fee?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<PartnerNodeType>;
|
||||
};
|
||||
|
||||
export type ChannelFeeType = {
|
||||
__typename?: 'channelFeeType';
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
baseFee?: Maybe<Scalars['Float']>;
|
||||
feeRate?: Maybe<Scalars['Int']>;
|
||||
transactionId?: Maybe<Scalars['String']>;
|
||||
transactionVout?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ChannelReportType = {
|
||||
__typename?: 'channelReportType';
|
||||
local?: Maybe<Scalars['Int']>;
|
||||
remote?: Maybe<Scalars['Int']>;
|
||||
maxIn?: Maybe<Scalars['Int']>;
|
||||
maxOut?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type NetworkInfoType = {
|
||||
__typename?: 'networkInfoType';
|
||||
averageChannelSize?: Maybe<Scalars['String']>;
|
||||
channelCount?: Maybe<Scalars['Int']>;
|
||||
maxChannelSize?: Maybe<Scalars['Int']>;
|
||||
medianChannelSize?: Maybe<Scalars['Int']>;
|
||||
minChannelSize?: Maybe<Scalars['Int']>;
|
||||
nodeCount?: Maybe<Scalars['Int']>;
|
||||
notRecentlyUpdatedPolicyCount?: Maybe<Scalars['Int']>;
|
||||
totalCapacity?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type NodeInfoType = {
|
||||
__typename?: 'nodeInfoType';
|
||||
chains?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
active_channels_count?: Maybe<Scalars['Int']>;
|
||||
closed_channels_count?: Maybe<Scalars['Int']>;
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
current_block_hash?: Maybe<Scalars['String']>;
|
||||
current_block_height?: Maybe<Scalars['Boolean']>;
|
||||
is_synced_to_chain?: Maybe<Scalars['Boolean']>;
|
||||
is_synced_to_graph?: Maybe<Scalars['Boolean']>;
|
||||
latest_block_at?: Maybe<Scalars['String']>;
|
||||
peers_count?: Maybe<Scalars['Int']>;
|
||||
pending_channels_count?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
uris?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type DecodeType = {
|
||||
__typename?: 'decodeType';
|
||||
chain_address?: Maybe<Scalars['String']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
description_hash?: Maybe<Scalars['String']>;
|
||||
destination?: Maybe<Scalars['String']>;
|
||||
expires_at?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
mtokens?: Maybe<Scalars['String']>;
|
||||
routes?: Maybe<Array<Maybe<DecodeRoutesType>>>;
|
||||
safe_tokens?: Maybe<Scalars['Int']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type DecodeRoutesType = {
|
||||
__typename?: 'DecodeRoutesType';
|
||||
base_fee_mtokens?: Maybe<Scalars['String']>;
|
||||
channel?: Maybe<Scalars['String']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type WalletInfoType = {
|
||||
__typename?: 'walletInfoType';
|
||||
build_tags?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
commit_hash?: Maybe<Scalars['String']>;
|
||||
is_autopilotrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_chainrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_invoicesrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_signrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_walletrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_watchtowerrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_wtclientrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type GetResumeType = {
|
||||
__typename?: 'getResumeType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
resume?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type GetForwardType = {
|
||||
__typename?: 'getForwardType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
forwards?: Maybe<Array<Maybe<ForwardType>>>;
|
||||
};
|
||||
|
||||
export type ForwardType = {
|
||||
__typename?: 'forwardType';
|
||||
created_at?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<Scalars['Int']>;
|
||||
fee_mtokens?: Maybe<Scalars['String']>;
|
||||
incoming_channel?: Maybe<Scalars['String']>;
|
||||
incoming_alias?: Maybe<Scalars['String']>;
|
||||
incoming_color?: Maybe<Scalars['String']>;
|
||||
mtokens?: Maybe<Scalars['String']>;
|
||||
outgoing_channel?: Maybe<Scalars['String']>;
|
||||
outgoing_alias?: Maybe<Scalars['String']>;
|
||||
outgoing_color?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type BitcoinFeeType = {
|
||||
__typename?: 'bitcoinFeeType';
|
||||
fast?: Maybe<Scalars['Int']>;
|
||||
halfHour?: Maybe<Scalars['Int']>;
|
||||
hour?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type InOutType = {
|
||||
__typename?: 'InOutType';
|
||||
invoices?: Maybe<Scalars['String']>;
|
||||
payments?: Maybe<Scalars['String']>;
|
||||
confirmedInvoices?: Maybe<Scalars['Int']>;
|
||||
unConfirmedInvoices?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type PeerType = {
|
||||
__typename?: 'peerType';
|
||||
bytes_received?: Maybe<Scalars['Int']>;
|
||||
bytes_sent?: Maybe<Scalars['Int']>;
|
||||
is_inbound?: Maybe<Scalars['Boolean']>;
|
||||
is_sync_peer?: Maybe<Scalars['Boolean']>;
|
||||
ping_time?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
socket?: Maybe<Scalars['String']>;
|
||||
tokens_received?: Maybe<Scalars['Int']>;
|
||||
tokens_sent?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<PartnerNodeType>;
|
||||
};
|
||||
|
||||
export type GetTransactionsType = {
|
||||
__typename?: 'getTransactionsType';
|
||||
block_id?: Maybe<Scalars['String']>;
|
||||
confirmation_count?: Maybe<Scalars['Int']>;
|
||||
confirmation_height?: Maybe<Scalars['Int']>;
|
||||
created_at?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
output_addresses?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type GetUtxosType = {
|
||||
__typename?: 'getUtxosType';
|
||||
address?: Maybe<Scalars['String']>;
|
||||
address_format?: Maybe<Scalars['String']>;
|
||||
confirmation_count?: Maybe<Scalars['Int']>;
|
||||
output_script?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type HodlOfferType = {
|
||||
__typename?: 'hodlOfferType';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
asset_code?: Maybe<Scalars['String']>;
|
||||
searchable?: Maybe<Scalars['Boolean']>;
|
||||
country?: Maybe<Scalars['String']>;
|
||||
country_code?: Maybe<Scalars['String']>;
|
||||
working_now?: Maybe<Scalars['Boolean']>;
|
||||
side?: Maybe<Scalars['String']>;
|
||||
title?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
currency_code?: Maybe<Scalars['String']>;
|
||||
price?: Maybe<Scalars['String']>;
|
||||
min_amount?: Maybe<Scalars['String']>;
|
||||
max_amount?: Maybe<Scalars['String']>;
|
||||
first_trade_limit?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<HodlOfferFeeType>;
|
||||
balance?: Maybe<Scalars['String']>;
|
||||
payment_window_minutes?: Maybe<Scalars['Int']>;
|
||||
confirmations?: Maybe<Scalars['Int']>;
|
||||
payment_method_instructions?: Maybe<Array<Maybe<HodlOfferPaymentType>>>;
|
||||
trader?: Maybe<HodlOfferTraderType>;
|
||||
};
|
||||
|
||||
export type HodlOfferFeeType = {
|
||||
__typename?: 'hodlOfferFeeType';
|
||||
author_fee_rate?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlOfferPaymentType = {
|
||||
__typename?: 'hodlOfferPaymentType';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
payment_method_id?: Maybe<Scalars['String']>;
|
||||
payment_method_type?: Maybe<Scalars['String']>;
|
||||
payment_method_name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlOfferTraderType = {
|
||||
__typename?: 'hodlOfferTraderType';
|
||||
login?: Maybe<Scalars['String']>;
|
||||
online_status?: Maybe<Scalars['String']>;
|
||||
rating?: Maybe<Scalars['String']>;
|
||||
trades_count?: Maybe<Scalars['Int']>;
|
||||
url?: Maybe<Scalars['String']>;
|
||||
verified?: Maybe<Scalars['Boolean']>;
|
||||
verified_by?: Maybe<Scalars['String']>;
|
||||
strong_hodler?: Maybe<Scalars['Boolean']>;
|
||||
country?: Maybe<Scalars['String']>;
|
||||
country_code?: Maybe<Scalars['String']>;
|
||||
average_payment_time_minutes?: Maybe<Scalars['Int']>;
|
||||
average_release_time_minutes?: Maybe<Scalars['Int']>;
|
||||
days_since_last_trade?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type HodlCountryType = {
|
||||
__typename?: 'hodlCountryType';
|
||||
code?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
native_name?: Maybe<Scalars['String']>;
|
||||
currency_code?: Maybe<Scalars['String']>;
|
||||
currency_name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlCurrencyType = {
|
||||
__typename?: 'hodlCurrencyType';
|
||||
code?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
type?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type GetMessagesType = {
|
||||
__typename?: 'getMessagesType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
messages?: Maybe<Array<Maybe<MessagesType>>>;
|
||||
};
|
||||
|
||||
export type MessagesType = {
|
||||
__typename?: 'messagesType';
|
||||
date?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
verified?: Maybe<Scalars['Boolean']>;
|
||||
contentType?: Maybe<Scalars['String']>;
|
||||
sender?: Maybe<Scalars['String']>;
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
message?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ServerAccountType = {
|
||||
__typename?: 'serverAccountType';
|
||||
name: Scalars['String'];
|
||||
id: Scalars['String'];
|
||||
type: Scalars['String'];
|
||||
loggedIn: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type LnPayInfoType = {
|
||||
__typename?: 'lnPayInfoType';
|
||||
max?: Maybe<Scalars['Int']>;
|
||||
min?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
closeChannel?: Maybe<CloseChannelType>;
|
||||
|
@ -587,7 +249,7 @@ export type Mutation = {
|
|||
updateFees?: Maybe<Scalars['Boolean']>;
|
||||
parsePayment?: Maybe<ParsePaymentType>;
|
||||
pay?: Maybe<PayType>;
|
||||
createInvoice?: Maybe<InvoiceType>;
|
||||
createInvoice?: Maybe<NewInvoiceType>;
|
||||
payViaRoute?: Maybe<Scalars['Boolean']>;
|
||||
createAddress?: Maybe<Scalars['String']>;
|
||||
sendToAddress?: Maybe<SendToType>;
|
||||
|
@ -681,18 +343,377 @@ export type MutationLogoutArgs = {
|
|||
type: Scalars['String'];
|
||||
};
|
||||
|
||||
export type NodeType = {
|
||||
__typename?: 'nodeType';
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
capacity?: Maybe<Scalars['String']>;
|
||||
channel_count?: Maybe<Scalars['Int']>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
updated_at?: Maybe<Scalars['String']>;
|
||||
base_fee?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Node = {
|
||||
__typename?: 'Node';
|
||||
node?: Maybe<NodeType>;
|
||||
};
|
||||
|
||||
export type NodeInfoType = {
|
||||
__typename?: 'nodeInfoType';
|
||||
chains?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
active_channels_count?: Maybe<Scalars['Int']>;
|
||||
closed_channels_count?: Maybe<Scalars['Int']>;
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
current_block_hash?: Maybe<Scalars['String']>;
|
||||
current_block_height?: Maybe<Scalars['Boolean']>;
|
||||
is_synced_to_chain?: Maybe<Scalars['Boolean']>;
|
||||
is_synced_to_graph?: Maybe<Scalars['Boolean']>;
|
||||
latest_block_at?: Maybe<Scalars['String']>;
|
||||
peers_count?: Maybe<Scalars['Int']>;
|
||||
pending_channels_count?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
uris?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ServerAccountType = {
|
||||
__typename?: 'serverAccountType';
|
||||
name: Scalars['String'];
|
||||
id: Scalars['String'];
|
||||
type: Scalars['String'];
|
||||
loggedIn: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type HodlCountryType = {
|
||||
__typename?: 'hodlCountryType';
|
||||
code?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
native_name?: Maybe<Scalars['String']>;
|
||||
currency_code?: Maybe<Scalars['String']>;
|
||||
currency_name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlCurrencyType = {
|
||||
__typename?: 'hodlCurrencyType';
|
||||
code?: Maybe<Scalars['String']>;
|
||||
name?: Maybe<Scalars['String']>;
|
||||
type?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlOfferFeeType = {
|
||||
__typename?: 'hodlOfferFeeType';
|
||||
author_fee_rate?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlOfferPaymentType = {
|
||||
__typename?: 'hodlOfferPaymentType';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
payment_method_id?: Maybe<Scalars['String']>;
|
||||
payment_method_type?: Maybe<Scalars['String']>;
|
||||
payment_method_name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type HodlOfferTraderType = {
|
||||
__typename?: 'hodlOfferTraderType';
|
||||
login?: Maybe<Scalars['String']>;
|
||||
online_status?: Maybe<Scalars['String']>;
|
||||
rating?: Maybe<Scalars['String']>;
|
||||
trades_count?: Maybe<Scalars['Int']>;
|
||||
url?: Maybe<Scalars['String']>;
|
||||
verified?: Maybe<Scalars['Boolean']>;
|
||||
verified_by?: Maybe<Scalars['String']>;
|
||||
strong_hodler?: Maybe<Scalars['Boolean']>;
|
||||
country?: Maybe<Scalars['String']>;
|
||||
country_code?: Maybe<Scalars['String']>;
|
||||
average_payment_time_minutes?: Maybe<Scalars['Int']>;
|
||||
average_release_time_minutes?: Maybe<Scalars['Int']>;
|
||||
days_since_last_trade?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type HodlOfferType = {
|
||||
__typename?: 'hodlOfferType';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
asset_code?: Maybe<Scalars['String']>;
|
||||
searchable?: Maybe<Scalars['Boolean']>;
|
||||
country?: Maybe<Scalars['String']>;
|
||||
country_code?: Maybe<Scalars['String']>;
|
||||
working_now?: Maybe<Scalars['Boolean']>;
|
||||
side?: Maybe<Scalars['String']>;
|
||||
title?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
currency_code?: Maybe<Scalars['String']>;
|
||||
price?: Maybe<Scalars['String']>;
|
||||
min_amount?: Maybe<Scalars['String']>;
|
||||
max_amount?: Maybe<Scalars['String']>;
|
||||
first_trade_limit?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<HodlOfferFeeType>;
|
||||
balance?: Maybe<Scalars['String']>;
|
||||
payment_window_minutes?: Maybe<Scalars['Int']>;
|
||||
confirmations?: Maybe<Scalars['Int']>;
|
||||
payment_method_instructions?: Maybe<Array<Maybe<HodlOfferPaymentType>>>;
|
||||
trader?: Maybe<HodlOfferTraderType>;
|
||||
};
|
||||
|
||||
export type LnPayInfoType = {
|
||||
__typename?: 'lnPayInfoType';
|
||||
max?: Maybe<Scalars['Int']>;
|
||||
min?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type BitcoinFeeType = {
|
||||
__typename?: 'bitcoinFeeType';
|
||||
fast?: Maybe<Scalars['Int']>;
|
||||
halfHour?: Maybe<Scalars['Int']>;
|
||||
hour?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type PeerType = {
|
||||
__typename?: 'peerType';
|
||||
bytes_received?: Maybe<Scalars['Int']>;
|
||||
bytes_sent?: Maybe<Scalars['Int']>;
|
||||
is_inbound?: Maybe<Scalars['Boolean']>;
|
||||
is_sync_peer?: Maybe<Scalars['Boolean']>;
|
||||
ping_time?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
socket?: Maybe<Scalars['String']>;
|
||||
tokens_received?: Maybe<Scalars['Int']>;
|
||||
tokens_sent?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type GetUtxosType = {
|
||||
__typename?: 'getUtxosType';
|
||||
address?: Maybe<Scalars['String']>;
|
||||
address_format?: Maybe<Scalars['String']>;
|
||||
confirmation_count?: Maybe<Scalars['Int']>;
|
||||
output_script?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type SendToType = {
|
||||
__typename?: 'sendToType';
|
||||
confirmationCount?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
isConfirmed?: Maybe<Scalars['Boolean']>;
|
||||
isOutgoing?: Maybe<Scalars['Boolean']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type GetTransactionsType = {
|
||||
__typename?: 'getTransactionsType';
|
||||
block_id?: Maybe<Scalars['String']>;
|
||||
confirmation_count?: Maybe<Scalars['Int']>;
|
||||
confirmation_height?: Maybe<Scalars['Int']>;
|
||||
created_at?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
output_addresses?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type DecodeType = {
|
||||
__typename?: 'decodeType';
|
||||
chain_address?: Maybe<Scalars['String']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
description_hash?: Maybe<Scalars['String']>;
|
||||
destination?: Maybe<Scalars['String']>;
|
||||
expires_at?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
mtokens?: Maybe<Scalars['String']>;
|
||||
routes?: Maybe<Array<Maybe<DecodeRoutesType>>>;
|
||||
safe_tokens?: Maybe<Scalars['Int']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type DecodeRoutesType = {
|
||||
__typename?: 'DecodeRoutesType';
|
||||
base_fee_mtokens?: Maybe<Scalars['String']>;
|
||||
channel?: Maybe<Scalars['String']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type GetMessagesType = {
|
||||
__typename?: 'getMessagesType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
messages?: Maybe<Array<Maybe<MessagesType>>>;
|
||||
};
|
||||
|
||||
export type MessagesType = {
|
||||
__typename?: 'messagesType';
|
||||
date?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
verified?: Maybe<Scalars['Boolean']>;
|
||||
contentType?: Maybe<Scalars['String']>;
|
||||
sender?: Maybe<Scalars['String']>;
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
message?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type InOutType = {
|
||||
__typename?: 'InOutType';
|
||||
invoices?: Maybe<Scalars['String']>;
|
||||
payments?: Maybe<Scalars['String']>;
|
||||
confirmedInvoices?: Maybe<Scalars['Int']>;
|
||||
unConfirmedInvoices?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type PolicyType = {
|
||||
__typename?: 'policyType';
|
||||
base_fee_mtokens?: Maybe<Scalars['String']>;
|
||||
cltv_delta?: Maybe<Scalars['Int']>;
|
||||
fee_rate?: Maybe<Scalars['Int']>;
|
||||
is_disabled?: Maybe<Scalars['Boolean']>;
|
||||
max_htlc_mtokens?: Maybe<Scalars['String']>;
|
||||
min_htlc_mtokens?: Maybe<Scalars['String']>;
|
||||
public_key: Scalars['String'];
|
||||
updated_at?: Maybe<Scalars['String']>;
|
||||
my_node?: Maybe<Scalars['Boolean']>;
|
||||
node?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type SingleChannelType = {
|
||||
__typename?: 'singleChannelType';
|
||||
capacity: Scalars['Int'];
|
||||
id: Scalars['String'];
|
||||
policies: Array<PolicyType>;
|
||||
transaction_id: Scalars['String'];
|
||||
transaction_vout: Scalars['Int'];
|
||||
updated_at?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Channel = {
|
||||
__typename?: 'Channel';
|
||||
channel?: Maybe<SingleChannelType>;
|
||||
};
|
||||
|
||||
export type ChannelFeeType = {
|
||||
__typename?: 'channelFeeType';
|
||||
alias?: Maybe<Scalars['String']>;
|
||||
color?: Maybe<Scalars['String']>;
|
||||
baseFee?: Maybe<Scalars['Float']>;
|
||||
feeRate?: Maybe<Scalars['Int']>;
|
||||
transactionId?: Maybe<Scalars['String']>;
|
||||
transactionVout?: Maybe<Scalars['Int']>;
|
||||
public_key?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ChannelReportType = {
|
||||
__typename?: 'channelReportType';
|
||||
local?: Maybe<Scalars['Int']>;
|
||||
remote?: Maybe<Scalars['Int']>;
|
||||
maxIn?: Maybe<Scalars['Int']>;
|
||||
maxOut?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ChannelBalanceType = {
|
||||
__typename?: 'channelBalanceType';
|
||||
confirmedBalance?: Maybe<Scalars['Int']>;
|
||||
pendingBalance?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type ChannelType = {
|
||||
__typename?: 'channelType';
|
||||
capacity?: Maybe<Scalars['Int']>;
|
||||
commit_transaction_fee?: Maybe<Scalars['Int']>;
|
||||
commit_transaction_weight?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
is_active?: Maybe<Scalars['Boolean']>;
|
||||
is_closing?: Maybe<Scalars['Boolean']>;
|
||||
is_opening?: Maybe<Scalars['Boolean']>;
|
||||
is_partner_initiated?: Maybe<Scalars['Boolean']>;
|
||||
is_private?: Maybe<Scalars['Boolean']>;
|
||||
is_static_remote_key?: Maybe<Scalars['Boolean']>;
|
||||
local_balance?: Maybe<Scalars['Int']>;
|
||||
local_reserve?: Maybe<Scalars['Int']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
received?: Maybe<Scalars['Int']>;
|
||||
remote_balance?: Maybe<Scalars['Int']>;
|
||||
remote_reserve?: Maybe<Scalars['Int']>;
|
||||
sent?: Maybe<Scalars['Int']>;
|
||||
time_offline?: Maybe<Scalars['Int']>;
|
||||
time_online?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
unsettled_balance?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<Node>;
|
||||
partner_fee_info?: Maybe<Channel>;
|
||||
};
|
||||
|
||||
export type CloseChannelType = {
|
||||
__typename?: 'closeChannelType';
|
||||
transactionId?: Maybe<Scalars['String']>;
|
||||
transactionOutputIndex?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ClosedChannelType = {
|
||||
__typename?: 'closedChannelType';
|
||||
capacity?: Maybe<Scalars['Int']>;
|
||||
close_confirm_height?: Maybe<Scalars['Int']>;
|
||||
close_transaction_id?: Maybe<Scalars['String']>;
|
||||
final_local_balance?: Maybe<Scalars['Int']>;
|
||||
final_time_locked_balance?: Maybe<Scalars['Int']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
is_breach_close?: Maybe<Scalars['Boolean']>;
|
||||
is_cooperative_close?: Maybe<Scalars['Boolean']>;
|
||||
is_funding_cancel?: Maybe<Scalars['Boolean']>;
|
||||
is_local_force_close?: Maybe<Scalars['Boolean']>;
|
||||
is_remote_force_close?: Maybe<Scalars['Boolean']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type OpenChannelType = {
|
||||
__typename?: 'openChannelType';
|
||||
transactionId?: Maybe<Scalars['String']>;
|
||||
transactionOutputIndex?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type PendingChannelType = {
|
||||
__typename?: 'pendingChannelType';
|
||||
close_transaction_id?: Maybe<Scalars['String']>;
|
||||
is_active?: Maybe<Scalars['Boolean']>;
|
||||
is_closing?: Maybe<Scalars['Boolean']>;
|
||||
is_opening?: Maybe<Scalars['Boolean']>;
|
||||
local_balance?: Maybe<Scalars['Int']>;
|
||||
local_reserve?: Maybe<Scalars['Int']>;
|
||||
partner_public_key?: Maybe<Scalars['String']>;
|
||||
received?: Maybe<Scalars['Int']>;
|
||||
remote_balance?: Maybe<Scalars['Int']>;
|
||||
remote_reserve?: Maybe<Scalars['Int']>;
|
||||
sent?: Maybe<Scalars['Int']>;
|
||||
transaction_fee?: Maybe<Scalars['Int']>;
|
||||
transaction_id?: Maybe<Scalars['String']>;
|
||||
transaction_vout?: Maybe<Scalars['Int']>;
|
||||
partner_node_info?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type WalletInfoType = {
|
||||
__typename?: 'walletInfoType';
|
||||
build_tags?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
commit_hash?: Maybe<Scalars['String']>;
|
||||
is_autopilotrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_chainrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_invoicesrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_signrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_walletrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_watchtowerrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
is_wtclientrpc_enabled?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type ParsePaymentType = {
|
||||
__typename?: 'parsePaymentType';
|
||||
chainAddresses?: Maybe<Array<Maybe<Scalars['String']>>>;
|
||||
|
@ -743,8 +764,8 @@ export type HopsType = {
|
|||
timeout?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type InvoiceType = {
|
||||
__typename?: 'invoiceType';
|
||||
export type NewInvoiceType = {
|
||||
__typename?: 'newInvoiceType';
|
||||
chainAddress?: Maybe<Scalars['String']>;
|
||||
createdAt?: Maybe<Scalars['DateTime']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
|
@ -754,11 +775,143 @@ export type InvoiceType = {
|
|||
tokens?: Maybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type SendToType = {
|
||||
__typename?: 'sendToType';
|
||||
confirmationCount?: Maybe<Scalars['String']>;
|
||||
id?: Maybe<Scalars['String']>;
|
||||
isConfirmed?: Maybe<Scalars['Boolean']>;
|
||||
isOutgoing?: Maybe<Scalars['Boolean']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
export type NetworkInfoType = {
|
||||
__typename?: 'networkInfoType';
|
||||
averageChannelSize?: Maybe<Scalars['String']>;
|
||||
channelCount?: Maybe<Scalars['Int']>;
|
||||
maxChannelSize?: Maybe<Scalars['Int']>;
|
||||
medianChannelSize?: Maybe<Scalars['Int']>;
|
||||
minChannelSize?: Maybe<Scalars['Int']>;
|
||||
nodeCount?: Maybe<Scalars['Int']>;
|
||||
notRecentlyUpdatedPolicyCount?: Maybe<Scalars['Int']>;
|
||||
totalCapacity?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type GetForwardType = {
|
||||
__typename?: 'getForwardType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
forwards?: Maybe<Array<Maybe<ForwardType>>>;
|
||||
};
|
||||
|
||||
export type ForwardType = {
|
||||
__typename?: 'forwardType';
|
||||
created_at?: Maybe<Scalars['String']>;
|
||||
fee?: Maybe<Scalars['Int']>;
|
||||
fee_mtokens?: Maybe<Scalars['String']>;
|
||||
incoming_channel?: Maybe<Scalars['String']>;
|
||||
mtokens?: Maybe<Scalars['String']>;
|
||||
outgoing_channel?: Maybe<Scalars['String']>;
|
||||
tokens?: Maybe<Scalars['Int']>;
|
||||
incoming_channel_info?: Maybe<Channel>;
|
||||
outgoing_channel_info?: Maybe<Channel>;
|
||||
};
|
||||
|
||||
export type PaymentType = {
|
||||
__typename?: 'PaymentType';
|
||||
created_at: Scalars['String'];
|
||||
destination: Scalars['String'];
|
||||
destination_node?: Maybe<Node>;
|
||||
fee: Scalars['Int'];
|
||||
fee_mtokens: Scalars['String'];
|
||||
hops?: Maybe<Array<Maybe<Node>>>;
|
||||
id: Scalars['String'];
|
||||
index?: Maybe<Scalars['Int']>;
|
||||
is_confirmed: Scalars['Boolean'];
|
||||
is_outgoing: Scalars['Boolean'];
|
||||
mtokens: Scalars['String'];
|
||||
request?: Maybe<Scalars['String']>;
|
||||
safe_fee: Scalars['Int'];
|
||||
safe_tokens?: Maybe<Scalars['Int']>;
|
||||
secret: Scalars['String'];
|
||||
tokens: Scalars['Int'];
|
||||
type: Scalars['String'];
|
||||
date: Scalars['String'];
|
||||
};
|
||||
|
||||
export type InvoiceType = {
|
||||
__typename?: 'InvoiceType';
|
||||
chain_address?: Maybe<Scalars['String']>;
|
||||
confirmed_at?: Maybe<Scalars['String']>;
|
||||
created_at: Scalars['String'];
|
||||
description: Scalars['String'];
|
||||
description_hash?: Maybe<Scalars['String']>;
|
||||
expires_at: Scalars['String'];
|
||||
id: Scalars['String'];
|
||||
is_canceled?: Maybe<Scalars['Boolean']>;
|
||||
is_confirmed: Scalars['Boolean'];
|
||||
is_held?: Maybe<Scalars['Boolean']>;
|
||||
is_private: Scalars['Boolean'];
|
||||
is_push?: Maybe<Scalars['Boolean']>;
|
||||
received: Scalars['Int'];
|
||||
received_mtokens: Scalars['String'];
|
||||
request?: Maybe<Scalars['String']>;
|
||||
secret: Scalars['String'];
|
||||
tokens: Scalars['Int'];
|
||||
type: Scalars['String'];
|
||||
date: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Transaction = InvoiceType | PaymentType;
|
||||
|
||||
export type GetResumeType = {
|
||||
__typename?: 'getResumeType';
|
||||
token?: Maybe<Scalars['String']>;
|
||||
resume?: Maybe<Array<Maybe<Transaction>>>;
|
||||
};
|
||||
|
||||
export type ChannelHealth = {
|
||||
__typename?: 'channelHealth';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
volumeNormalized?: Maybe<Scalars['String']>;
|
||||
averageVolumeNormalized?: Maybe<Scalars['String']>;
|
||||
partner?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type ChannelsHealth = {
|
||||
__typename?: 'channelsHealth';
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
channels?: Maybe<Array<Maybe<ChannelHealth>>>;
|
||||
};
|
||||
|
||||
export type ChannelTimeHealth = {
|
||||
__typename?: 'channelTimeHealth';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
significant?: Maybe<Scalars['Boolean']>;
|
||||
monitoredTime?: Maybe<Scalars['Int']>;
|
||||
monitoredUptime?: Maybe<Scalars['Int']>;
|
||||
monitoredDowntime?: Maybe<Scalars['Int']>;
|
||||
partner?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type ChannelsTimeHealth = {
|
||||
__typename?: 'channelsTimeHealth';
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
channels?: Maybe<Array<Maybe<ChannelTimeHealth>>>;
|
||||
};
|
||||
|
||||
export type FeeHealth = {
|
||||
__typename?: 'feeHealth';
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
rate?: Maybe<Scalars['Int']>;
|
||||
base?: Maybe<Scalars['String']>;
|
||||
rateScore?: Maybe<Scalars['Int']>;
|
||||
baseScore?: Maybe<Scalars['Int']>;
|
||||
rateOver?: Maybe<Scalars['Boolean']>;
|
||||
baseOver?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type ChannelFeeHealth = {
|
||||
__typename?: 'channelFeeHealth';
|
||||
id?: Maybe<Scalars['String']>;
|
||||
partnerSide?: Maybe<FeeHealth>;
|
||||
mySide?: Maybe<FeeHealth>;
|
||||
partner?: Maybe<Node>;
|
||||
};
|
||||
|
||||
export type ChannelsFeeHealth = {
|
||||
__typename?: 'channelsFeeHealth';
|
||||
score?: Maybe<Scalars['Int']>;
|
||||
channels?: Maybe<Array<Maybe<ChannelFeeHealth>>>;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import styled, { css } from 'styled-components';
|
||||
import { headerTextColor, themeColors, mediaWidths } from '../../styles/Themes';
|
||||
import {
|
||||
headerTextColor,
|
||||
themeColors,
|
||||
mediaWidths,
|
||||
unSelectedNavButton,
|
||||
homeCompatibleColor,
|
||||
} from '../../styles/Themes';
|
||||
import { SingleLine } from '../../components/generic/Styled';
|
||||
|
||||
export const HeaderStyle = styled.div`
|
||||
|
@ -54,3 +60,31 @@ export const HeaderLine = styled(SingleLine)<{ loggedIn: boolean }>`
|
|||
`}
|
||||
}
|
||||
`;
|
||||
|
||||
export const HeaderButtons = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
interface NavProps {
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
export const HeaderNavButton = styled.div<NavProps>`
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background: ${({ selected }) => selected && homeCompatibleColor};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
margin: 0 4px;
|
||||
color: ${({ selected }) =>
|
||||
selected ? headerTextColor : unSelectedNavButton};
|
||||
|
||||
&:hover {
|
||||
color: ${headerTextColor};
|
||||
background: ${homeCompatibleColor};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Cpu, Menu, X, Circle } from 'react-feather';
|
||||
import {
|
||||
Cpu,
|
||||
Menu,
|
||||
X,
|
||||
CreditCard,
|
||||
MessageCircle,
|
||||
Settings,
|
||||
Home,
|
||||
} from 'react-feather';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import { useRouter } from 'next/router';
|
||||
import { headerColor, headerTextColor } from '../../styles/Themes';
|
||||
import { SingleLine } from '../../components/generic/Styled';
|
||||
import { BurgerMenu } from '../../components/burgerMenu/BurgerMenu';
|
||||
|
@ -14,11 +23,19 @@ import {
|
|||
HeaderLine,
|
||||
HeaderTitle,
|
||||
IconPadding,
|
||||
HeaderButtons,
|
||||
HeaderNavButton,
|
||||
} from './Header.styled';
|
||||
|
||||
const HOME = '/home';
|
||||
const TRADER = '/trading';
|
||||
const CHAT = '/chat';
|
||||
const SETTINGS = '/settings';
|
||||
|
||||
export const Header = () => {
|
||||
const { pathname } = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
const { syncedToChain, connected } = useStatusState();
|
||||
const { connected } = useStatusState();
|
||||
|
||||
const transitions = useTransition(open, null, {
|
||||
from: { position: 'absolute', opacity: 0 },
|
||||
|
@ -26,6 +43,14 @@ export const Header = () => {
|
|||
leave: { opacity: 0 },
|
||||
});
|
||||
|
||||
const renderNavButton = (link: string, NavIcon: any) => (
|
||||
<Link to={link} noStyling={true}>
|
||||
<HeaderNavButton selected={pathname === link}>
|
||||
<NavIcon size={18} />
|
||||
</HeaderNavButton>
|
||||
</Link>
|
||||
);
|
||||
|
||||
const renderLoggedIn = () => (
|
||||
<>
|
||||
<ViewSwitch>
|
||||
|
@ -44,11 +69,12 @@ export const Header = () => {
|
|||
</IconWrapper>
|
||||
</ViewSwitch>
|
||||
<ViewSwitch hideMobile={true}>
|
||||
<Circle
|
||||
size={12}
|
||||
strokeWidth={'0'}
|
||||
color={syncedToChain ? '#95de64' : '#ff7875'}
|
||||
/>
|
||||
<HeaderButtons>
|
||||
{renderNavButton(HOME, Home)}
|
||||
{renderNavButton(TRADER, CreditCard)}
|
||||
{renderNavButton(CHAT, MessageCircle)}
|
||||
{renderNavButton(SETTINGS, Settings)}
|
||||
</HeaderButtons>
|
||||
</ViewSwitch>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
Users,
|
||||
CreditCard,
|
||||
MessageCircle,
|
||||
BarChart2,
|
||||
} from 'react-feather';
|
||||
import { useRouter } from 'next/router';
|
||||
import {
|
||||
|
@ -119,10 +120,11 @@ const TRANS = '/transactions';
|
|||
const FORWARDS = '/forwards';
|
||||
const CHAIN_TRANS = '/chain';
|
||||
const TOOLS = '/tools';
|
||||
const SETTINGS = '/settings';
|
||||
const FEES = '/fees';
|
||||
const STATS = '/stats';
|
||||
const TRADER = '/trading';
|
||||
const CHAT = '/chat';
|
||||
const SETTINGS = '/settings';
|
||||
|
||||
interface NavigationProps {
|
||||
isBurger?: boolean;
|
||||
|
@ -171,9 +173,7 @@ export const Navigation = ({ isBurger, setOpen }: NavigationProps) => {
|
|||
{renderNavButton('Forwards', FORWARDS, GitPullRequest, sidebar)}
|
||||
{renderNavButton('Chain', CHAIN_TRANS, LinkIcon, sidebar)}
|
||||
{renderNavButton('Tools', TOOLS, Shield, sidebar)}
|
||||
{renderNavButton('P2P Trading', TRADER, CreditCard, sidebar)}
|
||||
{renderNavButton('Chat', CHAT, MessageCircle, sidebar)}
|
||||
{renderNavButton('Settings', SETTINGS, Settings, sidebar)}
|
||||
{renderNavButton('Stats', STATS, BarChart2, sidebar)}
|
||||
</ButtonSection>
|
||||
);
|
||||
|
||||
|
@ -188,6 +188,7 @@ export const Navigation = ({ isBurger, setOpen }: NavigationProps) => {
|
|||
{renderBurgerNav('Forwards', FORWARDS, GitPullRequest)}
|
||||
{renderBurgerNav('Chain', CHAIN_TRANS, LinkIcon)}
|
||||
{renderBurgerNav('Tools', TOOLS, Shield)}
|
||||
{renderBurgerNav('Stats', STATS, BarChart2)}
|
||||
{renderBurgerNav('Trading', TRADER, CreditCard)}
|
||||
{renderBurgerNav('Chat', CHAT, MessageCircle)}
|
||||
{renderBurgerNav('Settings', SETTINGS, Settings)}
|
||||
|
|
|
@ -120,7 +120,7 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
base_fee,
|
||||
fee_rate,
|
||||
cltv_delta,
|
||||
} = partner_node_info;
|
||||
} = partner_node_info?.node || {};
|
||||
|
||||
const formatBalance = format({ amount: capacity });
|
||||
const formatLocal = format({ amount: local_balance });
|
||||
|
|
|
@ -35,9 +35,19 @@ export const Channels: React.FC = () => {
|
|||
|
||||
for (let i = 0; i < data.getChannels.length; i++) {
|
||||
const channel = data.getChannels[i];
|
||||
const { local_balance, remote_balance, partner_node_info = {} } = channel;
|
||||
const {
|
||||
local_balance,
|
||||
remote_balance,
|
||||
partner_node_info = {},
|
||||
partner_fee_info = {},
|
||||
} = channel;
|
||||
|
||||
const { capacity, channel_count } = partner_node_info?.node || {};
|
||||
const {
|
||||
base_fee,
|
||||
fee_rate,
|
||||
} = partner_fee_info?.channel?.policies?.[0]?.node.node;
|
||||
|
||||
const { capacity, channel_count, base_fee, fee_rate } = partner_node_info;
|
||||
const partner = Number(capacity) || 0;
|
||||
const channels = Number(channel_count) || 0;
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ export const ClosedCard = ({
|
|||
partner_node_info,
|
||||
} = channelInfo;
|
||||
|
||||
const { alias, color: nodeColor } = partner_node_info;
|
||||
const { alias, color: nodeColor } = partner_node_info?.node || {};
|
||||
|
||||
const formatCapacity = <Price amount={capacity} />;
|
||||
|
||||
|
|
|
@ -68,13 +68,8 @@ export const PendingCard = ({
|
|||
partner_node_info,
|
||||
} = channelInfo;
|
||||
|
||||
const {
|
||||
alias,
|
||||
capacity,
|
||||
channel_count,
|
||||
color: nodeColor,
|
||||
updated_at,
|
||||
} = partner_node_info;
|
||||
const { alias, capacity, channel_count, color: nodeColor, updated_at } =
|
||||
partner_node_info?.node || {};
|
||||
|
||||
const formatBalance = format({ amount: local_balance + remote_balance });
|
||||
const formatLocal = format({ amount: local_balance });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { ForwardType } from 'src/graphql/types';
|
||||
import {
|
||||
Separation,
|
||||
SubCard,
|
||||
|
@ -15,7 +16,7 @@ import {
|
|||
import { Price } from '../../components/price/Price';
|
||||
|
||||
interface ForwardCardProps {
|
||||
forward: any;
|
||||
forward: ForwardType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
@ -32,10 +33,10 @@ export const ForwardCard = ({
|
|||
fee,
|
||||
fee_mtokens,
|
||||
incoming_channel,
|
||||
incoming_alias,
|
||||
outgoing_channel,
|
||||
outgoing_alias,
|
||||
tokens,
|
||||
incoming_channel_info,
|
||||
outgoing_channel_info,
|
||||
} = forward;
|
||||
|
||||
const formatAmount = <Price amount={tokens} />;
|
||||
|
@ -67,8 +68,14 @@ export const ForwardCard = ({
|
|||
<ResponsiveLine>
|
||||
<ResponsiveSingle>
|
||||
<ColumnLine>
|
||||
{renderLine('Incoming:', incoming_alias)}
|
||||
{renderLine('Outgoing:', outgoing_alias)}
|
||||
{renderLine(
|
||||
'Incoming:',
|
||||
incoming_channel_info?.channel?.policies?.[0]?.node?.node?.alias
|
||||
)}
|
||||
{renderLine(
|
||||
'Outgoing:',
|
||||
outgoing_channel_info?.channel?.policies?.[0]?.node?.node?.alias
|
||||
)}
|
||||
</ColumnLine>
|
||||
</ResponsiveSingle>
|
||||
<ColumnLine>
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
|||
import styled from 'styled-components';
|
||||
import { ArrowDown, ArrowUp } from 'react-feather';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import { PeerType } from 'src/graphql/types';
|
||||
import {
|
||||
SubCard,
|
||||
Separation,
|
||||
|
@ -43,7 +44,7 @@ const getSymbol = (status: boolean) => {
|
|||
};
|
||||
|
||||
interface PeerProps {
|
||||
peer: any;
|
||||
peer: PeerType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
@ -79,13 +80,8 @@ export const PeersCard = ({
|
|||
const formatReceived = format({ amount: tokens_received });
|
||||
const formatSent = format({ amount: tokens_sent });
|
||||
|
||||
const {
|
||||
alias,
|
||||
capacity,
|
||||
channel_count,
|
||||
color,
|
||||
updated_at,
|
||||
} = partner_node_info;
|
||||
const { alias, capacity, channel_count, color, updated_at } =
|
||||
partner_node_info?.node || {};
|
||||
|
||||
const handleClick = () => {
|
||||
if (indexOpen === index) {
|
||||
|
|
139
src/views/stats/FeeStats.tsx
Normal file
139
src/views/stats/FeeStats.tsx
Normal file
|
@ -0,0 +1,139 @@
|
|||
import * as React from 'react';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetFeeHealthQuery } from 'src/graphql/queries/__generated__/getFeeHealth.generated';
|
||||
import {
|
||||
SubCard,
|
||||
SingleLine,
|
||||
DarkSubTitle,
|
||||
Separation,
|
||||
} from 'src/components/generic/Styled';
|
||||
import { ChannelFeeHealth } from 'src/graphql/types';
|
||||
import { sortBy } from 'underscore';
|
||||
import { renderLine } from 'src/components/generic/helpers';
|
||||
import { useStatsDispatch } from './context';
|
||||
import { ScoreColumn, ScoreLine, Clickable, WarningText } from './styles';
|
||||
import { StatWrapper } from './Wrapper';
|
||||
import { getIcon, getFeeMessage, getProgressColor } from './helpers';
|
||||
|
||||
type FeeStatCardProps = {
|
||||
channel: ChannelFeeHealth;
|
||||
index: number;
|
||||
open: boolean;
|
||||
openSet: (index: number) => void;
|
||||
myStats?: boolean;
|
||||
};
|
||||
|
||||
const FeeStatCard = ({
|
||||
channel,
|
||||
myStats,
|
||||
open,
|
||||
openSet,
|
||||
index,
|
||||
}: FeeStatCardProps) => {
|
||||
const renderContent = () => {
|
||||
const stats = myStats ? channel.mySide : channel.partnerSide;
|
||||
const { score } = stats;
|
||||
|
||||
return (
|
||||
<ScoreLine>
|
||||
<DarkSubTitle>Score</DarkSubTitle>
|
||||
{score}
|
||||
{getIcon(score)}
|
||||
</ScoreLine>
|
||||
);
|
||||
};
|
||||
|
||||
const renderDetails = () => {
|
||||
const stats = myStats ? channel.mySide : channel.partnerSide;
|
||||
const { rate, base, rateScore, baseScore, rateOver, baseOver } = stats;
|
||||
|
||||
const message = getFeeMessage(rateScore, rateOver);
|
||||
const baseMessage = getFeeMessage(Number(baseScore), baseOver, true);
|
||||
return (
|
||||
<>
|
||||
<Separation />
|
||||
<WarningText warningColor={getProgressColor(rateScore)}>
|
||||
{message}
|
||||
</WarningText>
|
||||
<WarningText warningColor={getProgressColor(baseScore)}>
|
||||
{baseMessage}
|
||||
</WarningText>
|
||||
{renderLine('Fee Rate (ppm):', rate)}
|
||||
{renderLine('Base Fee (sats):', base)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SubCard key={channel.id}>
|
||||
<Clickable onClick={() => openSet(open ? 0 : index)}>
|
||||
<SingleLine>
|
||||
{channel?.partner?.node?.alias}
|
||||
<ScoreColumn>{renderContent()}</ScoreColumn>
|
||||
</SingleLine>
|
||||
</Clickable>
|
||||
{open && renderDetails()}
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export const FeeStats = () => {
|
||||
const [open, openSet] = React.useState(0);
|
||||
const [openTwo, openTwoSet] = React.useState(0);
|
||||
const dispatch = useStatsDispatch();
|
||||
const { auth } = useAccountState();
|
||||
const { data, loading } = useGetFeeHealthQuery({
|
||||
skip: !auth,
|
||||
variables: { auth },
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (data && data.getFeeHealth) {
|
||||
dispatch({
|
||||
type: 'change',
|
||||
state: { feeScore: data.getFeeHealth.score },
|
||||
});
|
||||
}
|
||||
}, [data, dispatch]);
|
||||
|
||||
if (loading || !data || !data.getFeeHealth) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sortedArray = sortBy(
|
||||
data.getFeeHealth.channels,
|
||||
c => c.partnerSide.score
|
||||
);
|
||||
const sortedArrayMyStats = sortBy(
|
||||
data.getFeeHealth.channels,
|
||||
c => c.mySide.score
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StatWrapper title={'Fee Stats'}>
|
||||
{sortedArray.map((channel, index) => (
|
||||
<FeeStatCard
|
||||
key={channel.id}
|
||||
channel={channel}
|
||||
open={index + 1 === open}
|
||||
openSet={openSet}
|
||||
index={index + 1}
|
||||
/>
|
||||
))}
|
||||
</StatWrapper>
|
||||
<StatWrapper title={'My Fee Stats'}>
|
||||
{sortedArrayMyStats.map((channel, index) => (
|
||||
<FeeStatCard
|
||||
key={channel.id}
|
||||
channel={channel}
|
||||
myStats={true}
|
||||
open={index + 1 === openTwo}
|
||||
openSet={openTwoSet}
|
||||
index={index + 1}
|
||||
/>
|
||||
))}
|
||||
</StatWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
85
src/views/stats/StatResume.tsx
Normal file
85
src/views/stats/StatResume.tsx
Normal file
|
@ -0,0 +1,85 @@
|
|||
import * as React from 'react';
|
||||
import {
|
||||
CircularProgressbarWithChildren,
|
||||
buildStyles,
|
||||
} from 'react-circular-progressbar';
|
||||
import styled from 'styled-components';
|
||||
import { DarkSubTitle } from 'src/components/generic/Styled';
|
||||
import { mediaWidths } from 'src/styles/Themes';
|
||||
import { useStatsState } from './context';
|
||||
import { StatsTitle } from './styles';
|
||||
import { getProgressColor } from './helpers';
|
||||
|
||||
const ProgressRow = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 32px 0;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
margin: 16px 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const ProgressCard = styled.div`
|
||||
width: 20%;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
width: 30%;
|
||||
}
|
||||
`;
|
||||
|
||||
const ScoreTitle = styled.div`
|
||||
font-size: 32px;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
font-size: 18px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StatResume = () => {
|
||||
const { volumeScore, timeScore, feeScore } = useStatsState();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StatsTitle>Node Statistics</StatsTitle>
|
||||
<ProgressRow>
|
||||
<ProgressCard>
|
||||
<CircularProgressbarWithChildren
|
||||
value={volumeScore}
|
||||
styles={buildStyles({
|
||||
pathColor: getProgressColor(volumeScore),
|
||||
trailColor: 'rgba(0, 0, 0, 0.1)',
|
||||
})}
|
||||
>
|
||||
<DarkSubTitle>Volume</DarkSubTitle>
|
||||
<ScoreTitle>{volumeScore}</ScoreTitle>
|
||||
</CircularProgressbarWithChildren>
|
||||
</ProgressCard>
|
||||
<ProgressCard>
|
||||
<CircularProgressbarWithChildren
|
||||
value={timeScore}
|
||||
styles={buildStyles({
|
||||
pathColor: getProgressColor(timeScore),
|
||||
trailColor: 'rgba(0, 0, 0, 0.1)',
|
||||
})}
|
||||
>
|
||||
<DarkSubTitle>Time</DarkSubTitle>
|
||||
<ScoreTitle>{timeScore}</ScoreTitle>
|
||||
</CircularProgressbarWithChildren>
|
||||
</ProgressCard>
|
||||
<ProgressCard>
|
||||
<CircularProgressbarWithChildren
|
||||
value={feeScore}
|
||||
styles={buildStyles({
|
||||
pathColor: getProgressColor(feeScore),
|
||||
trailColor: 'rgba(0, 0, 0, 0.1)',
|
||||
})}
|
||||
>
|
||||
<DarkSubTitle>Fee</DarkSubTitle>
|
||||
<ScoreTitle>{feeScore}</ScoreTitle>
|
||||
</CircularProgressbarWithChildren>
|
||||
</ProgressCard>
|
||||
</ProgressRow>
|
||||
</>
|
||||
);
|
||||
};
|
103
src/views/stats/TimeStats.tsx
Normal file
103
src/views/stats/TimeStats.tsx
Normal file
|
@ -0,0 +1,103 @@
|
|||
import * as React from 'react';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import { useGetTimeHealthQuery } from 'src/graphql/queries/__generated__/getTimeHealth.generated';
|
||||
import {
|
||||
SubCard,
|
||||
SingleLine,
|
||||
SubTitle,
|
||||
DarkSubTitle,
|
||||
Separation,
|
||||
} from 'src/components/generic/Styled';
|
||||
import { ChannelTimeHealth } from 'src/graphql/types';
|
||||
import { sortBy } from 'underscore';
|
||||
import { renderLine } from 'src/components/generic/helpers';
|
||||
import { formatSeconds } from 'src/utils/helpers';
|
||||
import { useStatsDispatch } from './context';
|
||||
import { ScoreLine, WarningText, Clickable } from './styles';
|
||||
import { StatWrapper } from './Wrapper';
|
||||
import { getIcon, getTimeMessage, getProgressColor } from './helpers';
|
||||
|
||||
type TimeStatCardProps = {
|
||||
channel: ChannelTimeHealth;
|
||||
index: number;
|
||||
open: boolean;
|
||||
openSet: (index: number) => void;
|
||||
};
|
||||
|
||||
const TimeStatCard = ({ channel, open, openSet, index }: TimeStatCardProps) => {
|
||||
const message = getTimeMessage(channel.score);
|
||||
const renderContent = () => (
|
||||
<>
|
||||
<Separation />
|
||||
{!channel.significant && (
|
||||
<WarningText>
|
||||
Needs to be monitored for a longer period to give significant
|
||||
statistics.
|
||||
</WarningText>
|
||||
)}
|
||||
<WarningText warningColor={getProgressColor(channel.score)}>
|
||||
{message}
|
||||
</WarningText>
|
||||
{renderLine('Monitored time:', formatSeconds(channel.monitoredTime))}
|
||||
{renderLine('Monitored up time:', formatSeconds(channel.monitoredUptime))}
|
||||
{renderLine(
|
||||
'Monitored down time:',
|
||||
formatSeconds(channel.monitoredDowntime)
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<SubCard key={channel.id}>
|
||||
<Clickable onClick={() => openSet(open ? 0 : index)}>
|
||||
<SingleLine>
|
||||
<SubTitle>{channel?.partner?.node?.alias}</SubTitle>
|
||||
<ScoreLine>
|
||||
<DarkSubTitle>Score</DarkSubTitle>
|
||||
{channel.score}
|
||||
{getIcon(channel.score, !channel.significant)}
|
||||
</ScoreLine>
|
||||
</SingleLine>
|
||||
</Clickable>
|
||||
{open && renderContent()}
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export const TimeStats = () => {
|
||||
const [open, openSet] = React.useState(0);
|
||||
const dispatch = useStatsDispatch();
|
||||
const { auth } = useAccountState();
|
||||
const { data, loading } = useGetTimeHealthQuery({
|
||||
skip: !auth,
|
||||
variables: { auth },
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (data && data.getTimeHealth) {
|
||||
dispatch({
|
||||
type: 'change',
|
||||
state: { timeScore: data.getTimeHealth.score },
|
||||
});
|
||||
}
|
||||
}, [data, dispatch]);
|
||||
|
||||
if (loading || !data || !data.getTimeHealth) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sortedArray = sortBy(data.getTimeHealth.channels, 'score');
|
||||
|
||||
return (
|
||||
<StatWrapper title={'Time Stats'}>
|
||||
{sortedArray.map((channel, index) => (
|
||||
<TimeStatCard
|
||||
key={channel.id}
|
||||
channel={channel}
|
||||
open={index + 1 === open}
|
||||
openSet={openSet}
|
||||
index={index + 1}
|
||||
/>
|
||||
))}
|
||||
</StatWrapper>
|
||||
);
|
||||
};
|
100
src/views/stats/VolumeStats.tsx
Normal file
100
src/views/stats/VolumeStats.tsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import * as React from 'react';
|
||||
import { useGetVolumeHealthQuery } from 'src/graphql/queries/__generated__/getVolumeHealth.generated';
|
||||
import { useAccountState } from 'src/context/AccountContext';
|
||||
import {
|
||||
SubCard,
|
||||
SingleLine,
|
||||
DarkSubTitle,
|
||||
SubTitle,
|
||||
Separation,
|
||||
} from 'src/components/generic/Styled';
|
||||
import { sortBy } from 'underscore';
|
||||
import { renderLine } from 'src/components/generic/helpers';
|
||||
import { ChannelHealth } from 'src/graphql/types';
|
||||
import { useStatsDispatch } from './context';
|
||||
import { ScoreLine, Clickable, WarningText } from './styles';
|
||||
import { StatWrapper } from './Wrapper';
|
||||
import { getIcon, getVolumeMessage, getProgressColor } from './helpers';
|
||||
|
||||
type VolumeStatCardProps = {
|
||||
channel: ChannelHealth;
|
||||
index: number;
|
||||
open: boolean;
|
||||
openSet: (index: number) => void;
|
||||
};
|
||||
|
||||
const VolumeStatCard = ({
|
||||
channel,
|
||||
open,
|
||||
openSet,
|
||||
index,
|
||||
}: VolumeStatCardProps) => {
|
||||
const message = getVolumeMessage(channel.score);
|
||||
const renderContent = () => (
|
||||
<>
|
||||
<Separation />
|
||||
<WarningText warningColor={getProgressColor(channel.score)}>
|
||||
{message}
|
||||
</WarningText>
|
||||
{renderLine('Volume (sats/block):', channel.volumeNormalized)}
|
||||
{renderLine(
|
||||
'Average Volume (sats/block):',
|
||||
channel.averageVolumeNormalized
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<SubCard key={channel.id}>
|
||||
<Clickable onClick={() => openSet(open ? 0 : index)}>
|
||||
<SingleLine>
|
||||
<SubTitle>{channel?.partner?.node?.alias}</SubTitle>
|
||||
<ScoreLine>
|
||||
<DarkSubTitle>{'Score'}</DarkSubTitle>
|
||||
{channel.score}
|
||||
{getIcon(channel.score)}
|
||||
</ScoreLine>
|
||||
</SingleLine>
|
||||
</Clickable>
|
||||
{open && renderContent()}
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
||||
export const VolumeStats = () => {
|
||||
const [open, openSet] = React.useState(0);
|
||||
const dispatch = useStatsDispatch();
|
||||
const { auth } = useAccountState();
|
||||
const { data, loading } = useGetVolumeHealthQuery({
|
||||
skip: !auth,
|
||||
variables: { auth },
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (data && data.getVolumeHealth) {
|
||||
dispatch({
|
||||
type: 'change',
|
||||
state: { volumeScore: data.getVolumeHealth.score },
|
||||
});
|
||||
}
|
||||
}, [data, dispatch]);
|
||||
|
||||
if (loading || !data || !data.getVolumeHealth) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sortedArray = sortBy(data.getVolumeHealth.channels, 'score');
|
||||
|
||||
return (
|
||||
<StatWrapper title={'Volume Stats'}>
|
||||
{sortedArray.map((channel, index) => (
|
||||
<VolumeStatCard
|
||||
key={channel.id}
|
||||
channel={channel}
|
||||
open={index + 1 === open}
|
||||
openSet={openSet}
|
||||
index={index + 1}
|
||||
/>
|
||||
))}
|
||||
</StatWrapper>
|
||||
);
|
||||
};
|
25
src/views/stats/Wrapper.tsx
Normal file
25
src/views/stats/Wrapper.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from 'react';
|
||||
import { Card, SubTitle } from 'src/components/generic/Styled';
|
||||
import { ChevronDown, ChevronUp } from 'react-feather';
|
||||
import { StatHeaderLine } from './styles';
|
||||
|
||||
type StatWrapperProps = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export const StatWrapper: React.FC<StatWrapperProps> = ({
|
||||
children,
|
||||
title,
|
||||
}) => {
|
||||
const [open, openSet] = React.useState(false);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<StatHeaderLine isOpen={open} onClick={() => openSet(p => !p)}>
|
||||
<SubTitle>{title}</SubTitle>
|
||||
{open ? <ChevronUp /> : <ChevronDown />}
|
||||
</StatHeaderLine>
|
||||
{open && children}
|
||||
</Card>
|
||||
);
|
||||
};
|
66
src/views/stats/context/index.tsx
Normal file
66
src/views/stats/context/index.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
import React, { createContext, useContext, useReducer } from 'react';
|
||||
|
||||
type State = {
|
||||
volumeScore: number | null;
|
||||
timeScore: number | null;
|
||||
feeScore: number | null;
|
||||
};
|
||||
|
||||
type ChangeState = {
|
||||
volumeScore?: number;
|
||||
timeScore?: number;
|
||||
feeScore?: number;
|
||||
};
|
||||
|
||||
type ActionType = {
|
||||
type: 'change';
|
||||
state?: ChangeState;
|
||||
};
|
||||
|
||||
type Dispatch = (action: ActionType) => void;
|
||||
|
||||
const StateContext = createContext<State | undefined>(undefined);
|
||||
const DispatchContext = createContext<Dispatch | undefined>(undefined);
|
||||
|
||||
const initialState = {
|
||||
volumeScore: 0,
|
||||
timeScore: 0,
|
||||
feeScore: 0,
|
||||
};
|
||||
|
||||
const stateReducer = (state: State, action: ActionType): State => {
|
||||
switch (action.type) {
|
||||
case 'change':
|
||||
return { ...state, ...action.state };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const StatsProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(stateReducer, initialState);
|
||||
|
||||
return (
|
||||
<DispatchContext.Provider value={dispatch}>
|
||||
<StateContext.Provider value={state}>{children}</StateContext.Provider>
|
||||
</DispatchContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useStatsState = () => {
|
||||
const context = useContext(StateContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useStatsState must be used within a StatsProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
const useStatsDispatch = () => {
|
||||
const context = useContext(DispatchContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useStatsDispatch must be used within a StatsProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export { StatsProvider, useStatsState, useStatsDispatch };
|
129
src/views/stats/helpers.tsx
Normal file
129
src/views/stats/helpers.tsx
Normal file
|
@ -0,0 +1,129 @@
|
|||
import * as React from 'react';
|
||||
import { chartColors } from 'src/styles/Themes';
|
||||
import {
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
XCircle,
|
||||
AlertTriangle,
|
||||
} from 'react-feather';
|
||||
|
||||
export const getProgressColor = (score: number): string => {
|
||||
switch (true) {
|
||||
case score > 90:
|
||||
return chartColors.green;
|
||||
case score > 75:
|
||||
return chartColors.darkyellow;
|
||||
case score > 60:
|
||||
return chartColors.orange;
|
||||
case score > 50:
|
||||
return chartColors.orange2;
|
||||
default:
|
||||
return chartColors.red;
|
||||
}
|
||||
};
|
||||
|
||||
export const getIcon = (
|
||||
score: number,
|
||||
notSignificant?: boolean
|
||||
): JSX.Element => {
|
||||
if (notSignificant) {
|
||||
return <AlertTriangle color={chartColors.orange} />;
|
||||
}
|
||||
switch (true) {
|
||||
case score > 90:
|
||||
return <CheckCircle color={getProgressColor(score)} />;
|
||||
case score > 75:
|
||||
return <CheckCircle color={getProgressColor(score)} />;
|
||||
case score > 60:
|
||||
return <AlertCircle color={getProgressColor(score)} />;
|
||||
case score > 50:
|
||||
return <AlertCircle color={getProgressColor(score)} />;
|
||||
default:
|
||||
return <XCircle color={getProgressColor(score)} />;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFeeMessage = (
|
||||
score: number,
|
||||
isOver: boolean,
|
||||
isBase?: boolean
|
||||
): string => {
|
||||
let message = '';
|
||||
const ending = isBase ? 'base fees' : 'ppm fees';
|
||||
switch (true) {
|
||||
case score > 90:
|
||||
message = 'This channel has very good';
|
||||
break;
|
||||
case score > 75:
|
||||
message = 'This channel has good';
|
||||
break;
|
||||
case score > 60 && isOver:
|
||||
message = 'This channel has above average high';
|
||||
break;
|
||||
case score > 60:
|
||||
message = 'This channel could have higher';
|
||||
break;
|
||||
case score > 50 && isOver:
|
||||
message = 'This channel has high';
|
||||
break;
|
||||
case score > 50:
|
||||
message = 'This channel has too low';
|
||||
break;
|
||||
case isOver:
|
||||
message = 'This channel has very high';
|
||||
break;
|
||||
default:
|
||||
message = 'This channel has very low';
|
||||
break;
|
||||
}
|
||||
return `${message} ${ending}`;
|
||||
};
|
||||
|
||||
export const getTimeMessage = (score: number): string => {
|
||||
let message = '';
|
||||
switch (true) {
|
||||
case score > 90:
|
||||
message = 'This channel has very good uptime';
|
||||
break;
|
||||
case score > 75:
|
||||
message = 'This channel has good uptime';
|
||||
break;
|
||||
case score > 60:
|
||||
message = 'This channel has average uptime';
|
||||
break;
|
||||
case score > 50:
|
||||
message = 'This channel has below average uptime';
|
||||
break;
|
||||
default:
|
||||
message = 'This channel has very bad uptime';
|
||||
break;
|
||||
}
|
||||
return message;
|
||||
};
|
||||
|
||||
export const getVolumeMessage = (score: number): string => {
|
||||
let message = '';
|
||||
switch (true) {
|
||||
case score > 100:
|
||||
message = `This channel moves ${
|
||||
score - 100
|
||||
}% more volume than the average from all your channels`;
|
||||
break;
|
||||
case score > 90:
|
||||
message = 'This channel moves very good volume';
|
||||
break;
|
||||
case score > 75:
|
||||
message = 'This channel moves good volume';
|
||||
break;
|
||||
case score > 60:
|
||||
message = 'This channel moves average volume';
|
||||
break;
|
||||
case score > 50:
|
||||
message = 'This channel moves below average volume';
|
||||
break;
|
||||
default:
|
||||
message = 'This channel moves very low volume';
|
||||
break;
|
||||
}
|
||||
return message;
|
||||
};
|
48
src/views/stats/styles.tsx
Normal file
48
src/views/stats/styles.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
import styled from 'styled-components';
|
||||
import { DarkSubTitle } from 'src/components/generic/Styled';
|
||||
import { chartColors } from 'src/styles/Themes';
|
||||
|
||||
export const ScoreColumn = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export const ScoreLine = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 160px;
|
||||
`;
|
||||
|
||||
type StatHeaderProps = {
|
||||
isOpen?: boolean;
|
||||
};
|
||||
|
||||
export const StatHeaderLine = styled.div<StatHeaderProps>`
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: 8px 0 16px;
|
||||
margin-bottom: ${({ isOpen }) => (isOpen ? 0 : '-8px')};
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const StatsTitle = styled.div`
|
||||
font-size: 24px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
type WarningProps = {
|
||||
warningColor?: string;
|
||||
};
|
||||
|
||||
export const WarningText = styled(DarkSubTitle)<WarningProps>`
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: ${({ warningColor }) =>
|
||||
warningColor ? warningColor : chartColors.orange};
|
||||
`;
|
||||
|
||||
export const Clickable = styled.div`
|
||||
cursor: pointer;
|
||||
`;
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { InvoiceType } from 'src/graphql/types';
|
||||
import {
|
||||
Separation,
|
||||
SubCard,
|
||||
|
@ -20,7 +21,7 @@ import {
|
|||
import { Price } from '../../components/price/Price';
|
||||
|
||||
interface InvoiceCardProps {
|
||||
invoice: any;
|
||||
invoice: InvoiceType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
@ -33,25 +34,20 @@ export const InvoiceCard = ({
|
|||
indexOpen,
|
||||
}: InvoiceCardProps) => {
|
||||
const {
|
||||
date,
|
||||
chain_address,
|
||||
confirmed_at,
|
||||
created_at,
|
||||
description,
|
||||
expires_at,
|
||||
is_confirmed,
|
||||
// received,
|
||||
tokens,
|
||||
chain_address,
|
||||
description_hash,
|
||||
expires_at,
|
||||
id,
|
||||
is_canceled,
|
||||
is_confirmed,
|
||||
is_held,
|
||||
is_outgoing,
|
||||
is_private,
|
||||
// payments,
|
||||
// received_mtokens,
|
||||
// request,
|
||||
secret,
|
||||
tokens,
|
||||
date,
|
||||
} = invoice;
|
||||
|
||||
const formatAmount = <Price amount={tokens} />;
|
||||
|
@ -86,7 +82,6 @@ export const InvoiceCard = ({
|
|||
{renderLine('Description Hash:', description_hash)}
|
||||
{renderLine('Is Canceled:', is_canceled)}
|
||||
{renderLine('Is Held:', is_held)}
|
||||
{renderLine('Is Outgoing:', is_outgoing)}
|
||||
{renderLine('Is Private:', is_private)}
|
||||
{renderLine('Secret:', secret)}
|
||||
</>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { PaymentType } from 'src/graphql/types';
|
||||
import {
|
||||
Separation,
|
||||
SubCard,
|
||||
|
@ -21,7 +22,7 @@ import {
|
|||
import { Price } from '../../components/price/Price';
|
||||
|
||||
interface PaymentsCardProps {
|
||||
payment: any;
|
||||
payment: PaymentType;
|
||||
index: number;
|
||||
setIndexOpen: (index: number) => void;
|
||||
indexOpen: number;
|
||||
|
@ -38,21 +39,23 @@ export const PaymentsCard = ({
|
|||
indexOpen,
|
||||
}: PaymentsCardProps) => {
|
||||
const {
|
||||
alias,
|
||||
date,
|
||||
created_at,
|
||||
destination,
|
||||
destination_node,
|
||||
fee,
|
||||
fee_mtokens,
|
||||
hops,
|
||||
is_confirmed,
|
||||
tokens,
|
||||
id,
|
||||
is_confirmed,
|
||||
is_outgoing,
|
||||
mtokens,
|
||||
secret,
|
||||
tokens,
|
||||
date,
|
||||
} = payment;
|
||||
|
||||
const alias = destination_node?.node?.alias;
|
||||
|
||||
const formatAmount = <Price amount={tokens} />;
|
||||
const formatFee = <Price amount={fee} />;
|
||||
|
||||
|
@ -72,12 +75,15 @@ export const PaymentsCard = ({
|
|||
'Created:',
|
||||
`${getDateDif(created_at)} ago (${getFormatDate(created_at)})`
|
||||
)}
|
||||
{renderLine('Destination Node:', getNodeLink(destination))}
|
||||
{renderLine('Destination Node:', getNodeLink(destination, alias))}
|
||||
{renderLine('Fee:', formatFee)}
|
||||
{renderLine('Fee msats:', `${fee_mtokens} millisats`)}
|
||||
{renderLine('Hops:', hops.length)}
|
||||
{hops.map((hop: any, index: number) =>
|
||||
renderLine(`Hop ${index + 1}:`, hop)
|
||||
{hops.map((hop, index: number) =>
|
||||
renderLine(
|
||||
`Hop ${index + 1}:`,
|
||||
getNodeLink(destination, hop.node.alias)
|
||||
)
|
||||
)}
|
||||
{renderLine('Id:', id)}
|
||||
{renderLine('Is Outgoing:', is_outgoing ? 'true' : 'false')}
|
||||
|
|
Loading…
Add table
Reference in a new issue