mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-22 14:22:33 +01:00
React tables migration (#540)
* feat: migration ClosedChannels and ChannelTable to tanstack react-table * feat: create ColumnConfigurations to encapsulate functionality * feat: hook up local storage to channel configurations * feat: finish migrating all tables in codebase to tanstack * feat: update package.json, remove dependency, and delete react-table * fix: migrate missing table * fix: remove default pagination --------- Co-authored-by: Anthony Potdevin <31413433+apotdevin@users.noreply.github.com>
This commit is contained in:
parent
8a55db4cb4
commit
ec2857b11b
18 changed files with 692 additions and 760 deletions
38
package-lock.json
generated
38
package-lock.json
generated
|
@ -74,7 +74,6 @@
|
|||
"react-select": "^5.7.3",
|
||||
"react-slider": "^2.0.4",
|
||||
"react-spinners": "^0.13.8",
|
||||
"react-table": "^7.8.0",
|
||||
"react-toastify": "^9.1.3",
|
||||
"react-tooltip": "^5.13.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -122,7 +121,6 @@
|
|||
"@types/react-grid-layout": "^1.3.2",
|
||||
"@types/react-qr-reader": "^2.1.4",
|
||||
"@types/react-slider": "^1.3.1",
|
||||
"@types/react-table": "^7.7.14",
|
||||
"@types/secp256k1": "^4.0.3",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/styled-react-modal": "^1.2.2",
|
||||
|
@ -6911,15 +6909,6 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-table": {
|
||||
"version": "7.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-7.7.14.tgz",
|
||||
"integrity": "sha512-TYrv7onCiakaG1uAu/UpQ9FojNEt/4/ht87EgJQaEGFoWV606ZLWUZAcUHzMxgc3v1mywP1cDyz3qB4ho3hWOw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
|
||||
|
@ -19186,18 +19175,6 @@
|
|||
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-table": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
|
||||
"integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.3 || ^17.0.0-0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-toastify": {
|
||||
"version": "9.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz",
|
||||
|
@ -27798,15 +27775,6 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-table": {
|
||||
"version": "7.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-7.7.14.tgz",
|
||||
"integrity": "sha512-TYrv7onCiakaG1uAu/UpQ9FojNEt/4/ht87EgJQaEGFoWV606ZLWUZAcUHzMxgc3v1mywP1cDyz3qB4ho3hWOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
|
||||
|
@ -37264,12 +37232,6 @@
|
|||
"integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-table": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
|
||||
"integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-toastify": {
|
||||
"version": "9.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz",
|
||||
|
|
|
@ -99,7 +99,6 @@
|
|||
"react-select": "^5.7.3",
|
||||
"react-slider": "^2.0.4",
|
||||
"react-spinners": "^0.13.8",
|
||||
"react-table": "^7.8.0",
|
||||
"react-toastify": "^9.1.3",
|
||||
"react-tooltip": "^5.13.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
|
@ -147,7 +146,6 @@
|
|||
"@types/react-grid-layout": "^1.3.2",
|
||||
"@types/react-qr-reader": "^2.1.4",
|
||||
"@types/react-slider": "^1.3.1",
|
||||
"@types/react-table": "^7.7.14",
|
||||
"@types/secp256k1": "^4.0.3",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/styled-react-modal": "^1.2.2",
|
||||
|
|
|
@ -12,8 +12,8 @@ import {
|
|||
import { LoadingCard } from '../src/components/loading/LoadingCard';
|
||||
import { AddPeer } from '../src/views/peers/AddPeer';
|
||||
import { copyLink, getNodeLink } from '../src/components/generic/helpers';
|
||||
import { Table } from '../src/components/table';
|
||||
import { Price } from '../src/components/price/Price';
|
||||
import Table from '../src/components/table';
|
||||
|
||||
const PeersView = () => {
|
||||
const { loading, data } = useGetPeersQuery();
|
||||
|
@ -32,27 +32,27 @@ const PeersView = () => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Peer',
|
||||
accessor: 'alias',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Peer',
|
||||
accessorKey: 'alias',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getNodeLink(row.original.public_key, row.original.alias)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Sync Peer',
|
||||
accessor: 'is_sync_peer',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sync Peer',
|
||||
accessorKey: 'is_sync_peer',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{row.original.is_sync_peer ? 'Yes' : '-'}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Socket',
|
||||
accessor: 'socket',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Socket',
|
||||
accessorKey: 'socket',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{row.original.socket.includes('.onion') ? 'Tor' : 'Clearnet'}
|
||||
{copyLink(row.original.socket)}
|
||||
|
@ -60,45 +60,45 @@ const PeersView = () => {
|
|||
),
|
||||
},
|
||||
{
|
||||
Header: 'Ping',
|
||||
accessor: 'ping_time',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Ping',
|
||||
accessorKey: 'ping_time',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{`${row.original.ping_time} ms`}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Sats Received',
|
||||
accessor: 'tokens_received',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sats Received',
|
||||
accessorKey: 'tokens_received',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.tokens_received} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Sats Sent',
|
||||
accessor: 'tokens_sent',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sats Sent',
|
||||
accessorKey: 'tokens_sent',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.tokens_sent} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Bytes Received',
|
||||
accessor: 'bytes_received',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Bytes Received',
|
||||
accessorKey: 'bytes_received',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{`${Math.round(row.original.bytes_received * 0.0001) / 100} MB`}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Bytes Sent',
|
||||
accessor: 'bytes_sent',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Bytes Sent',
|
||||
accessorKey: 'bytes_sent',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{`${Math.round(row.original.bytes_sent * 0.0001) / 100} MB`}
|
||||
</div>
|
||||
|
@ -130,8 +130,10 @@ const PeersView = () => {
|
|||
<Card mobileNoBackground={true}>
|
||||
<Table
|
||||
withBorder={true}
|
||||
tableColumns={columns}
|
||||
tableData={tableData}
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withSorting={true}
|
||||
withGlobalSort={true}
|
||||
filterPlaceholder="peers"
|
||||
/>
|
||||
</Card>
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import {
|
||||
useReactTable,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
flexRender,
|
||||
ColumnDef,
|
||||
SortingState,
|
||||
} from '@tanstack/react-table';
|
||||
import { Input } from '../input';
|
||||
import { separationColor } from '../../../src/styles/Themes';
|
||||
|
||||
interface TableV2Props {
|
||||
columns: ColumnDef<any, any>[];
|
||||
data: any;
|
||||
filterPlaceholder: string;
|
||||
withBorder?: boolean;
|
||||
alignCenter?: boolean;
|
||||
fontSize?: string;
|
||||
}
|
||||
|
||||
const FilterLine = styled.div`
|
||||
margin-bottom: 24px;
|
||||
`;
|
||||
|
||||
type StyledTableProps = {
|
||||
withBorder?: boolean;
|
||||
alignCenter?: boolean;
|
||||
fontSize?: string;
|
||||
};
|
||||
|
||||
const Styles = styled.div`
|
||||
overflow-x: auto;
|
||||
table {
|
||||
border-spacing: 0;
|
||||
tr {
|
||||
:last-child {
|
||||
td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.cursor {
|
||||
cursor: pointer;
|
||||
}
|
||||
,
|
||||
th,
|
||||
td {
|
||||
font-size: ${({ fontSize }: StyledTableProps) => fontSize || '14px'};
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
${({ withBorder }: StyledTableProps) =>
|
||||
withBorder &&
|
||||
css`
|
||||
border-bottom: 1px solid ${separationColor};
|
||||
`}
|
||||
${({ alignCenter }: StyledTableProps) =>
|
||||
alignCenter &&
|
||||
css`
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
`}
|
||||
:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function TableV2({
|
||||
columns,
|
||||
data,
|
||||
filterPlaceholder,
|
||||
withBorder,
|
||||
alignCenter,
|
||||
fontSize,
|
||||
}: TableV2Props) {
|
||||
const [globalFilter, setGlobalFilter] = useState('');
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
state: {
|
||||
globalFilter,
|
||||
sorting,
|
||||
},
|
||||
enableSorting: true,
|
||||
onGlobalFilterChange: setGlobalFilter,
|
||||
onSortingChange: setSorting,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<FilterLine>
|
||||
<DebouncedInput
|
||||
value={globalFilter ?? ''}
|
||||
onChange={value => setGlobalFilter(String(value))}
|
||||
placeholder={filterPlaceholder}
|
||||
count={table.getFilteredRowModel().rows.length}
|
||||
/>
|
||||
</FilterLine>
|
||||
|
||||
<Styles
|
||||
withBorder={withBorder}
|
||||
fontSize={fontSize}
|
||||
alignCenter={alignCenter}
|
||||
>
|
||||
<table>
|
||||
<thead>
|
||||
{table.getHeaderGroups().map(headerGroup => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
colSpan={header.colSpan}
|
||||
style={{ whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
<>
|
||||
<div
|
||||
{...{
|
||||
className: header.column.getCanSort()
|
||||
? 'cursor'
|
||||
: '',
|
||||
onClick: header.column.getToggleSortingHandler(),
|
||||
}}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
{{
|
||||
asc: ' ⬆',
|
||||
desc: ' ⬇',
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{table.getRowModel().rows.map(row => {
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
{row.getVisibleCells().map(cell => {
|
||||
return (
|
||||
<td key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</Styles>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// A debounced input react component
|
||||
function DebouncedInput({
|
||||
value: initialValue,
|
||||
onChange,
|
||||
debounce = 500,
|
||||
placeholder,
|
||||
count,
|
||||
}: {
|
||||
value: string | number;
|
||||
onChange: (value: string | number) => void;
|
||||
count: number;
|
||||
debounce?: number;
|
||||
placeholder?: string;
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>) {
|
||||
const [value, setValue] = useState(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
onChange(value);
|
||||
}, debounce);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
maxWidth={'300px'}
|
||||
value={value || ''}
|
||||
onChange={e => setValue(e.target.value)}
|
||||
placeholder={`Search ${count} ${placeholder || ''}`}
|
||||
/>
|
||||
);
|
||||
}
|
95
src/client/src/components/table/ColumnConfigurations.tsx
Normal file
95
src/client/src/components/table/ColumnConfigurations.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
import { Table } from '@tanstack/react-table';
|
||||
import { FC, useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { mediaWidths } from '../../styles/Themes';
|
||||
import { groupBy } from 'lodash';
|
||||
import { DarkSubTitle, SubCard } from '../generic/Styled';
|
||||
|
||||
interface ColumnConfigurationsProps {
|
||||
table: Table<any>;
|
||||
toggleConfiguration: (hide: boolean, id: string) => void;
|
||||
}
|
||||
|
||||
const S = {
|
||||
row: styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
`,
|
||||
optionRow: styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
option: styled.label`
|
||||
margin: 4px 8px;
|
||||
`,
|
||||
options: styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
flex-direction: row;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const ColumnConfigurations: FC<ColumnConfigurationsProps> = ({
|
||||
table,
|
||||
toggleConfiguration,
|
||||
}: ColumnConfigurationsProps) => {
|
||||
// The columns that are hideable in configurations need to be grouped by their parents id in order for display purposes, see enableHiding to toggle viewability of each column
|
||||
const groupedHideableColumns = useMemo(() => {
|
||||
const allLeafColumns = table
|
||||
.getAllLeafColumns()
|
||||
.filter(c => c.getCanHide());
|
||||
const grouped = groupBy(allLeafColumns, (c: any) => c?.parent?.id);
|
||||
return grouped;
|
||||
}, [table]);
|
||||
|
||||
return (
|
||||
<S.optionRow>
|
||||
{Object.keys(groupedHideableColumns).map(
|
||||
(group: string, index: number) => {
|
||||
return (
|
||||
<SubCard key={`${group}-${index}`} style={{ height: 'auto' }}>
|
||||
<DarkSubTitle fontSize="16px">
|
||||
{group === 'undefined' ? 'General' : group}
|
||||
</DarkSubTitle>
|
||||
<S.options>
|
||||
{groupedHideableColumns[group].map((column: any) => {
|
||||
return (
|
||||
<S.option key={column.id} className="px-1">
|
||||
<label>
|
||||
<input
|
||||
{...{
|
||||
type: 'checkbox',
|
||||
checked: column.getIsVisible(),
|
||||
onChange: column.getToggleVisibilityHandler(),
|
||||
}}
|
||||
onClick={(e: any) =>
|
||||
toggleConfiguration(!e.target.checked, column.id)
|
||||
}
|
||||
/>{' '}
|
||||
{column.columnDef.header}
|
||||
</label>
|
||||
</S.option>
|
||||
);
|
||||
})}
|
||||
</S.options>
|
||||
</SubCard>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</S.optionRow>
|
||||
);
|
||||
};
|
40
src/client/src/components/table/DebouncedInput.tsx
Normal file
40
src/client/src/components/table/DebouncedInput.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { Input } from '../input';
|
||||
|
||||
// A debounced input react component
|
||||
export function DebouncedInput({
|
||||
value: initialValue,
|
||||
onChange,
|
||||
debounce = 500,
|
||||
placeholder,
|
||||
count,
|
||||
}: {
|
||||
value: string | number;
|
||||
onChange: (value: string | number) => void;
|
||||
count: number;
|
||||
debounce?: number;
|
||||
placeholder?: string;
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>) {
|
||||
const [value, setValue] = useState(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
onChange(value);
|
||||
}, debounce);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
maxWidth={'300px'}
|
||||
value={value || ''}
|
||||
onChange={e => setValue(e.target.value)}
|
||||
placeholder={`Search ${count} ${placeholder || ''}`}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -1,21 +1,33 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import {
|
||||
useTable,
|
||||
useSortBy,
|
||||
useAsyncDebounce,
|
||||
useGlobalFilter,
|
||||
TableInstance,
|
||||
useFilters,
|
||||
ColumnInstance,
|
||||
} from 'react-table';
|
||||
import { mediaWidths, separationColor } from '../../../src/styles/Themes';
|
||||
import { Input } from '../input';
|
||||
useReactTable,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getSortedRowModel,
|
||||
flexRender,
|
||||
ColumnDef,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
} from '@tanstack/react-table';
|
||||
import { Settings, X } from 'react-feather';
|
||||
import { separationColor } from '../../styles/Themes';
|
||||
import { ColorButton } from '../buttons/colorButton/ColorButton';
|
||||
import { DarkSubTitle, SubCard } from '../generic/Styled';
|
||||
import { groupBy } from 'lodash';
|
||||
import 'regenerator-runtime/runtime';
|
||||
import { ColumnConfigurations } from './ColumnConfigurations';
|
||||
import { DebouncedInput } from './DebouncedInput';
|
||||
|
||||
interface TableProps {
|
||||
columns: ColumnDef<any, any>[];
|
||||
data: any;
|
||||
filterPlaceholder?: string;
|
||||
withGlobalSort?: boolean; // enables the global search box
|
||||
withSorting?: boolean; // enables columns to be sorted
|
||||
withBorder?: boolean;
|
||||
alignCenter?: boolean;
|
||||
fontSize?: string;
|
||||
defaultHiddenColumns?: VisibilityState;
|
||||
toggleConfiguration?: (hide: boolean, id: string) => void;
|
||||
}
|
||||
|
||||
type StyledTableProps = {
|
||||
withBorder?: boolean;
|
||||
|
@ -23,290 +35,185 @@ type StyledTableProps = {
|
|||
fontSize?: string;
|
||||
};
|
||||
|
||||
const Styles = styled.div`
|
||||
overflow-x: auto;
|
||||
table {
|
||||
border-spacing: 0;
|
||||
tr {
|
||||
:last-child {
|
||||
td {
|
||||
border-bottom: 0;
|
||||
const S = {
|
||||
row: styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
`,
|
||||
wrapper: styled.div`
|
||||
overflow-x: auto;
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
tr {
|
||||
:last-child {
|
||||
td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.cursor {
|
||||
cursor: pointer;
|
||||
}
|
||||
,
|
||||
th,
|
||||
td {
|
||||
font-size: ${({ fontSize }: StyledTableProps) => fontSize || '14px'};
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
${({ withBorder }: StyledTableProps) =>
|
||||
withBorder &&
|
||||
css`
|
||||
border-bottom: 1px solid ${separationColor};
|
||||
`}
|
||||
${({ alignCenter }: StyledTableProps) =>
|
||||
alignCenter &&
|
||||
css`
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
`}
|
||||
:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
th,
|
||||
td {
|
||||
font-size: ${({ fontSize }: StyledTableProps) => fontSize || '14px'};
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
${({ withBorder }: StyledTableProps) =>
|
||||
withBorder &&
|
||||
css`
|
||||
border-bottom: 1px solid ${separationColor};
|
||||
`}
|
||||
${({ alignCenter }: StyledTableProps) =>
|
||||
alignCenter &&
|
||||
css`
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
`}
|
||||
:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const S = {
|
||||
options: styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
flex-direction: row;
|
||||
}
|
||||
`,
|
||||
option: styled.label`
|
||||
margin: 4px 8px;
|
||||
`,
|
||||
row: styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
`,
|
||||
optionRow: styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (${mediaWidths.mobile}) {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
const FilterLine = styled.div`
|
||||
margin-bottom: 24px;
|
||||
`;
|
||||
|
||||
const GlobalFilter = ({
|
||||
preGlobalFilteredRows,
|
||||
globalFilter,
|
||||
setGlobalFilter,
|
||||
export default function Table({
|
||||
columns,
|
||||
data,
|
||||
filterPlaceholder,
|
||||
}: any) => {
|
||||
const count = preGlobalFilteredRows.length;
|
||||
const [value, setValue] = useState(globalFilter);
|
||||
const onChange = useAsyncDebounce(value => {
|
||||
setGlobalFilter(value || undefined);
|
||||
}, 200);
|
||||
|
||||
return (
|
||||
<FilterLine>
|
||||
<Input
|
||||
maxWidth={'300px'}
|
||||
value={value || ''}
|
||||
onChange={e => {
|
||||
setValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
placeholder={`Search ${count} ${filterPlaceholder || ''}`}
|
||||
/>
|
||||
</FilterLine>
|
||||
);
|
||||
};
|
||||
|
||||
type TableColumn = {
|
||||
Header: string | JSX.Element;
|
||||
accessor: string;
|
||||
};
|
||||
|
||||
type TableProps = {
|
||||
tableData: any[];
|
||||
tableColumns: (
|
||||
| TableColumn
|
||||
| {
|
||||
Header: string | JSX.Element;
|
||||
columns: TableColumn[];
|
||||
}
|
||||
)[];
|
||||
withBorder?: boolean;
|
||||
fontSize?: string;
|
||||
filterPlaceholder?: string;
|
||||
notSortable?: boolean;
|
||||
alignCenter?: boolean;
|
||||
defaultHiddenColumns?: string[];
|
||||
onHideToggle?: (hide: boolean, id: string) => void;
|
||||
};
|
||||
|
||||
export const Table: React.FC<TableProps> = ({
|
||||
onHideToggle,
|
||||
defaultHiddenColumns = [],
|
||||
tableData,
|
||||
tableColumns,
|
||||
withBorder,
|
||||
fontSize,
|
||||
filterPlaceholder,
|
||||
notSortable,
|
||||
alignCenter,
|
||||
}) => {
|
||||
fontSize,
|
||||
defaultHiddenColumns,
|
||||
toggleConfiguration,
|
||||
withGlobalSort = false,
|
||||
withSorting = false,
|
||||
}: TableProps) {
|
||||
const [globalFilter, setGlobalFilter] = useState('');
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const data = useMemo(() => tableData, [tableData]);
|
||||
const columns = useMemo(() => tableColumns, [tableColumns]);
|
||||
const hiddenColumns = useMemo(
|
||||
() => defaultHiddenColumns,
|
||||
[defaultHiddenColumns]
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(
|
||||
defaultHiddenColumns || {}
|
||||
);
|
||||
|
||||
const instance = useTable(
|
||||
{
|
||||
autoResetSortBy: false,
|
||||
columns,
|
||||
data,
|
||||
initialState: {
|
||||
hiddenColumns,
|
||||
},
|
||||
} as any,
|
||||
useFilters,
|
||||
useGlobalFilter,
|
||||
useSortBy
|
||||
);
|
||||
|
||||
const {
|
||||
allColumns,
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
rows,
|
||||
prepareRow,
|
||||
state,
|
||||
preGlobalFilteredRows,
|
||||
setGlobalFilter,
|
||||
} = instance as TableInstance & {
|
||||
preGlobalFilteredRows: any;
|
||||
setGlobalFilter: any;
|
||||
const tableConfigs = {
|
||||
data,
|
||||
columns,
|
||||
state: {
|
||||
columnVisibility,
|
||||
globalFilter,
|
||||
sorting,
|
||||
},
|
||||
enableSorting: withSorting,
|
||||
onSortingChange: setSorting,
|
||||
onGlobalFilterChange: setGlobalFilter,
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
};
|
||||
|
||||
const orderedColumns = useMemo(() => {
|
||||
const hidableColumns = allColumns.reduce((p, c) => {
|
||||
if (c.isVisible && (c as any).forceVisible) {
|
||||
return p;
|
||||
}
|
||||
if (withGlobalSort) {
|
||||
tableConfigs.enableSorting = true;
|
||||
tableConfigs.state.globalFilter = globalFilter;
|
||||
tableConfigs.onGlobalFilterChange = setGlobalFilter;
|
||||
}
|
||||
|
||||
return [...p, c];
|
||||
}, [] as ColumnInstance[]);
|
||||
if (withSorting) {
|
||||
tableConfigs.state.sorting = sorting;
|
||||
tableConfigs.onSortingChange = setSorting;
|
||||
}
|
||||
|
||||
const grouped = groupBy(
|
||||
hidableColumns,
|
||||
(c: any) => c?.parent?.Header || ''
|
||||
);
|
||||
|
||||
const final = [];
|
||||
|
||||
for (const key in grouped) {
|
||||
if (Object.prototype.hasOwnProperty.call(grouped, key)) {
|
||||
const group = grouped[key];
|
||||
final.push({ name: key, items: group });
|
||||
}
|
||||
}
|
||||
|
||||
return final;
|
||||
}, [allColumns]);
|
||||
const table = useReactTable(tableConfigs);
|
||||
|
||||
return (
|
||||
<>
|
||||
{filterPlaceholder || onHideToggle ? (
|
||||
<S.row>
|
||||
{filterPlaceholder ? (
|
||||
<GlobalFilter
|
||||
preGlobalFilteredRows={preGlobalFilteredRows}
|
||||
globalFilter={(state as any).globalFilter}
|
||||
setGlobalFilter={setGlobalFilter}
|
||||
filterPlaceholder={filterPlaceholder}
|
||||
/>
|
||||
) : null}
|
||||
{onHideToggle ? (
|
||||
<S.row>
|
||||
{withGlobalSort ? (
|
||||
<DebouncedInput
|
||||
value={globalFilter ?? ''}
|
||||
onChange={value => setGlobalFilter(String(value))}
|
||||
placeholder={filterPlaceholder || ''}
|
||||
count={table.getFilteredRowModel().rows.length}
|
||||
/>
|
||||
) : null}
|
||||
{toggleConfiguration ? (
|
||||
<>
|
||||
<ColorButton onClick={() => setIsOpen(p => !p)}>
|
||||
{isOpen ? <X size={18} /> : <Settings size={18} />}
|
||||
</ColorButton>
|
||||
) : null}
|
||||
</S.row>
|
||||
</>
|
||||
) : null}
|
||||
</S.row>
|
||||
|
||||
{isOpen && toggleConfiguration ? (
|
||||
<ColumnConfigurations
|
||||
table={table}
|
||||
toggleConfiguration={toggleConfiguration}
|
||||
/>
|
||||
) : null}
|
||||
{isOpen && (
|
||||
<S.optionRow>
|
||||
{orderedColumns.map((column, index) => {
|
||||
const { name, items } = column;
|
||||
|
||||
return (
|
||||
<SubCard key={`${name}${index}`} style={{ height: 'auto' }}>
|
||||
<DarkSubTitle fontSize="16px">{name || 'General'}</DarkSubTitle>
|
||||
<S.options>
|
||||
{items.map(item => {
|
||||
const { checked } = item.getToggleHiddenProps();
|
||||
|
||||
return (
|
||||
<S.option key={item.id}>
|
||||
<label>
|
||||
<input
|
||||
onClick={() =>
|
||||
onHideToggle && onHideToggle(checked, item.id)
|
||||
}
|
||||
type={'checkbox'}
|
||||
{...item.getToggleHiddenProps()}
|
||||
/>
|
||||
{item.Header as any}
|
||||
</label>
|
||||
</S.option>
|
||||
);
|
||||
})}
|
||||
</S.options>
|
||||
</SubCard>
|
||||
);
|
||||
})}
|
||||
</S.optionRow>
|
||||
)}
|
||||
<Styles
|
||||
<S.wrapper
|
||||
withBorder={withBorder}
|
||||
fontSize={fontSize}
|
||||
alignCenter={alignCenter}
|
||||
>
|
||||
<table {...getTableProps()} style={{ width: '100%' }}>
|
||||
<table>
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup, index) => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()} key={index}>
|
||||
{headerGroup.headers.map((column: any, index) => (
|
||||
<th
|
||||
{...column.getHeaderProps(
|
||||
notSortable ? undefined : column.getSortByToggleProps()
|
||||
)}
|
||||
key={index}
|
||||
>
|
||||
<span style={{ whiteSpace: 'nowrap' }}>
|
||||
{column.render('Header')}
|
||||
</span>
|
||||
<span>
|
||||
{column.isSorted ? (column.isSortedDesc ? '⬇' : '⬆') : ''}
|
||||
</span>
|
||||
</th>
|
||||
))}
|
||||
{table.getHeaderGroups().map(headerGroup => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map(header => {
|
||||
return (
|
||||
<th
|
||||
key={header.id}
|
||||
colSpan={header.colSpan}
|
||||
style={{ whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
<>
|
||||
<div
|
||||
{...{
|
||||
className: header.column.getCanSort()
|
||||
? 'cursor'
|
||||
: '',
|
||||
onClick: header.column.getToggleSortingHandler(),
|
||||
}}
|
||||
>
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
{{
|
||||
asc: ' ⬆',
|
||||
desc: ' ⬇',
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</th>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{rows.map((row, index) => {
|
||||
prepareRow(row);
|
||||
<tbody>
|
||||
{table.getRowModel().rows.map(row => {
|
||||
return (
|
||||
<tr {...row.getRowProps()} key={index}>
|
||||
{row.cells.map((cell, index) => {
|
||||
<tr key={row.id}>
|
||||
{row.getVisibleCells().map(cell => {
|
||||
return (
|
||||
<td {...cell.getCellProps()} key={index}>
|
||||
{cell.render('Cell')}
|
||||
<td key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
|
@ -315,7 +222,7 @@ export const Table: React.FC<TableProps> = ({
|
|||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</Styles>
|
||||
</S.wrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useGetChainTransactionsQuery } from '../../../graphql/queries/__generat
|
|||
import { DarkSubTitle } from '../../../components/generic/Styled';
|
||||
import { getErrorContent } from '../../../utils/error';
|
||||
import { LoadingCard } from '../../../components/loading/LoadingCard';
|
||||
import { Table } from '../../../components/table';
|
||||
import Table from '../../../components/table';
|
||||
import {
|
||||
getAddressLink,
|
||||
getDateDif,
|
||||
|
@ -33,9 +33,9 @@ export const ChainTransactions = () => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Type',
|
||||
accessor: 'transaction_type',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Type',
|
||||
accessorKey: 'transaction_type',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{row.original.transaction_type === 'Sent' ? (
|
||||
<ArrowUp color={chartColors.red} size={16} />
|
||||
|
@ -46,38 +46,39 @@ export const ChainTransactions = () => {
|
|||
),
|
||||
},
|
||||
{
|
||||
Header: 'Date',
|
||||
accessor: 'created_at',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Date',
|
||||
accessorKey: 'created_at',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{`${getDateDif(row.original.created_at)} ago`}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Sats',
|
||||
accessor: 'tokens',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sats',
|
||||
accessorKey: 'tokens',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.tokens} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Fee',
|
||||
accessor: 'fee',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Fee',
|
||||
accessorKey: 'fee',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.fee} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{ Header: 'Confirmations', accessor: 'confirmation_count' },
|
||||
{ Header: 'Confirmation Block', accessor: 'confirmation_height' },
|
||||
{ header: 'Confirmations', accessorKey: 'confirmation_count' },
|
||||
{ header: 'Confirmation Block', accessorKey: 'confirmation_height' },
|
||||
{
|
||||
Header: 'Output Addresses',
|
||||
accessor: 'output_addresses',
|
||||
Cell: ({ row }: any) =>
|
||||
header: 'Output Addresses',
|
||||
accessorKey: 'output_addresses',
|
||||
enableSorting: false,
|
||||
cell: ({ row }: any) =>
|
||||
row.original.output_addresses.map((a: string) => (
|
||||
<div key={a} style={{ whiteSpace: 'nowrap' }}>
|
||||
{getAddressLink(a)}
|
||||
|
@ -85,9 +86,10 @@ export const ChainTransactions = () => {
|
|||
)),
|
||||
},
|
||||
{
|
||||
Header: 'Transaction',
|
||||
accessor: 'id',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Transaction',
|
||||
accessorKey: 'id',
|
||||
enableSorting: false,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getTransactionLink(row.original.id)}
|
||||
</div>
|
||||
|
@ -106,6 +108,11 @@ export const ChainTransactions = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Table withBorder={true} tableColumns={columns} tableData={tableData} />
|
||||
<Table
|
||||
withBorder={true}
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withSorting={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useGetUtxosQuery } from '../../../graphql/queries/__generated__/getUtxo
|
|||
import { DarkSubTitle } from '../../../components/generic/Styled';
|
||||
import { getErrorContent } from '../../../utils/error';
|
||||
import { LoadingCard } from '../../../components/loading/LoadingCard';
|
||||
import { Table } from '../../../components/table';
|
||||
import Table from '../../../components/table';
|
||||
import { getAddressLink } from '../../../components/generic/helpers';
|
||||
import { Price } from '../../../components/price/Price';
|
||||
import { blockToTime } from '../../../utils/helpers';
|
||||
|
@ -29,43 +29,46 @@ export const ChainUtxos = () => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: '',
|
||||
accessor: 'index',
|
||||
header: '',
|
||||
accessorKey: 'index',
|
||||
},
|
||||
{
|
||||
Header: 'Sats',
|
||||
accessor: 'tokens',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sats',
|
||||
accessorKey: 'tokens',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.tokens} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Confirmations',
|
||||
header: 'Confirmations',
|
||||
columns: [
|
||||
{ Header: 'Blocks', accessor: 'confirmation_count' },
|
||||
{ header: 'Blocks', accessorKey: 'confirmation_count' },
|
||||
{
|
||||
Header: 'Since',
|
||||
accessor: 'time',
|
||||
header: 'Since',
|
||||
accessorKey: 'time',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Address',
|
||||
header: 'Address',
|
||||
enableSorting: false,
|
||||
columns: [
|
||||
{
|
||||
Header: 'Link',
|
||||
accessor: 'output_addresses',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Link',
|
||||
enableSorting: false,
|
||||
accessorKey: 'output_addresses',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getAddressLink(row.original.address)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Format',
|
||||
accessor: 'address_format',
|
||||
header: 'Format',
|
||||
enableSorting: false,
|
||||
accessorKey: 'address_format',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -82,6 +85,11 @@ export const ChainUtxos = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Table withBorder={true} tableColumns={columns} tableData={tableData} />
|
||||
<Table
|
||||
withBorder={true}
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withSorting={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ import { LoadingCard } from '../../../components/loading/LoadingCard';
|
|||
import { CloseChannel } from '../../../components/modal/closeChannel/CloseChannel';
|
||||
import Modal from '../../../components/modal/ReactModal';
|
||||
import { Price } from '../../../components/price/Price';
|
||||
import { Table } from '../../../components/table';
|
||||
import Table from '../../../components/table';
|
||||
import { useGetChannelsQuery } from '../../../graphql/queries/__generated__/getChannels.generated';
|
||||
import { useLocalStorage } from '../../../hooks/UseLocalStorage';
|
||||
import { chartColors } from '../../../styles/Themes';
|
||||
|
@ -29,6 +29,7 @@ import { getErrorContent } from '../../../utils/error';
|
|||
import { blockToTime, formatSeconds, getPercent } from '../../../utils/helpers';
|
||||
import { ChannelDetails } from './ChannelDetails';
|
||||
import { defaultHiddenColumns } from './helpers';
|
||||
import { VisibilityState } from '@tanstack/react-table';
|
||||
|
||||
const S = {
|
||||
link: styled.span`
|
||||
|
@ -276,47 +277,52 @@ export const ChannelTable = () => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Status',
|
||||
header: 'Status',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Active',
|
||||
accessor: 'channelActiveLogo',
|
||||
header: 'Active',
|
||||
accessorKey: 'channelActiveLogo',
|
||||
sortType: numberStringSorting('channelActive'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Private',
|
||||
accessor: 'channelPrivateLogo',
|
||||
header: 'Private',
|
||||
accessorKey: 'channelPrivateLogo',
|
||||
sortType: numberStringSorting('channelPrivate'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Initiated',
|
||||
accessor: 'channelOpenerLogo',
|
||||
header: 'Initiated',
|
||||
accessorKey: 'channelOpenerLogo',
|
||||
sortType: numberStringSorting('channelOpener'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Actions',
|
||||
header: 'Actions',
|
||||
columns: [
|
||||
{
|
||||
Header: <Edit size={14} />,
|
||||
accessor: 'editAction',
|
||||
disableSortBy: true,
|
||||
header: <Edit size={14} />,
|
||||
accessorKey: 'editAction',
|
||||
enableSorting: false,
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: <X size={14} />,
|
||||
accessor: 'closeAction',
|
||||
disableSortBy: true,
|
||||
header: <X size={14} />,
|
||||
accessorKey: 'closeAction',
|
||||
enableSorting: false,
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Info',
|
||||
header: 'Info',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Peer',
|
||||
accessor: 'undercaseAlias',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Peer',
|
||||
accessorKey: 'undercaseAlias',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getNodeLink(
|
||||
row.original.partner_public_key,
|
||||
|
@ -326,86 +332,88 @@ export const ChannelTable = () => {
|
|||
),
|
||||
},
|
||||
{
|
||||
Header: 'Channel Id',
|
||||
accessor: 'id',
|
||||
forceVisible: true,
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Channel Id',
|
||||
accessorKey: 'id',
|
||||
enableHiding: false,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getChannelLink(row.original.id)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Capacity',
|
||||
accessor: 'capacity',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Capacity',
|
||||
accessorKey: 'capacity',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.capacity} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{ Header: 'Block Age', accessor: 'channel_age' },
|
||||
{ header: 'Block Age', accessorKey: 'channel_age' },
|
||||
{
|
||||
Header: 'Channel Age',
|
||||
accessor: 'channel_age_duplicate',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Channel Age',
|
||||
accessorKey: 'channel_age_duplicate',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{blockToTime(row.original.channel_age)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Past States',
|
||||
accessor: 'past_states',
|
||||
header: 'Past States',
|
||||
accessorKey: 'past_states',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Balance',
|
||||
header: 'Balance',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Local',
|
||||
accessor: 'local_balance',
|
||||
Cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.local_balance} />
|
||||
</div>
|
||||
),
|
||||
header: 'Local',
|
||||
accessorKey: 'local_balance',
|
||||
cell: ({ row }: any) => {
|
||||
return (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.local_balance} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
Header: 'Remote',
|
||||
accessor: 'remote_balance',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Remote',
|
||||
accessorKey: 'remote_balance',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.remote_balance} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Percent',
|
||||
accessor: 'balancePercentText',
|
||||
header: 'Percent',
|
||||
accessorKey: 'balancePercentText',
|
||||
sortType: numberStringSorting('balancePercent'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Pending HTLC',
|
||||
header: 'Pending HTLC',
|
||||
columns: [
|
||||
{ Header: 'Total HTLC', accessor: 'pending_total_amount' },
|
||||
{ Header: 'Total Sats', accessor: 'pending_total_tokens' },
|
||||
{ Header: 'Incoming HTLC', accessor: 'pending_incoming_amount' },
|
||||
{ Header: 'Incoming Sats', accessor: 'pending_incoming_tokens' },
|
||||
{ Header: 'Outgoing HTLC', accessor: 'pending_outgoing_amount' },
|
||||
{ Header: 'Outgoing Sats', accessor: 'pending_outgoing_tokens' },
|
||||
{ header: 'Total HTLC', accessorKey: 'pending_total_amount' },
|
||||
{ header: 'Total Sats', accessorKey: 'pending_total_tokens' },
|
||||
{ header: 'Incoming HTLC', accessorKey: 'pending_incoming_amount' },
|
||||
{ header: 'Incoming Sats', accessorKey: 'pending_incoming_tokens' },
|
||||
{ header: 'Outgoing HTLC', accessorKey: 'pending_outgoing_amount' },
|
||||
{ header: 'Outgoing Sats', accessorKey: 'pending_outgoing_tokens' },
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Monitoring',
|
||||
header: 'Monitoring',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Online',
|
||||
accessor: 'time_online',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Online',
|
||||
accessorKey: 'time_online',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{formatSeconds(
|
||||
Math.round((row.original.time_online || 0) / 1000)
|
||||
|
@ -414,9 +422,9 @@ export const ChannelTable = () => {
|
|||
),
|
||||
},
|
||||
{
|
||||
Header: 'Offline',
|
||||
accessor: 'time_offline',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Offline',
|
||||
accessorKey: 'time_offline',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{formatSeconds(
|
||||
Math.round((row.original.time_offline || 0) / 1000)
|
||||
|
@ -425,89 +433,97 @@ export const ChannelTable = () => {
|
|||
),
|
||||
},
|
||||
{
|
||||
Header: 'Percent',
|
||||
accessor: 'percentOnlineText',
|
||||
header: 'Percent',
|
||||
accessorKey: 'percentOnlineText',
|
||||
sortType: numberStringSorting('percentOnline'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Activity',
|
||||
header: 'Activity',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Sent',
|
||||
accessor: 'sent',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Sent',
|
||||
accessorKey: 'sent',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.sent} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Received',
|
||||
accessor: 'received',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Received',
|
||||
accessorKey: 'received',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.received} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Percent',
|
||||
accessor: 'activityPercentText',
|
||||
header: 'Percent',
|
||||
accessorKey: 'activityPercentText',
|
||||
sortType: numberStringSorting('activityPercent'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'My Fees',
|
||||
header: 'My Fees',
|
||||
columns: [
|
||||
{ Header: 'Rate', accessor: 'myRate' },
|
||||
{ Header: 'Base', accessor: 'myBase' },
|
||||
{ header: 'Rate', accessorKey: 'myRate' },
|
||||
{ header: 'Base', accessorKey: 'myBase' },
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Partner Fees',
|
||||
header: 'Partner Fees',
|
||||
columns: [
|
||||
{ Header: 'Rate', accessor: 'partnerRate' },
|
||||
{ Header: 'Base', accessor: 'partnerBase' },
|
||||
{ header: 'Rate', accessorKey: 'partnerRate' },
|
||||
{ header: 'Base', accessorKey: 'partnerBase' },
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'My HTLC',
|
||||
header: 'My HTLC',
|
||||
columns: [
|
||||
{ Header: 'Max', accessor: 'myMaxHtlc' },
|
||||
{ Header: 'Min', accessor: 'myMinHtlc' },
|
||||
{ header: 'Max', accessorKey: 'myMaxHtlc' },
|
||||
{ header: 'Min', accessorKey: 'myMinHtlc' },
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Partner HTLC',
|
||||
header: 'Partner HTLC',
|
||||
columns: [
|
||||
{ Header: 'Max', accessor: 'partnerMaxHtlc' },
|
||||
{ Header: 'Min', accessor: 'partnerMinHtlc' },
|
||||
{ header: 'Max', accessorKey: 'partnerMaxHtlc' },
|
||||
{ header: 'Min', accessorKey: 'partnerMinHtlc' },
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Bars',
|
||||
header: 'Bars',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Balance',
|
||||
accessor: 'balanceBars',
|
||||
header: 'Balance',
|
||||
accessorKey: 'balanceBars',
|
||||
sortType: numberStringSorting('balancePercent'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Proportional',
|
||||
accessor: 'proportionalBars',
|
||||
header: 'Proportional',
|
||||
accessorKey: 'proportionalBars',
|
||||
sortType: numberStringSorting('balancePercent'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Activity',
|
||||
accessor: 'activityBars',
|
||||
header: 'Activity',
|
||||
accessorKey: 'activityBars',
|
||||
sortType: numberStringSorting('activityPercent'),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{ Header: 'Details', accessor: 'viewAction' },
|
||||
{
|
||||
header: 'Details',
|
||||
accessorKey: 'viewAction',
|
||||
enableSorting: false,
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
[numberStringSorting]
|
||||
);
|
||||
|
@ -521,6 +537,14 @@ export const ChannelTable = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const hiddenColumnState: VisibilityState = useMemo(() => {
|
||||
const defaultColumns: VisibilityState = {};
|
||||
hiddenColumns.forEach(c => {
|
||||
defaultColumns[c] = false;
|
||||
});
|
||||
return defaultColumns;
|
||||
}, [hiddenColumns]);
|
||||
|
||||
if (loading) {
|
||||
return <LoadingCard noCard={true} />;
|
||||
}
|
||||
|
@ -552,10 +576,12 @@ export const ChannelTable = () => {
|
|||
<>
|
||||
<Table
|
||||
withBorder={true}
|
||||
tableColumns={columns}
|
||||
tableData={tableData}
|
||||
onHideToggle={handleToggle}
|
||||
defaultHiddenColumns={hiddenColumns}
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withGlobalSort={true}
|
||||
withSorting={true}
|
||||
toggleConfiguration={handleToggle}
|
||||
defaultHiddenColumns={hiddenColumnState}
|
||||
filterPlaceholder="channels"
|
||||
/>
|
||||
<Modal isOpen={!!channel} closeCallback={() => setChannel(null)}>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useGetClosedChannelsQuery } from '../../../graphql/queries/__generated_
|
|||
import { DarkSubTitle } from '../../../components/generic/Styled';
|
||||
import { getErrorContent } from '../../../utils/error';
|
||||
import { LoadingCard } from '../../../components/loading/LoadingCard';
|
||||
import { Table } from '../../../components/table';
|
||||
import Table from '../../../components/table';
|
||||
import { Price } from '../../../components/price/Price';
|
||||
import { blockToTime } from '../../../utils/helpers';
|
||||
import { orderBy } from 'lodash';
|
||||
|
@ -56,49 +56,54 @@ export const ClosedChannels = () => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Peer',
|
||||
accessor: 'alias',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Peer',
|
||||
accessorKey: 'alias',
|
||||
enableSorting: true,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{getNodeLink(row.original.partner_public_key, row.original.alias)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Closed Since',
|
||||
accessor: 'closed_for_blocks',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Closed Since',
|
||||
accessorKey: 'closed_for_blocks',
|
||||
enableSorting: true,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{blockToTime(row.original.closed_for_blocks)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Channel Age',
|
||||
accessor: 'channel_age',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Channel Age',
|
||||
accessorKey: 'channel_age',
|
||||
enableSorting: true,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{blockToTime(row.original.channel_age)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Capacity',
|
||||
accessor: 'capacity',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Capacity',
|
||||
accessorKey: 'capacity',
|
||||
enableSorting: true,
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.capacity} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Close Type',
|
||||
accessor: 'closeType',
|
||||
header: 'Close Type',
|
||||
accessorKey: 'closeType',
|
||||
},
|
||||
{
|
||||
Header: 'Transaction Id',
|
||||
accessor: 'transaction_id',
|
||||
Cell: ({ row }: any) => getTransactionLink(row.original.transaction_id),
|
||||
header: 'Transaction Id',
|
||||
accessorKey: 'transaction_id',
|
||||
enableSorting: true,
|
||||
cell: ({ row }: any) => getTransactionLink(row.original.transaction_id),
|
||||
},
|
||||
],
|
||||
[]
|
||||
|
@ -114,9 +119,11 @@ export const ClosedChannels = () => {
|
|||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withBorder={true}
|
||||
tableColumns={columns}
|
||||
tableData={tableData}
|
||||
withGlobalSort={true}
|
||||
withSorting={true}
|
||||
filterPlaceholder="channels"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
getNodeLink,
|
||||
getTransactionLink,
|
||||
} from '../../../components/generic/helpers';
|
||||
import TableV2 from '../../../components/table-v2';
|
||||
import Table from '../../../components/table';
|
||||
import { Price } from '../../../components/price/Price';
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { PendingChannel } from '../../../graphql/types';
|
||||
|
@ -180,10 +180,12 @@ export const PendingChannels = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<TableV2
|
||||
<Table
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withBorder={true}
|
||||
withGlobalSort={true}
|
||||
withSorting={true}
|
||||
filterPlaceholder="channels"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Table } from '../../../../components/table';
|
||||
import Table from '../../../../components/table';
|
||||
import { useBitcoinFees } from '../../../../hooks/UseBitcoinFees';
|
||||
import styled from 'styled-components';
|
||||
|
||||
|
@ -17,10 +17,10 @@ export const MempoolWidget = () => {
|
|||
}
|
||||
|
||||
const columns = [
|
||||
{ Header: 'Fastest', accessor: 'fast' },
|
||||
{ Header: 'Half Hour', accessor: 'halfHour' },
|
||||
{ Header: 'Hour', accessor: 'hour' },
|
||||
{ Header: 'Minimum', accessor: 'minimum' },
|
||||
{ header: 'Fastest', accessorKey: 'fast' },
|
||||
{ header: 'Half Hour', accessorKey: 'halfHour' },
|
||||
{ header: 'Hour', accessorKey: 'hour' },
|
||||
{ header: 'Minimum', accessorKey: 'minimum' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
|
@ -34,7 +34,7 @@ export const MempoolWidget = () => {
|
|||
|
||||
return (
|
||||
<S.wrapper>
|
||||
<Table alignCenter={true} tableColumns={columns} tableData={data} />
|
||||
<Table alignCenter={true} columns={columns} data={data} />
|
||||
</S.wrapper>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getDateDif } from '../../../../components/generic/helpers';
|
||||
import { Price } from '../../../../components/price/Price';
|
||||
import { Table } from '../../../../components/table';
|
||||
import Table from '../../../../components/table';
|
||||
import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/getForwards.generated';
|
||||
import { ChannelAlias } from '../../../../views/home/reports/forwardReport/ChannelAlias';
|
||||
import styled from 'styled-components';
|
||||
|
@ -32,11 +32,31 @@ export const ForwardListWidget = () => {
|
|||
const forwards = data?.getForwards || [];
|
||||
|
||||
const columns = [
|
||||
{ Header: 'Date', accessor: 'date' },
|
||||
{ Header: 'Amount', accessor: 'amount' },
|
||||
{ Header: 'Fee', accessor: 'fee' },
|
||||
{ Header: 'Incoming', accessor: 'incoming' },
|
||||
{ Header: 'Outgoing', accessor: 'outgoing' },
|
||||
{
|
||||
header: 'Date',
|
||||
accessorKey: 'date',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Amount',
|
||||
accessorKey: 'amount',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Fee',
|
||||
accessorKey: 'fee',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Incoming',
|
||||
accessorKey: 'incoming',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Outgoing',
|
||||
accessorKey: 'outgoing',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = forwards.reduce((p, f) => {
|
||||
|
@ -65,7 +85,7 @@ export const ForwardListWidget = () => {
|
|||
<S.wrapper>
|
||||
<S.title>Forwards</S.title>
|
||||
<S.table>
|
||||
<Table tableColumns={columns} tableData={tableData} />
|
||||
<Table columns={columns} data={tableData} withSorting={true} />
|
||||
</S.table>
|
||||
</S.wrapper>
|
||||
);
|
||||
|
|
|
@ -3,7 +3,6 @@ import { toast } from 'react-toastify';
|
|||
import { ProgressBar } from '../../components/generic/CardGeneric';
|
||||
import { SingleLine } from '../../components/generic/Styled';
|
||||
import { getPrice } from '../../components/price/Price';
|
||||
import { Table } from '../../components/table';
|
||||
import { useConfigState } from '../../context/ConfigContext';
|
||||
import { usePriceState } from '../../context/PriceContext';
|
||||
import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated';
|
||||
|
@ -11,6 +10,7 @@ import { Forward } from '../../graphql/types';
|
|||
import { getErrorContent } from '../../utils/error';
|
||||
import { ChannelAlias } from '../home/reports/forwardReport/ChannelAlias';
|
||||
import { sortByNode } from './helpers';
|
||||
import Table from '../../components/table';
|
||||
|
||||
const getBar = (top: number, bottom: number) => {
|
||||
const percent = (top / bottom) * 100;
|
||||
|
@ -52,12 +52,36 @@ export const ForwardTable: FC<{ days: number; order: string }> = ({
|
|||
);
|
||||
|
||||
const columns = [
|
||||
{ Header: 'Alias', accessor: 'alias' },
|
||||
{ Header: 'Channel', accessor: 'channel' },
|
||||
{ Header: 'Incoming', accessor: 'incoming' },
|
||||
{ Header: 'Outgoing', accessor: 'outgoing' },
|
||||
{ Header: 'Incoming', accessor: 'incomingBar' },
|
||||
{ Header: 'Outgoing', accessor: 'outgoingBar' },
|
||||
{
|
||||
header: 'Alias',
|
||||
accessorKey: 'alias',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Channel',
|
||||
accessorKey: 'channel',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Incoming',
|
||||
accessorKey: 'incoming',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Outgoing',
|
||||
accessorKey: 'outgoing',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Incoming',
|
||||
accessorKey: 'incomingBar',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Outgoing',
|
||||
accessorKey: 'outgoingBar',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = final.map(f => ({
|
||||
|
@ -69,5 +93,5 @@ export const ForwardTable: FC<{ days: number; order: string }> = ({
|
|||
outgoingBar: <SingleBar value={getBar(f.outgoing, maxOut)} height={16} />,
|
||||
}));
|
||||
|
||||
return <Table tableData={tableData} tableColumns={columns} />;
|
||||
return <Table data={tableData} columns={columns} withSorting={true} />;
|
||||
};
|
||||
|
|
|
@ -4,10 +4,10 @@ import { getDateDif } from '../../components/generic/helpers';
|
|||
import { DarkSubTitle } from '../../components/generic/Styled';
|
||||
import { LoadingCard } from '../../components/loading/LoadingCard';
|
||||
import { Price } from '../../components/price/Price';
|
||||
import { Table } from '../../components/table';
|
||||
import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated';
|
||||
import { getErrorContent } from '../../utils/error';
|
||||
import { ChannelAlias } from '../home/reports/forwardReport/ChannelAlias';
|
||||
import Table from '../../components/table';
|
||||
|
||||
type ForwardProps = {
|
||||
days: number;
|
||||
|
@ -34,30 +34,30 @@ export const ForwardsList: FC<ForwardProps> = ({ days }) => {
|
|||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Date',
|
||||
accessor: 'created_at',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Date',
|
||||
accessorKey: 'created_at',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
{`${getDateDif(row.original.created_at)} ago`}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Sats',
|
||||
header: 'Sats',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Forwarded',
|
||||
accessor: 'tokens',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Forwarded',
|
||||
accessorKey: 'tokens',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.tokens} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: 'Earned',
|
||||
accessor: 'fee',
|
||||
Cell: ({ row }: any) => (
|
||||
header: 'Earned',
|
||||
accessorKey: 'fee',
|
||||
cell: ({ row }: any) => (
|
||||
<div style={{ whiteSpace: 'nowrap' }}>
|
||||
<Price amount={row.original.fee} />
|
||||
</div>
|
||||
|
@ -66,28 +66,32 @@ export const ForwardsList: FC<ForwardProps> = ({ days }) => {
|
|||
],
|
||||
},
|
||||
{
|
||||
Header: 'Peer',
|
||||
header: 'Peer',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Incoming',
|
||||
accessor: 'incoming_name',
|
||||
header: 'Incoming',
|
||||
accessorKey: 'incoming_name',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Outgoing',
|
||||
accessor: 'outgoing_name',
|
||||
header: 'Outgoing',
|
||||
accessorKey: 'outgoing_name',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Channel',
|
||||
header: 'Channel',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Incoming',
|
||||
accessor: 'incoming_channel',
|
||||
header: 'Incoming',
|
||||
accessorKey: 'incoming_channel',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
Header: 'Outgoing',
|
||||
accessor: 'outgoing_channel',
|
||||
header: 'Outgoing',
|
||||
accessorKeyKey: 'outgoing_channel',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -104,6 +108,11 @@ export const ForwardsList: FC<ForwardProps> = ({ days }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Table withBorder={true} tableColumns={columns} tableData={tableData} />
|
||||
<Table
|
||||
withBorder={true}
|
||||
columns={columns}
|
||||
data={tableData}
|
||||
withSorting={true}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { FC } from 'react';
|
||||
import { Table } from '../../../../components/table';
|
||||
import { ChannelAlias } from './ChannelAlias';
|
||||
import Table from '../../../../components/table';
|
||||
|
||||
export type RouteType = {
|
||||
route: string;
|
||||
|
@ -53,9 +53,21 @@ export const RouteTable: FC<RouteTableProps> = ({ order, forwardArray }) => {
|
|||
};
|
||||
|
||||
const columns = [
|
||||
{ Header: 'In', accessor: 'aliasIn' },
|
||||
{ Header: 'Out', accessor: 'aliasOut' },
|
||||
{ Header: getTitle(), accessor: getAccesor() },
|
||||
{
|
||||
header: 'In',
|
||||
accessorKey: 'aliasIn',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Out',
|
||||
accessorKey: 'aliasOut',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: getTitle(),
|
||||
accessorKey: getAccesor(),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = forwardArray.map(f => ({
|
||||
|
@ -64,7 +76,7 @@ export const RouteTable: FC<RouteTableProps> = ({ order, forwardArray }) => {
|
|||
aliasOut: <ChannelAlias id={f.outgoing_channel} />,
|
||||
}));
|
||||
|
||||
return <Table tableData={tableData} tableColumns={columns} />;
|
||||
return <Table data={tableData} columns={columns} withSorting={true} />;
|
||||
};
|
||||
|
||||
export const ChannelTable: FC<ChannelTableProps> = ({
|
||||
|
@ -94,9 +106,21 @@ export const ChannelTable: FC<ChannelTableProps> = ({
|
|||
};
|
||||
|
||||
const columns = [
|
||||
{ Header: 'Alias', accessor: 'alias' },
|
||||
{ Header: 'Id', accessor: 'name' },
|
||||
{ Header: getTitle(), accessor: getAccesor() },
|
||||
{
|
||||
header: 'Alias',
|
||||
accessorKey: 'alias',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Id',
|
||||
accessorKey: 'name',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: getTitle(),
|
||||
accessorKey: getAccesor(),
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = forwardArray.map(f => ({
|
||||
|
@ -104,5 +128,5 @@ export const ChannelTable: FC<ChannelTableProps> = ({
|
|||
alias: <ChannelAlias id={f.channelId} />,
|
||||
}));
|
||||
|
||||
return <Table tableData={tableData} tableColumns={columns} />;
|
||||
return <Table data={tableData} columns={columns} withSorting={true} />;
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
CardWithTitle,
|
||||
SubTitle,
|
||||
} from '../../../../components/generic/Styled';
|
||||
import { Table } from '../../../../components/table';
|
||||
import Table from '../../../../components/table';
|
||||
import { useBitcoinFees } from '../../../../hooks/UseBitcoinFees';
|
||||
|
||||
export const MempoolReport = () => {
|
||||
|
@ -14,10 +14,26 @@ export const MempoolReport = () => {
|
|||
}
|
||||
|
||||
const columns = [
|
||||
{ Header: 'Fastest', accessor: 'fast' },
|
||||
{ Header: 'Half Hour', accessor: 'halfHour' },
|
||||
{ Header: 'Hour', accessor: 'hour' },
|
||||
{ Header: 'Minimum', accessor: 'minimum' },
|
||||
{
|
||||
header: 'Fastest',
|
||||
accessorKey: 'fast',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Half Hour',
|
||||
accessorKey: 'halfHour',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Hour',
|
||||
accessorKey: 'hour',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
{
|
||||
header: 'Minimum',
|
||||
accessorKey: 'minimum',
|
||||
cell: ({ cell }: any) => cell.renderValue(),
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
|
@ -33,7 +49,7 @@ export const MempoolReport = () => {
|
|||
<CardWithTitle>
|
||||
<SubTitle>Mempool Fees</SubTitle>
|
||||
<Card>
|
||||
<Table alignCenter={true} tableColumns={columns} tableData={data} />
|
||||
<Table alignCenter={true} columns={columns} data={data} />
|
||||
</Card>
|
||||
</CardWithTitle>
|
||||
);
|
||||
|
|
Loading…
Add table
Reference in a new issue