diff --git a/react/src/App.js b/react/src/App.js index 52ae7157c..0cfab419e 100644 --- a/react/src/App.js +++ b/react/src/App.js @@ -17,9 +17,8 @@ import {Epoch} from "./Epoch"; import {LegacyDealDetail} from "./LegacyDealDetail" import {SettingsPage} from "./Settings"; import {Banner} from "./Banner"; -import {PieceDirectoryDetail, PieceDirectoryPage} from "./PieceDirectory"; import {ProposalLogsPage} from "./ProposalLogs"; -import {InspectPage, InspectPiecePage} from "./Inspect"; +import {PieceDoctorPage, InspectPiecePage, LIDPage} from "./LID"; import {RetrievalLogsPage} from "./RetrievalLogs"; import {RetrievalLogDetail} from "./RetrievalLogDetail"; @@ -46,6 +45,7 @@ function App(props) { } /> } /> } /> + } /> } /> } /> } /> @@ -53,13 +53,12 @@ function App(props) { } /> } /> } /> - } /> } /> } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> } /> diff --git a/react/src/CumulativeBarChart.js b/react/src/CumulativeBarChart.js index 5efe5482d..abdbf827a 100644 --- a/react/src/CumulativeBarChart.js +++ b/react/src/CumulativeBarChart.js @@ -1,5 +1,5 @@ /* global BigInt */ -import {humanFIL, humanFileSize} from "./util"; +import {addCommas, humanFIL, humanFileSize, isInteger} from "./util"; import React from "react"; import './CumulativeBarChart.css' @@ -72,7 +72,11 @@ function amountToString(unit, amount) { case 'attoFIL': return humanFIL(amount) default: - return amount.toString() + const amtStr = amount.toString() + if (isInteger(amtStr)) { + return addCommas(amtStr) + } + return amtStr } } diff --git a/react/src/DealDetail.js b/react/src/DealDetail.js index 5e182ccc8..913bfe7a6 100644 --- a/react/src/DealDetail.js +++ b/react/src/DealDetail.js @@ -146,7 +146,7 @@ export function DealDetail(props) { Deal Data Root CID - {deal.DealDataRoot} + {deal.DealDataRoot} Verified @@ -162,7 +162,7 @@ export function DealDetail(props) { Piece CID - {deal.PieceCid} + {deal.PieceCid} Piece Size diff --git a/react/src/DealTransfers.js b/react/src/DealTransfers.js index 178aaf53e..061f45684 100644 --- a/react/src/DealTransfers.js +++ b/react/src/DealTransfers.js @@ -5,7 +5,6 @@ import {TransfersQuery, TransferStatsQuery} from "./gql"; import moment from "moment" import {PageContainer} from "./Components"; import {Link} from "react-router-dom"; -import {toFixed} from "./util"; import arrowLeftRightImg from './bootstrap-icons/icons/arrow-left-right.svg' import './DealTransfers.css' diff --git a/react/src/LID.css b/react/src/LID.css new file mode 100644 index 000000000..165b0920b --- /dev/null +++ b/react/src/LID.css @@ -0,0 +1,45 @@ +.block-stats th { + text-align: left; +} + +.block-stats td, .block-stats th { + padding: 0.5em 1em; +} + +.lid-graphs { + margin-top: 2em; + width: 100%; +} + +.lid-graphs td { + vertical-align: top; +} + +.storage-chart { + padding: 1em; +} + +.storage-chart .indexed, .storage-chart .unsealed, .storage-chart .active { + background-color: rgb(44, 123, 229); +} + +.storage-chart .flagged { + background-color: rgb(166, 197, 247); +} + +.storage-chart .sealed, .storage-chart .inactive { + background-color: #b3b3b3; +} + +.storage-fields td { + padding: 0.5em 1em; + font-weight: normal; +} + +.sectors-list-link p, .flagged-pieces-link p { + padding: 1em; +} + +.sectors-list-link a, .flagged-pieces-link a { + margin-left: 1em; +} \ No newline at end of file diff --git a/react/src/Inspect.js b/react/src/LID.js similarity index 70% rename from react/src/Inspect.js rename to react/src/LID.js index 09d0844d2..868831f6d 100644 --- a/react/src/Inspect.js +++ b/react/src/LID.js @@ -1,3 +1,4 @@ +/* global BigInt */ import {useMutation, useQuery} from "@apollo/react-hooks"; import { FlaggedPiecesQuery, PieceBuildIndexMutation, @@ -10,30 +11,284 @@ import {PageContainer, ShortDealLink} from "./Components"; import {Link, useNavigate, useParams} from "react-router-dom"; import {dateFormat} from "./util-date"; import xImg from './bootstrap-icons/icons/x-lg.svg' -import inspectImg from './bootstrap-icons/icons/wrench.svg' +import lidImg from './bootstrap-icons/icons/wrench.svg' +//import repairImg from './bootstrap-icons/icons/wrench-white.svg' +import './LID.css' import './Inspect.css' import {Pagination} from "./Pagination"; import {Info, InfoListItem} from "./Info"; +import {CumulativeBarChart, CumulativeBarLabels} from "./CumulativeBarChart"; +import {addCommas, humanFileSize} from "./util"; -var inspectBasePath = '/inspect' +var lidBasePath = '/lid' -export function InspectMenuItem(props) { +export function LIDMenuItem(props) { return ( - - -

Inspect

+ + +

Local Index Directory

) } -// Main page with flagged pieces -export function InspectPage(props) { - return - +// Landing page for LID +export function LIDPage(props) { + return + + +} + +function LIDContent() { + return
+ + + + + + + + +
+ + + + + +
+
+} + +function BlockStatsSection() { + return
+

Block Stats

+ + + + + + + + + + + + +
Total blocks:{addCommas(32129310123)}
Avg Block size:{humanFileSize(256*1024)}
+
+} + +function mockDealData() { + return { + data: { + storage: { + Indexed: BigInt(12345432343223), + Flagged: BigInt(1234512345423), + Sealed: BigInt(1634512345423), + } + } + } +} + +function DealDataSection() { + // const {loading, error, data} = useQuery(StorageQuery, { pollInterval: 10000 }) + const {loading, error, data} = mockDealData() + + if (loading) { + return
Loading...
+ } + if (error) { + return
Error: {error.message}
+ } + + var storage = data.storage + + const bars = [{ + name: 'Indexed', + className: 'indexed', + amount: storage.Indexed, + description: '' + }, { + name: 'Flagged', + className: 'flagged', + amount: storage.Flagged, + description: '' + }, { + name: 'Sealed Only', + className: 'sealed', + amount: storage.Sealed, + description: '' + }] + + return
+

Deal Data

+ +
+ + +
+
+} + +function mockPiecesData() { + return { + data: { + storage: { + Indexed: BigInt(2132), + Flagged: BigInt(123), + Sealed: BigInt(213), + } + } + } +} + +function PiecesSection() { + // const {loading, error, data} = useQuery(StorageQuery, { pollInterval: 10000 }) + const {loading, error, data} = mockPiecesData() + + if (loading) { + return
Loading...
+ } + if (error) { + return
Error: {error.message}
+ } + + var storage = data.storage + + const bars = [{ + name: 'Indexed', + className: 'indexed', + amount: storage.Indexed, + description: '' + }, { + name: 'Flagged', + className: 'flagged', + amount: storage.Flagged, + description: '' + }, { + name: 'Sealed Only', + className: 'sealed', + amount: storage.Sealed, + description: '' + }] + + return
+

Pieces

+ +
+ + +
+ +
+

Flagged Pieces

+

+ {addCommas(storage.Flagged)} Flagged Pieces + View Flagged Pieces +

+
+
+} + +function mockSectorUnsealedData() { + return { + data: { + sectors: { + Unsealed: BigInt(1334), + Sealed: BigInt(321), + } + } + } +} + +function SectorUnsealedSection() { + // const {loading, error, data} = useQuery(StorageQuery, { pollInterval: 10000 }) + const {loading, error, data} = mockSectorUnsealedData() + + if (loading) { + return
Loading...
+ } + if (error) { + return
Error: {error.message}
+ } + + var sectors = data.sectors + + const bars = [{ + name: 'Unsealed Copy', + className: 'unsealed', + amount: sectors.Unsealed, + description: '' + }, { + name: 'Sealed Only', + className: 'sealed', + amount: sectors.Sealed, + description: '' + }] + + return
+

Sector Unsealed Copies

+ +
+ + +
+
+} + +function mockSectorProvingState() { + return { + data: { + sectors: { + Active: BigInt(1274), + Inactive: BigInt(381), + } + } + } +} + +function SectorProvingState() { + // const {loading, error, data} = useQuery(StorageQuery, { pollInterval: 10000 }) + const {loading, error, data} = mockSectorProvingState() + + if (loading) { + return
Loading...
+ } + if (error) { + return
Error: {error.message}
+ } + + var sectors = data.sectors + + const bars = [{ + name: 'Active', + className: 'active', + amount: sectors.Active, + description: '' + }, { + name: 'Inactive', + className: 'inactive', + amount: sectors.Inactive, + description: '' + }] + + return
+

Sector Proving State

+ +
+ + +
+
+} + +// Page listing pieces flagged by the piece doctor +export function PieceDoctorPage(props) { + return + } -function InspectContent() { +function PieceDoctorContent() { const params = useParams() const [searchQuery, setSearchQuery] = useState(params.query) @@ -56,7 +311,7 @@ function FlaggedPieces({setSearchQuery}) { const val = parseInt(e.target.value) RowsPerPage.save(val) setRowsPerPage(val) - navigate(inspectBasePath) + navigate(lidBasePath) scrollTop() } @@ -93,7 +348,7 @@ function FlaggedPieces({setSearchQuery}) { } const paginationParams = { - basePath: inspectBasePath, + basePath: lidBasePath, cursor, pageNum, totalCount, rowsPerPage: rowsPerPage, moreRows: moreRows, @@ -149,7 +404,7 @@ function FlaggedPieceRow({piece}) { return - + {piece.PieceCid} @@ -281,7 +536,7 @@ function PiecesWithPayload({payloadCid, pieceCids, setSearchQuery}) {
Pieces with payload CID {payloadCid}:
{pieceCids.map(pc => (
- setSearchQuery(pc)} to={"/inspect/"+pc}>{pc} + setSearchQuery(pc)} to={"/piece-doctor/"+pc}>{pc}
))} diff --git a/react/src/LegacyDealDetail.js b/react/src/LegacyDealDetail.js index 290e14840..016a60c63 100644 --- a/react/src/LegacyDealDetail.js +++ b/react/src/LegacyDealDetail.js @@ -79,7 +79,7 @@ export function LegacyDealDetail(props) { Deal Data Root CID - {deal.DealDataRoot} + {deal.DealDataRoot} CAR File Path @@ -87,7 +87,7 @@ export function LegacyDealDetail(props) { Piece CID - {deal.PieceCid} + {deal.PieceCid} Verified diff --git a/react/src/Loading.css b/react/src/Loading.css new file mode 100644 index 000000000..2753568c2 --- /dev/null +++ b/react/src/Loading.css @@ -0,0 +1,60 @@ +/*! + * three-dots - v0.3.2 + * CSS loading animations made with single element + * https://nzbin.github.io/three-dots/ + * + * Copyright (c) 2018 nzbin + * Released under MIT License + */ +@charset "UTF-8"; + +/** + * ============================================== + * Dot Flashing + * ============================================== + */ +.dot-flashing { + position: relative; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: #b3b3b3; + color: #b3b3b3; + animation: dot-flashing 1s infinite linear alternate; + animation-delay: 0.5s; +} +.dot-flashing::before, .dot-flashing::after { + content: ""; + display: inline-block; + position: absolute; + top: 0; +} +.dot-flashing::before { + left: -15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: #b3b3b3; + color: #b3b3b3; + animation: dot-flashing 1s infinite alternate; + animation-delay: 0s; +} +.dot-flashing::after { + left: 15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: #b3b3b3; + color: #b3b3b3; + animation: dot-flashing 1s infinite alternate; + animation-delay: 1s; +} + +@keyframes dot-flashing { + 0% { + background-color: #b3b3b3; + } + 50%, 100% { + background-color: #f9fbfd; + } +} diff --git a/react/src/Menu.js b/react/src/Menu.js index 5fa4250c0..fc4fc7f14 100644 --- a/react/src/Menu.js +++ b/react/src/Menu.js @@ -8,7 +8,7 @@ import {FundsMenuItem} from "./Funds"; import gridImg from './bootstrap-icons/icons/grid-3x3-gap.svg' import './Menu.css' import {SettingsMenuItem} from "./Settings"; -import {InspectMenuItem} from "./Inspect"; +import {LIDMenuItem} from "./LID"; import {ProposalLogsMenuItem} from "./ProposalLogs"; import {RetrievalLogsMenuItem} from "./RetrievalLogs"; @@ -22,12 +22,12 @@ export function Menu(props) { + - + -

Message Pool

diff --git a/react/src/Pagination.js b/react/src/Pagination.js index 9fcac7f77..1d56dd8dd 100644 --- a/react/src/Pagination.js +++ b/react/src/Pagination.js @@ -27,7 +27,7 @@ export function Pagination({basePath, cursor, pageNum, moreRows, totalCount, row var totalPages = Math.ceil(totalCount / rowsPerPage) var pageLinks = {} - if (cursor) { + if (cursor !== null && cursor !== "") { if (pageNum === 2) { pageLinks.prev = basePath } else if (pageNum > 2) { diff --git a/react/src/PieceDirectory.css b/react/src/PieceDirectory.css deleted file mode 100644 index dd0189dd0..000000000 --- a/react/src/PieceDirectory.css +++ /dev/null @@ -1,79 +0,0 @@ -.piece-directory table { - font-size: 1em; - width: 100%; -} - -.piece-directory td, .piece-directory th { - padding: 0.5em 1em; - font-weight: normal; -} - -.piece-directory th { - white-space: nowrap; - text-align: left; - opacity: 0.6; -} - -.piece-directory .search { - position: absolute; - right: 8em; - top: 2em; -} - -.piece-directory .search input { - background-image: url("./bootstrap-icons/icons/search.svg"); - background-repeat: no-repeat; - background-position: left 0.5em center; - padding-left: 2em; - padding-right: 2em; -} - -.piece-directory .search .clear-text { - position: absolute; - right: 1em; - top: 1.1em; - cursor: pointer; -} - -.piece-directory h3 { - margin-top: 2em; -} - -.piece-directory .title { - font-size: 1.25em; - color: #a61e4d; - margin: 2em 0.8em 1.5em 0.8em; -} - -.piece-detail { - padding: 1em 0 5em 0; -} - -.piece-detail .title { - color: inherit; - font-weight: normal; - margin: 0.8em; -} - -.piece-detail table { - font-size: 1em; -} - -.piece-detail table.deals tr td:first-child { - width: 8em; -} -.piece-detail table.deals tr td:last-child { - line-break: anywhere; -} - -.piece-detail table th { - text-align: left; -} - -.piece-detail table.deals .param { - color: #777777; -} - -.piece-detail td, .piece-detail th { - padding: 0.5em 1em; -} diff --git a/react/src/PieceDirectory.js b/react/src/PieceDirectory.js deleted file mode 100644 index 656460ce6..000000000 --- a/react/src/PieceDirectory.js +++ /dev/null @@ -1,279 +0,0 @@ -import {useQuery} from "@apollo/react-hooks"; -import { - DealsCountQuery, -} from "./gql"; -import moment from "moment"; -import {DebounceInput} from 'react-debounce-input'; -import React, {useState} from "react"; -import {PageContainer, ShortDealLink} from "./Components"; -import {Link} from "react-router-dom"; -import {dateFormat} from "./util-date"; -import columnsGapImg from './bootstrap-icons/icons/columns-gap.svg' -import xImg from './bootstrap-icons/icons/x-lg.svg' -import './PieceDirectory.css' -import {addCommas} from "./util"; - -const piecesBasePath = '/pieces' - -export function PieceDirectoryPage(props) { - return - - -} - -function PieceDirectoryContent(props) { - const [searchQuery, setSearchQuery] = useState('') - const handleSearchQueryChange = (event) => { - setSearchQuery(event.target.value) - } - const clearSearchBox = () => { - setSearchQuery('') - } - - const pieceRes = searchPieceCid(searchQuery) - const payloadRes = searchPayloadCid(searchQuery) - - if (pieceRes.error || payloadRes.error) { - return
Error: {pieceRes.error ? pieceRes.error.message : payloadRes.error.message}
- } - - if (pieceRes.loading || payloadRes.loading) { - return
Loading ...
- } - - const showPieces = !!pieceRes.data.piece - const showPayload = !!payloadRes.data.payload.Pieces.length - const showInstructions = !showPieces && !showPayload - return
- - - { showPieces ? : null } - { showPayload ? : null } - { showInstructions ?

Enter the piece CID or payload CID into the Search Box

: null } -
-} - -export function PieceDirectoryDetail({piece}) { - if (!piece) { - return
No piece found with piece CID {piece.PieceCid}
- } - - return
-
- - - - - - - - - - - - - - - - - - - -
Piece CID{piece.PieceCid}
Data Root CID{piece.RootCid}
Indexed CIDs{addCommas(piece.CidCount)}
Index Status{piece.IndexStatus}
- -
Deals
- - - - - - - - - - - - {piece.Deals.map(deal => ( - - - - - - - - - - ))} - -
CreatedAtDeal UUIDChain Deal IDSector NumberPiece OffsetPiece LengthUnsealed
{moment().format(dateFormat)}{deal.ChainDealID}{deal.SectorID}{deal.PieceOffset}{deal.PieceLength}{deal.IsUnsealed ? 'Yes' : 'No'}
-
-
-} - -export function PayloadMetaDetail({payload}) { - if (payload.Pieces.length === 0) { - return
No piece found with payload CID {payload.RootCid}
- } - - return
-
Pieces containing payload CID {payload.RootCid}
- {payload.Pieces.map(piece => )} -
-} - -function SearchBox(props) { - return
- - { props.value ? clear : null } -
-} - -export function PiecesMenuItem(props) { - const {data} = useQuery(DealsCountQuery, { - pollInterval: 10000, - fetchPolicy: 'network-only', - }) - - return ( -
- - -

Pieces

- -
- ) -} - -function searchPayloadCid(payloadCid) { - const pieces = [] - for (const p of mockPieces) { - if (p.RootCid == payloadCid) { - pieces.push(p) - } - } - - return { - data: { - payload: { - RootCid: payloadCid, - Pieces: pieces - } - } - } -} - -function searchPieceCid(pieceCid) { - for (const p of mockPieces) { - if (p.PieceCid == pieceCid) { - return { - data: { piece: p } - } - } - } - - return { - data: { piece: null } - } -} - -const mockPieces = [{ - PieceCid: 'baga6ea4seaqgbkvk6apsnfbtvnbjabpu4tsv6ns45c36452fdhkqxznt3vlnedq', - RootCid: 'bafybeiagwnqiviaae5aet2zivwhhsorg75x2wka2pu55o7grr23ulx5kxm', - CidCount: '3214', - IndexStatus: 'Complete', - Deals: [{ - DealUUID: '237fb3d0-fc11-40dc-a77a-0b75363ffa5e', - ChainDealID: '1', - SectorID: 1, - PieceLength: 2048, - PieceOffset: 0, - IsUnsealed: true, - }, { - DealUUID: '25332be9-54b4-471e-a669-0757f6b61fe8', - ChainDealID: '2', - SectorID: 4, - PieceLength: 2048, - PieceOffset: 2048, - IsUnsealed: false, - }] -}, { - PieceCid: 'bafybeig3yg2msah74sgvow25uxddqbabex3f3mh6hysess3w5kmgiv6zqy', - RootCid: 'bafybeiagwnqiviaae5aet2zivwhhsorg75x2wka2pu55o7grr23ulx5kxm', - CidCount: '53234', - IndexStatus: 'Indexing', - Deals: [{ - DealUUID: '237fb3d0-fc11-40dc-a77a-0b75363ffa5e', - ChainDealID: '1', - SectorID: 1, - PieceLength: 2048, - PieceOffset: 0, - IsUnsealed: true, - }, { - DealUUID: '25332be9-54b4-471e-a669-0757f6b61fe8', - ChainDealID: '2', - SectorID: 4, - PieceLength: 2048, - PieceOffset: 2048, - IsUnsealed: false, - }] -}, { - PieceCid: 'bafybeiaij7wqrolyv5gx2glkordkq22yacpgg23bdwyweenwlknk37zjyu', - RootCid: 'bafybeigbb6jrtwwdlqtqu23uzvsezm5m7qpw57emqipy5muclgp5dakpmq', - CidCount: '14921', - IndexStatus: 'Complete', - Deals: [{ - DealUUID: '237fb3d0-fc11-40dc-a77a-0b75363ffa5e', - ChainDealID: '1', - SectorID: 1, - PieceLength: 2048, - PieceOffset: 0, - IsUnsealed: true, - }, { - DealUUID: '25332be9-54b4-471e-a669-0757f6b61fe8', - ChainDealID: '2', - SectorID: 4, - PieceLength: 2048, - PieceOffset: 2048, - IsUnsealed: false, - }] -}, { - PieceCid: 'bafybeicl6ujc6ncfktctxxroxognfn7d2fqavvrryoc2lv6m4i6hpbkfti', - Deals: [{ - DealUUID: '237fb3d0-fc11-40dc-a77a-0b75363ffa5e', - ChainDealID: '1', - SectorID: 1, - PieceLength: 2048, - PieceOffset: 0, - IsUnsealed: true, - }, { - DealUUID: '25332be9-54b4-471e-a669-0757f6b61fe8', - ChainDealID: '2', - SectorID: 4, - PieceLength: 2048, - PieceOffset: 2048, - IsUnsealed: true, - }, { - DealUUID: '237fb3d0-fc11-40dc-a77a-0b75363ffa5e', - ChainDealID: '3', - SectorID: 6, - PieceLength: 2048, - PieceOffset: 0, - IsUnsealed: false, - }] -}, { - PieceCid: 'bafybeihhponjv2pdbmg33nxvccrgj34546avahl3nojk5cplawofvn2d3m', - Deals: [{ - DealUUID: '25332be9-54b4-471e-a669-0757f6b61fe8', - ChainDealID: '2', - SectorID: 4, - PieceLength: 2048, - PieceOffset: 2048, - IsUnsealed: true, - }] -}] diff --git a/react/src/RetrievalLogDetail.js b/react/src/RetrievalLogDetail.js index b5a80acba..aa214d3f1 100644 --- a/react/src/RetrievalLogDetail.js +++ b/react/src/RetrievalLogDetail.js @@ -103,11 +103,11 @@ export function RetrievalLogDetail(props) { Deal Data Root CID - {retrieval.PayloadCID} + {retrieval.PayloadCID} Piece CID - {retrieval.PieceCid} + {retrieval.PieceCid} Price per byte diff --git a/react/src/RetrievalLogs.js b/react/src/RetrievalLogs.js index 116b1ba58..d2dac60b5 100644 --- a/react/src/RetrievalLogs.js +++ b/react/src/RetrievalLogs.js @@ -176,7 +176,7 @@ function TableRow(props) { - + diff --git a/react/src/gql.js b/react/src/gql.js index cce06c3b2..55be46ae8 100644 --- a/react/src/gql.js +++ b/react/src/gql.js @@ -294,7 +294,6 @@ const RetrievalLogsCountQuery = gql` } `; - const DealCancelMutation = gql` mutation AppDealCancelMutation($id: ID!) { dealCancel(id: $id) diff --git a/react/src/util.js b/react/src/util.js index b9e421ce8..9953fb147 100644 --- a/react/src/util.js +++ b/react/src/util.js @@ -133,3 +133,11 @@ export function isContractAddress(addr) { const addressType = addr.substring(0, 2) return addressType === 't4' || addressType === 'f4' } + +export function isInteger(num){ + const isNum = (typeof(num) === 'number' || typeof(num) === "string" && num.trim() !== '') && !isNaN(num); + if (!isNum) { + return false + } + return (num+'').indexOf('.') == -1 +}