Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
vicotor
frontend
Commits
12ba8d63
Commit
12ba8d63
authored
Jan 17, 2023
by
Yuri Mikhin
Committed by
Yuri Mikhin
Jan 18, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remake charts API integration.
parent
1130e1c2
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
184 additions
and
234 deletions
+184
-234
resources.ts
lib/api/resources.ts
+10
-4
stats.ts
types/api/stats.ts
+17
-3
stats.ts
types/client/stats.ts
+0
-17
Stats.tsx
ui/pages/Stats.tsx
+10
-2
ChartWidget.tsx
ui/shared/chart/ChartWidget.tsx
+3
-2
ChartWidgetContainer.tsx
ui/stats/ChartWidgetContainer.tsx
+5
-6
ChartsWidgetsList.tsx
ui/stats/ChartsWidgetsList.tsx
+83
-48
NumberWidgetsList.tsx
ui/stats/NumberWidgetsList.tsx
+7
-2
StatsFilters.tsx
ui/stats/StatsFilters.tsx
+14
-17
charts-scheme.ts
ui/stats/constants/charts-scheme.ts
+0
-104
index.ts
ui/stats/constants/index.ts
+1
-9
useStats.tsx
ui/stats/useStats.tsx
+34
-20
No files found.
lib/api/resources.ts
View file @
12ba8d63
...
@@ -22,7 +22,7 @@ import type { InternalTransactionsResponse } from 'types/api/internalTransaction
...
@@ -22,7 +22,7 @@ import type { InternalTransactionsResponse } from 'types/api/internalTransaction
import
type
{
LogsResponseTx
,
LogsResponseAddress
}
from
'
types/api/log
'
;
import
type
{
LogsResponseTx
,
LogsResponseAddress
}
from
'
types/api/log
'
;
import
type
{
RawTracesResponse
}
from
'
types/api/rawTrace
'
;
import
type
{
RawTracesResponse
}
from
'
types/api/rawTrace
'
;
import
type
{
SearchResult
,
SearchResultFilters
}
from
'
types/api/search
'
;
import
type
{
SearchResult
,
SearchResultFilters
}
from
'
types/api/search
'
;
import
type
{
Counters
,
Charts
,
HomeStats
}
from
'
types/api/stats
'
;
import
type
{
Counters
,
StatsCharts
,
StatsChart
,
HomeStats
}
from
'
types/api/stats
'
;
import
type
{
TokenCounters
,
TokenInfo
,
TokenHolders
}
from
'
types/api/tokenInfo
'
;
import
type
{
TokenCounters
,
TokenInfo
,
TokenHolders
}
from
'
types/api/tokenInfo
'
;
import
type
{
TokenTransferResponse
,
TokenTransferFilters
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TokenTransferResponse
,
TokenTransferFilters
}
from
'
types/api/tokenTransfer
'
;
import
type
{
TransactionsResponseValidated
,
TransactionsResponsePending
,
Transaction
}
from
'
types/api/transaction
'
;
import
type
{
TransactionsResponseValidated
,
TransactionsResponsePending
,
Transaction
}
from
'
types/api/transaction
'
;
...
@@ -70,8 +70,13 @@ export const RESOURCES = {
...
@@ -70,8 +70,13 @@ export const RESOURCES = {
endpoint
:
appConfig
.
statsApi
.
endpoint
,
endpoint
:
appConfig
.
statsApi
.
endpoint
,
basePath
:
appConfig
.
statsApi
.
basePath
,
basePath
:
appConfig
.
statsApi
.
basePath
,
},
},
stats_charts
:
{
stats_lines
:
{
path
:
'
/api/v1/charts/line
'
,
path
:
'
/api/v1/lines
'
,
endpoint
:
appConfig
.
statsApi
.
endpoint
,
basePath
:
appConfig
.
statsApi
.
basePath
,
},
stats_line
:
{
path
:
'
/api/v1/lines/:id
'
,
endpoint
:
appConfig
.
statsApi
.
endpoint
,
endpoint
:
appConfig
.
statsApi
.
endpoint
,
basePath
:
appConfig
.
statsApi
.
basePath
,
basePath
:
appConfig
.
statsApi
.
basePath
,
},
},
...
@@ -293,7 +298,8 @@ Q extends 'homepage_blocks' ? Array<Block> :
...
@@ -293,7 +298,8 @@ Q extends 'homepage_blocks' ? Array<Block> :
Q
extends
'
homepage_txs
'
?
Array
<
Transaction
>
:
Q
extends
'
homepage_txs
'
?
Array
<
Transaction
>
:
Q
extends
'
homepage_indexing_status
'
?
IndexingStatus
:
Q
extends
'
homepage_indexing_status
'
?
IndexingStatus
:
Q
extends
'
stats_counters
'
?
Counters
:
Q
extends
'
stats_counters
'
?
Counters
:
Q
extends
'
stats_charts
'
?
Charts
:
Q
extends
'
stats_lines
'
?
StatsCharts
:
Q
extends
'
stats_line
'
?
StatsChart
:
Q
extends
'
blocks
'
?
BlocksResponse
:
Q
extends
'
blocks
'
?
BlocksResponse
:
Q
extends
'
block
'
?
Block
:
Q
extends
'
block
'
?
Block
:
Q
extends
'
block_txs
'
?
BlockTransactionsResponse
:
Q
extends
'
block_txs
'
?
BlockTransactionsResponse
:
...
...
types/api/stats.ts
View file @
12ba8d63
...
@@ -30,11 +30,25 @@ type Counter = {
...
@@ -30,11 +30,25 @@ type Counter = {
units
:
string
;
units
:
string
;
}
}
export
type
Charts
=
{
export
type
Stats
Charts
=
{
chart
:
Array
<
ChartsItem
>
;
sections
:
Array
<
StatsChartsSection
>
;
}
}
export
type
ChartsItem
=
{
export
type
StatsChartsSection
=
{
id
:
string
;
title
:
string
;
charts
:
Array
<
StatsChartInfo
>
;
}
export
type
StatsChartInfo
=
{
id
:
string
;
title
:
string
;
description
:
string
;
}
export
type
StatsChart
=
{
chart
:
Array
<
StatsChartItem
>
};
export
type
StatsChartItem
=
{
date
:
string
;
date
:
string
;
value
:
string
;
value
:
string
;
}
}
types/client/stats.ts
View file @
12ba8d63
export
type
StatsSection
=
{
id
:
StatsSectionIds
;
title
:
string
;
charts
:
Array
<
StatsChart
>
}
export
type
StatsSectionIds
=
keyof
typeof
StatsSectionId
;
export
enum
StatsSectionId
{
'
all
'
,
'
accounts
'
,
'
blocks
'
,
'
tokens
'
,
'
transactions
'
,
'
gas
'
,
}
export
type
StatsInterval
=
{
id
:
StatsIntervalIds
;
title
:
string
}
export
type
StatsInterval
=
{
id
:
StatsIntervalIds
;
title
:
string
}
export
type
StatsIntervalIds
=
keyof
typeof
StatsIntervalId
;
export
type
StatsIntervalIds
=
keyof
typeof
StatsIntervalId
;
export
enum
StatsIntervalId
{
export
enum
StatsIntervalId
{
...
@@ -18,9 +7,3 @@ export enum StatsIntervalId {
...
@@ -18,9 +7,3 @@ export enum StatsIntervalId {
'
sixMonths
'
,
'
sixMonths
'
,
'
oneYear
'
,
'
oneYear
'
,
}
}
export
type
StatsChart
=
{
apiId
:
string
;
title
:
string
;
description
:
string
;
}
ui/pages/Stats.tsx
View file @
12ba8d63
...
@@ -12,12 +12,16 @@ import useStats from '../stats/useStats';
...
@@ -12,12 +12,16 @@ import useStats from '../stats/useStats';
const
Stats
=
()
=>
{
const
Stats
=
()
=>
{
const
{
const
{
section
,
isLoading
,
isError
,
sections
,
currentSection
,
handleSectionChange
,
handleSectionChange
,
interval
,
interval
,
handleIntervalChange
,
handleIntervalChange
,
debounceFilterCharts
,
debounceFilterCharts
,
displayedCharts
,
displayedCharts
,
filterQuery
,
}
=
useStats
();
}
=
useStats
();
return
(
return
(
...
@@ -30,7 +34,8 @@ const Stats = () => {
...
@@ -30,7 +34,8 @@ const Stats = () => {
<
Box
mb=
{
{
base
:
6
,
sm
:
8
}
}
>
<
Box
mb=
{
{
base
:
6
,
sm
:
8
}
}
>
<
StatsFilters
<
StatsFilters
section=
{
section
}
sections=
{
sections
}
currentSection=
{
currentSection
}
onSectionChange=
{
handleSectionChange
}
onSectionChange=
{
handleSectionChange
}
interval=
{
interval
}
interval=
{
interval
}
onIntervalChange=
{
handleIntervalChange
}
onIntervalChange=
{
handleIntervalChange
}
...
@@ -39,6 +44,9 @@ const Stats = () => {
...
@@ -39,6 +44,9 @@ const Stats = () => {
</
Box
>
</
Box
>
<
ChartsWidgetsList
<
ChartsWidgetsList
filterQuery=
{
filterQuery
}
isError=
{
isError
}
isLoading=
{
isLoading
}
charts=
{
displayedCharts
}
charts=
{
displayedCharts
}
interval=
{
interval
}
interval=
{
interval
}
/>
/>
...
...
ui/shared/chart/ChartWidget.tsx
View file @
12ba8d63
...
@@ -236,9 +236,10 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight, isErro
...
@@ -236,9 +236,10 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight, isErro
<
Text
<
Text
variant=
"secondary"
variant=
"secondary"
fontSize=
"sm"
fontSize=
"sm"
textAlign=
"center"
>
>
{
`
Data didn${ apos }t load, please
`
}
{
`
The data didn${ apos }t load. Please,
`
}
<
Link
href=
{
window
.
document
.
location
.
href
}
>
try to reload page.
</
Link
>
<
Link
href=
{
window
.
document
.
location
.
href
}
>
try to reload
the
page.
</
Link
>
</
Text
>
</
Text
>
</
Flex
>
</
Flex
>
)
}
)
}
...
...
ui/stats/ChartWidgetContainer.tsx
View file @
12ba8d63
...
@@ -25,18 +25,17 @@ const ChartWidgetContainer = ({ id, title, description, interval, onLoadingError
...
@@ -25,18 +25,17 @@ const ChartWidgetContainer = ({ id, title, description, interval, onLoadingError
const
endDate
=
selectedInterval
.
start
?
formatDate
(
new
Date
())
:
undefined
;
const
endDate
=
selectedInterval
.
start
?
formatDate
(
new
Date
())
:
undefined
;
const
startDate
=
selectedInterval
.
start
?
formatDate
(
selectedInterval
.
start
)
:
undefined
;
const
startDate
=
selectedInterval
.
start
?
formatDate
(
selectedInterval
.
start
)
:
undefined
;
const
{
data
,
isLoading
,
isError
}
=
useApiQuery
(
'
stats_charts
'
,
{
const
{
data
,
isLoading
,
isError
}
=
useApiQuery
(
'
stats_line
'
,
{
pathParams
:
{
id
},
queryParams
:
{
queryParams
:
{
name
:
id
,
from
:
startDate
,
from
:
startDate
,
to
:
endDate
,
to
:
endDate
,
},
},
});
});
const
items
=
data
?.
chart
const
items
=
data
?.
chart
?.
map
((
item
)
=>
{
.
map
((
item
)
=>
{
return
{
date
:
new
Date
(
item
.
date
),
value
:
Number
(
item
.
value
)
};
return
{
date
:
new
Date
(
item
.
date
),
value
:
Number
(
item
.
value
)
};
});
});
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
isError
)
{
if
(
isError
)
{
...
...
ui/stats/ChartsWidgetsList.tsx
View file @
12ba8d63
import
{
Box
,
Grid
,
GridItem
,
Heading
,
List
,
ListItem
}
from
'
@chakra-ui/react
'
;
import
{
Box
,
Grid
,
GridItem
,
Heading
,
List
,
ListItem
,
Skeleton
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useState
}
from
'
react
'
;
import
type
{
StatsIntervalIds
,
StatsSection
}
from
'
types/client/stats
'
;
import
type
{
StatsChartsSection
}
from
'
types/api/stats
'
;
import
type
{
StatsIntervalIds
}
from
'
types/client/stats
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
import
EmptySearchResult
from
'
../apps/EmptySearchResult
'
;
import
EmptySearchResult
from
'
../apps/EmptySearchResult
'
;
import
ChartWidgetSkeleton
from
'
../shared/chart/ChartWidgetSkeleton
'
;
import
ChartsLoadingErrorAlert
from
'
./ChartsLoadingErrorAlert
'
;
import
ChartsLoadingErrorAlert
from
'
./ChartsLoadingErrorAlert
'
;
import
ChartWidgetContainer
from
'
./ChartWidgetContainer
'
;
import
ChartWidgetContainer
from
'
./ChartWidgetContainer
'
;
type
Props
=
{
type
Props
=
{
charts
:
Array
<
StatsSection
>
;
filterQuery
:
string
;
isError
:
boolean
;
isLoading
:
boolean
;
charts
?:
Array
<
StatsChartsSection
>
;
interval
:
StatsIntervalIds
;
interval
:
StatsIntervalIds
;
}
}
const
ChartsWidgetsList
=
({
charts
,
interval
}:
Props
)
=>
{
const
skeletonsCount
=
4
;
const
ChartsWidgetsList
=
({
filterQuery
,
isError
,
isLoading
,
charts
,
interval
}:
Props
)
=>
{
const
[
isSomeChartLoadingError
,
setIsSomeChartLoadingError
]
=
useState
(
false
);
const
[
isSomeChartLoadingError
,
setIsSomeChartLoadingError
]
=
useState
(
false
);
const
isAnyChartDisplayed
=
charts
.
some
((
section
)
=>
section
.
charts
.
length
>
0
);
const
isAnyChartDisplayed
=
charts
?.
some
((
section
)
=>
section
.
charts
.
length
>
0
);
const
isEmptyChartList
=
Boolean
(
filterQuery
)
&&
!
isAnyChartDisplayed
;
const
handleChartLoadingError
=
useCallback
(
const
handleChartLoadingError
=
useCallback
(
()
=>
setIsSomeChartLoadingError
(
true
),
()
=>
setIsSomeChartLoadingError
(
true
),
[
setIsSomeChartLoadingError
]);
[
setIsSomeChartLoadingError
]);
const
skeletonElement
=
[
...
Array
(
skeletonsCount
)
]
.
map
((
e
,
i
)
=>
(
<
GridItem
key=
{
i
}
>
<
ChartWidgetSkeleton
hasDescription=
{
true
}
/>
</
GridItem
>
));
if
(
isLoading
)
{
return
(
<>
<
Skeleton
w=
"30%"
h=
"32px"
mb=
{
4
}
/>
<
Grid
templateColumns=
{
{
lg
:
'
repeat(2, minmax(0, 1fr))
'
,
}
}
gap=
{
4
}
>
{
skeletonElement
}
</
Grid
>
</>
);
}
if
(
isError
)
{
return
<
ChartsLoadingErrorAlert
/>;
}
if
(
isEmptyChartList
)
{
return
<
EmptySearchResult
text=
{
`Couldn${ apos }t find a chart that matches your filter query.`
}
/>;
}
return
(
return
(
<
Box
>
<
Box
>
{
isSomeChartLoadingError
&&
(
{
isSomeChartLoadingError
&&
(
<
ChartsLoadingErrorAlert
/>
<
ChartsLoadingErrorAlert
/>
)
}
)
}
{
isAnyChartDisplayed
?
(
<
List
>
<
List
>
{
{
charts
?.
map
((
section
)
=>
(
charts
.
map
((
section
)
=>
(
<
ListItem
<
ListItem
key=
{
section
.
id
}
key=
{
section
.
id
}
mb=
{
8
}
mb=
{
8
}
_last=
{
{
_last=
{
{
marginBottom
:
0
,
marginBottom
:
0
,
}
}
}
}
>
<
Heading
size=
"md"
mb=
{
4
}
>
>
<
Heading
{
section
.
title
}
size=
"md"
</
Heading
>
mb=
{
4
}
>
{
section
.
title
}
</
Heading
>
<
Grid
<
Grid
templateColumns=
{
{
templateColumns=
{
{
lg
:
'
repeat(2, minmax(0, 1fr))
'
,
lg
:
'
repeat(2, minmax(0, 1fr))
'
,
}
}
}
}
gap=
{
4
}
gap=
{
4
}
>
>
{
section
.
charts
.
map
((
chart
)
=>
(
{
section
.
charts
.
map
((
chart
)
=>
(
<
GridItem
<
GridItem
key=
{
chart
.
apiId
}
key=
{
chart
.
id
}
>
>
<
ChartWidgetContainer
<
ChartWidgetContainer
id=
{
chart
.
apiId
}
id=
{
chart
.
id
}
title=
{
chart
.
title
}
title=
{
chart
.
title
}
description=
{
chart
.
description
}
description=
{
chart
.
description
}
interval=
{
interval
}
interval=
{
interval
}
onLoadingError=
{
handleChartLoadingError
}
onLoadingError=
{
handleChartLoadingError
}
/>
/>
</
GridItem
>
</
GridItem
>
))
}
))
}
</
Grid
>
</
Grid
>
</
ListItem
>
</
ListItem
>
))
))
}
}
</
List
>
</
List
>
)
:
(
<
EmptySearchResult
text=
{
`Couldn${ apos }t find a chart that matches your filter query.`
}
/>
)
}
</
Box
>
</
Box
>
);
);
};
};
...
...
ui/stats/NumberWidgetsList.tsx
View file @
12ba8d63
...
@@ -4,17 +4,22 @@ import React from 'react';
...
@@ -4,17 +4,22 @@ import React from 'react';
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
import
formatNumberToMetricPrefix
from
'
lib/formatNumberToMetricPrefix
'
;
import
formatNumberToMetricPrefix
from
'
lib/formatNumberToMetricPrefix
'
;
import
DataFetchAlert
from
'
../shared/DataFetchAlert
'
;
import
NumberWidget
from
'
./NumberWidget
'
;
import
NumberWidget
from
'
./NumberWidget
'
;
import
NumberWidgetSkeleton
from
'
./NumberWidgetSkeleton
'
;
import
NumberWidgetSkeleton
from
'
./NumberWidgetSkeleton
'
;
const
skeletonsCount
=
8
;
const
skeletonsCount
=
8
;
const
NumberWidgetsList
=
()
=>
{
const
NumberWidgetsList
=
()
=>
{
const
{
data
,
isLoading
}
=
useApiQuery
(
'
stats_counters
'
);
const
{
data
,
isLoading
,
isError
}
=
useApiQuery
(
'
stats_counters
'
);
const
skeletonElement
=
[
...
Array
(
skeletonsCount
)
]
const
skeletonElement
=
[
...
Array
(
skeletonsCount
)
]
.
map
((
e
,
i
)
=>
<
NumberWidgetSkeleton
key=
{
i
}
/>);
.
map
((
e
,
i
)
=>
<
NumberWidgetSkeleton
key=
{
i
}
/>);
if
(
isError
)
{
return
<
DataFetchAlert
/>;
}
return
(
return
(
<
Grid
<
Grid
gridTemplateColumns=
{
{
base
:
'
repeat(2, 1fr)
'
,
lg
:
'
repeat(4, 1fr)
'
}
}
gridTemplateColumns=
{
{
base
:
'
repeat(2, 1fr)
'
,
lg
:
'
repeat(4, 1fr)
'
}
}
...
@@ -27,7 +32,7 @@ const NumberWidgetsList = () => {
...
@@ -27,7 +32,7 @@ const NumberWidgetsList = () => {
<
NumberWidget
<
NumberWidget
key=
{
id
}
key=
{
id
}
label=
{
title
}
label=
{
title
}
value=
{
`${ formatNumberToMetricPrefix(Number(value)) } ${ units }`
}
value=
{
`${ formatNumberToMetricPrefix(Number(value)) } ${ units
? units : ''
}`
}
/>
/>
);
);
})
}
})
}
...
...
ui/stats/StatsFilters.tsx
View file @
12ba8d63
import
{
Grid
,
GridItem
}
from
'
@chakra-ui/react
'
;
import
{
Grid
,
GridItem
}
from
'
@chakra-ui/react
'
;
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
StatsInterval
,
StatsIntervalIds
,
StatsSection
,
StatsSectionIds
}
from
'
types/client/stats
'
;
import
type
{
StatsChartsSection
}
from
'
types/api/stats
'
;
import
type
{
StatsInterval
,
StatsIntervalIds
}
from
'
types/client/stats
'
;
import
FilterInput
from
'
ui/shared/FilterInput
'
;
import
FilterInput
from
'
ui/shared/FilterInput
'
;
import
{
STATS_INTERVALS
,
STATS_SECTIONS
}
from
'
./constants
'
;
import
{
STATS_INTERVALS
}
from
'
./constants
'
;
import
{
statsChartsScheme
}
from
'
./constants/charts-scheme
'
;
import
StatsDropdownMenu
from
'
./StatsDropdownMenu
'
;
import
StatsDropdownMenu
from
'
./StatsDropdownMenu
'
;
const
listedSections
=
statsChartsScheme
.
filter
(
section
=>
section
.
charts
.
length
>
0
);
const
sectionsList
=
Object
.
keys
(
STATS_SECTIONS
)
.
filter
(
key
=>
key
===
'
all
'
||
listedSections
.
some
(
section
=>
section
.
id
===
key
))
.
map
((
id
:
string
)
=>
({
id
:
id
,
title
:
STATS_SECTIONS
[
id
as
StatsSectionIds
],
}))
as
Array
<
StatsSection
>
;
const
intervalList
=
Object
.
keys
(
STATS_INTERVALS
).
map
((
id
:
string
)
=>
({
const
intervalList
=
Object
.
keys
(
STATS_INTERVALS
).
map
((
id
:
string
)
=>
({
id
:
id
,
id
:
id
,
title
:
STATS_INTERVALS
[
id
as
StatsIntervalIds
].
title
,
title
:
STATS_INTERVALS
[
id
as
StatsIntervalIds
].
title
,
}))
as
Array
<
StatsInterval
>
;
}))
as
Array
<
StatsInterval
>
;
type
Props
=
{
type
Props
=
{
section
:
StatsSectionIds
;
sections
?:
Array
<
StatsChartsSection
>
;
onSectionChange
:
(
newSection
:
StatsSectionIds
)
=>
void
;
currentSection
:
string
;
onSectionChange
:
(
newSection
:
string
)
=>
void
;
interval
:
StatsIntervalIds
;
interval
:
StatsIntervalIds
;
onIntervalChange
:
(
newInterval
:
StatsIntervalIds
)
=>
void
;
onIntervalChange
:
(
newInterval
:
StatsIntervalIds
)
=>
void
;
onFilterInputChange
:
(
q
:
string
)
=>
void
;
onFilterInputChange
:
(
q
:
string
)
=>
void
;
}
}
const
StatsFilters
=
({
const
StatsFilters
=
({
section
,
sections
,
currentSection
,
onSectionChange
,
onSectionChange
,
interval
,
interval
,
onIntervalChange
,
onIntervalChange
,
onFilterInputChange
,
onFilterInputChange
,
}:
Props
)
=>
{
}:
Props
)
=>
{
const
sectionsList
=
[
{
id
:
'
all
'
,
title
:
'
All
'
,
},
...
(
sections
||
[])
];
return
(
return
(
<
Grid
<
Grid
gap=
{
2
}
gap=
{
2
}
...
@@ -56,7 +53,7 @@ const StatsFilters = ({
...
@@ -56,7 +53,7 @@ const StatsFilters = ({
>
>
<
StatsDropdownMenu
<
StatsDropdownMenu
items=
{
sectionsList
}
items=
{
sectionsList
}
selectedId=
{
s
ection
}
selectedId=
{
currentS
ection
}
onSelect=
{
onSectionChange
}
onSelect=
{
onSectionChange
}
/>
/>
</
GridItem
>
</
GridItem
>
...
...
ui/stats/constants/charts-scheme.ts
deleted
100644 → 0
View file @
1130e1c2
import
type
{
StatsSection
}
from
'
types/client/stats
'
;
export
const
statsChartsScheme
:
Array
<
StatsSection
>
=
[
{
id
:
'
accounts
'
,
title
:
'
Accounts
'
,
charts
:
[
{
apiId
:
'
activeAccounts
'
,
title
:
'
Active accounts
'
,
description
:
'
Active accounts number per period
'
,
},
{
apiId
:
'
accountsGrowth
'
,
title
:
'
Accounts growth
'
,
description
:
'
Cumulative accounts number per period
'
,
},
],
},
{
id
:
'
transactions
'
,
title
:
'
Transactions
'
,
charts
:
[
{
apiId
:
'
averageTxnFee
'
,
title
:
'
Average transaction fee
'
,
description
:
'
The average amount in USD spent per transaction
'
,
},
{
apiId
:
'
txnsFee
'
,
title
:
'
Transactions fees
'
,
description
:
'
Amount of tokens paid as fees
'
,
},
{
apiId
:
'
newTxns
'
,
title
:
'
New transactions
'
,
description
:
'
New transactions number
'
,
},
{
apiId
:
'
txnsGrowth
'
,
title
:
'
Transactions growth
'
,
description
:
'
Cumulative transactions number
'
,
},
],
},
{
id
:
'
blocks
'
,
title
:
'
Blocks
'
,
charts
:
[
{
apiId
:
'
newBlocks
'
,
title
:
'
New blocks
'
,
description
:
'
New blocks number
'
,
},
{
apiId
:
'
averageBlockSize
'
,
title
:
'
Average block size
'
,
description
:
'
Average size of blocks in bytes
'
,
},
],
},
{
id
:
'
tokens
'
,
title
:
'
Tokens
'
,
charts
:
[
{
apiId
:
'
nativeCoinHoldersGrowth
'
,
title
:
'
Native coin holders growth
'
,
description
:
'
Cumulative token holders number for the period
'
,
},
{
apiId
:
'
newNativeCoinTransfers
'
,
title
:
'
New native coins transfers
'
,
description
:
'
New token transfers number for the period
'
,
},
{
apiId
:
'
nativeCoinSupply
'
,
title
:
'
Native coin circulating supply
'
,
description
:
'
Amount of token circulating supply for the period
'
,
},
],
},
{
id
:
'
gas
'
,
title
:
'
Gas
'
,
charts
:
[
{
apiId
:
'
averageGasLimit
'
,
title
:
'
Average gas limit
'
,
description
:
'
Average gas limit per block for the period
'
,
},
{
apiId
:
'
gasUsedGrowth
'
,
title
:
'
Gas used growth
'
,
description
:
'
Cumulative gas used for the period
'
,
},
{
apiId
:
'
averageGasPrice
'
,
title
:
'
Average gas price
'
,
description
:
'
Average gas price for the period (Gwei)
'
,
},
],
},
];
ui/stats/constants/index.ts
View file @
12ba8d63
import
type
{
StatsSectionIds
,
StatsIntervalIds
}
from
'
types/client/stats
'
;
import
type
{
StatsIntervalIds
}
from
'
types/client/stats
'
;
export
const
STATS_SECTIONS
:
{
[
key
in
StatsSectionIds
]?:
string
}
=
{
all
:
'
All stats
'
,
accounts
:
'
Accounts
'
,
blocks
:
'
Blocks
'
,
transactions
:
'
Transactions
'
,
gas
:
'
Gas
'
,
};
export
const
STATS_INTERVALS
:
{
[
key
in
StatsIntervalIds
]:
{
title
:
string
;
start
?:
Date
}
}
=
{
export
const
STATS_INTERVALS
:
{
[
key
in
StatsIntervalIds
]:
{
title
:
string
;
start
?:
Date
}
}
=
{
all
:
{
all
:
{
...
...
ui/stats/useStats.tsx
View file @
12ba8d63
import
debounce
from
'
lodash/debounce
'
;
import
debounce
from
'
lodash/debounce
'
;
import
React
,
{
useCallback
,
useEffect
,
useState
}
from
'
react
'
;
import
React
,
{
useCallback
,
useEffect
,
use
Memo
,
use
State
}
from
'
react
'
;
import
type
{
StatsChart
,
StatsIntervalIds
,
StatsSection
,
StatsSectionIds
}
from
'
types/client/stats
'
;
import
type
{
StatsChartInfo
,
StatsChartsSection
}
from
'
types/api/stats
'
;
import
type
{
StatsIntervalIds
}
from
'
types/client/stats
'
;
import
{
statsChartsScheme
}
from
'
./constants/charts-scheme
'
;
import
useApiQuery
from
'
lib/api/useApiQuery
'
;
function
isSectionMatches
(
section
:
Stats
Section
,
currentSection
:
StatsSectionIds
):
boolean
{
function
isSectionMatches
(
section
:
Stats
ChartsSection
,
currentSection
:
string
):
boolean
{
return
currentSection
===
'
all
'
||
section
.
id
===
currentSection
;
return
currentSection
===
'
all
'
||
section
.
id
===
currentSection
;
}
}
function
isChartNameMatches
(
q
:
string
,
chart
:
StatsChart
)
{
function
isChartNameMatches
(
q
:
string
,
chart
:
StatsChart
Info
)
{
return
chart
.
title
.
toLowerCase
().
includes
(
q
.
toLowerCase
());
return
chart
.
title
.
toLowerCase
().
includes
(
q
.
toLowerCase
());
}
}
export
default
function
useStats
()
{
export
default
function
useStats
()
{
const
[
displayedCharts
,
setDisplayedCharts
]
=
useState
<
Array
<
StatsSection
>>
(
statsChartsScheme
);
const
{
data
,
isLoading
,
isError
}
=
useApiQuery
(
'
stats_lines
'
);
const
[
section
,
setSection
]
=
useState
<
StatsSectionIds
>
(
'
all
'
);
const
[
interval
,
setInterval
]
=
useState
<
StatsIntervalIds
>
(
'
oneMonth
'
);
const
[
currentSection
,
setCurrentSection
]
=
useState
(
'
all
'
);
const
[
filterQuery
,
setFilterQuery
]
=
useState
(
''
);
const
[
filterQuery
,
setFilterQuery
]
=
useState
(
''
);
const
[
displayedCharts
,
setDisplayedCharts
]
=
useState
(
data
?.
sections
);
const
[
interval
,
setInterval
]
=
useState
<
StatsIntervalIds
>
(
'
oneMonth
'
);
const
sectionIds
=
useMemo
(()
=>
data
?.
sections
?.
map
(({
id
})
=>
id
),
[
data
]);
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
const
debounceFilterCharts
=
useCallback
(
debounce
(
q
=>
setFilterQuery
(
q
),
500
),
[]);
const
debounceFilterCharts
=
useCallback
(
debounce
(
q
=>
setFilterQuery
(
q
),
500
),
[]);
const
filterCharts
=
useCallback
((
q
:
string
,
currentSection
:
StatsSectionIds
)
=>
{
const
filterCharts
=
useCallback
((
q
:
string
,
currentSection
:
string
)
=>
{
const
charts
=
statsChartsScheme
const
charts
=
data
?.
sections
?.
map
((
section
:
StatsSection
)
=>
{
?.
map
((
section
)
=>
{
const
charts
=
section
.
charts
.
filter
((
chart
:
StatsChart
)
=>
isSectionMatches
(
section
,
currentSection
)
&&
isChartNameMatches
(
q
,
chart
));
const
charts
=
section
.
charts
.
filter
((
chart
)
=>
isSectionMatches
(
section
,
currentSection
)
&&
isChartNameMatches
(
q
,
chart
));
return
{
return
{
...
section
,
...
section
,
charts
,
charts
,
};
};
}).
filter
((
section
:
StatsSection
)
=>
section
.
charts
.
length
>
0
);
}).
filter
((
section
)
=>
section
.
charts
.
length
>
0
);
setDisplayedCharts
(
charts
||
[]);
setDisplayedCharts
(
charts
||
[]);
},
[]);
},
[
data
]);
const
handleSectionChange
=
useCallback
((
newSection
:
StatsSectionIds
)
=>
{
const
handleSectionChange
=
useCallback
((
newSection
:
string
)
=>
{
setSection
(
newSection
);
set
Current
Section
(
newSection
);
},
[]);
},
[]);
const
handleIntervalChange
=
useCallback
((
newInterval
:
StatsIntervalIds
)
=>
{
const
handleIntervalChange
=
useCallback
((
newInterval
:
StatsIntervalIds
)
=>
{
...
@@ -45,18 +49,28 @@ export default function useStats() {
...
@@ -45,18 +49,28 @@ export default function useStats() {
},
[]);
},
[]);
useEffect
(()
=>
{
useEffect
(()
=>
{
filterCharts
(
filterQuery
,
s
ection
);
filterCharts
(
filterQuery
,
currentS
ection
);
},
[
filterQuery
,
s
ection
,
filterCharts
]);
},
[
filterQuery
,
currentS
ection
,
filterCharts
]);
return
React
.
useMemo
(()
=>
({
return
React
.
useMemo
(()
=>
({
section
,
sections
:
data
?.
sections
,
sectionIds
,
isLoading
,
isError
,
filterQuery
,
currentSection
,
handleSectionChange
,
handleSectionChange
,
interval
,
interval
,
handleIntervalChange
,
handleIntervalChange
,
debounceFilterCharts
,
debounceFilterCharts
,
displayedCharts
,
displayedCharts
,
}),
[
}),
[
section
,
data
,
sectionIds
,
isLoading
,
isError
,
filterQuery
,
currentSection
,
handleSectionChange
,
handleSectionChange
,
interval
,
interval
,
handleIntervalChange
,
handleIntervalChange
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment