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
e22db695
Commit
e22db695
authored
Sep 25, 2024
by
isstuev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
stats fixes after test part 1
parent
ab22a7ab
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
162 additions
and
107 deletions
+162
-107
useNavItems.tsx
lib/hooks/useNavItems.tsx
+1
-1
Chart.tsx
ui/pages/Chart.tsx
+27
-35
ChartMenu.tsx
ui/shared/chart/ChartMenu.tsx
+22
-1
ChartTooltip.tsx
ui/shared/chart/ChartTooltip.tsx
+29
-3
ChartWidget.tsx
ui/shared/chart/ChartWidget.tsx
+7
-4
ChartWidgetContent.tsx
ui/shared/chart/ChartWidgetContent.tsx
+8
-4
ChartWidgetGraph.tsx
ui/shared/chart/ChartWidgetGraph.tsx
+38
-41
FullscreenChartModal.tsx
ui/shared/chart/FullscreenChartModal.tsx
+13
-13
ChartTooltipTitle.tsx
ui/shared/chart/tooltip/ChartTooltipTitle.tsx
+7
-2
types.tsx
ui/shared/chart/types.tsx
+1
-0
useChartQuery.tsx
ui/shared/chart/useChartQuery.tsx
+1
-1
useZoom.tsx
ui/shared/chart/useZoom.tsx
+6
-2
TagGroupSelect.tsx
ui/shared/tagGroupSelect/TagGroupSelect.tsx
+2
-0
No files found.
lib/hooks/useNavItems.tsx
View file @
e22db695
...
...
@@ -248,7 +248,7 @@ export default function useNavItems(): ReturnType {
text
:
'
Charts & stats
'
,
nextRoute
:
{
pathname
:
'
/stats
'
as
const
},
icon
:
'
stats
'
,
isActive
:
pathname
===
'
/stats
'
,
isActive
:
pathname
.
startsWith
(
'
/stats
'
)
,
}
:
null
,
apiNavItems
.
length
>
0
&&
{
text
:
'
API
'
,
...
...
ui/pages/Chart.tsx
View file @
e22db695
import
{
Button
,
Flex
,
IconButton
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
Button
,
Flex
,
IconButton
,
Link
,
Text
}
from
'
@chakra-ui/react
'
;
import
{
useRouter
}
from
'
next/router
'
;
import
React
from
'
react
'
;
...
...
@@ -19,7 +19,7 @@ import ChartMenu from 'ui/shared/chart/ChartMenu';
import
ChartResolutionSelect
from
'
ui/shared/chart/ChartResolutionSelect
'
;
import
ChartWidgetContent
from
'
ui/shared/chart/ChartWidgetContent
'
;
import
useChartQuery
from
'
ui/shared/chart/useChartQuery
'
;
import
useZoom
Reset
from
'
ui/shared/chart/useZoomReset
'
;
import
useZoom
from
'
ui/shared/chart/useZoom
'
;
import
CopyToClipboard
from
'
ui/shared/CopyToClipboard
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
import
PageTitle
from
'
ui/shared/Page/PageTitle
'
;
...
...
@@ -46,7 +46,7 @@ const Chart = () => {
const
id
=
getQueryParamString
(
router
.
query
.
id
);
const
[
intervalState
,
setIntervalState
]
=
React
.
useState
<
StatsIntervalIds
|
undefined
>
();
const
[
resolution
,
setResolution
]
=
React
.
useState
<
Resolution
>
(
DEFAULT_RESOLUTION
);
const
{
isZoomResetInitial
,
handleZoom
,
handleZoomReset
}
=
useZoomReset
();
const
{
zoomRange
,
handleZoom
,
handleZoomReset
}
=
useZoom
();
const
interval
=
intervalState
||
getIntervalByResolution
(
resolution
);
...
...
@@ -155,6 +155,10 @@ const Chart = () => {
title=
{
info
?.
title
||
''
}
isLoading=
{
lineQuery
.
isPlaceholderData
}
chartRef=
{
ref
}
resolution=
{
resolution
}
zoomRange=
{
zoomRange
}
handleZoom=
{
handleZoom
}
handleZoomReset=
{
handleZoomReset
}
/>
)
}
</
Flex
>
...
...
@@ -172,44 +176,31 @@ const Chart = () => {
withTextAd
/>
<
Flex
alignItems=
"center"
justifyContent=
"space-between"
>
<
Flex
alignItems=
"center"
gap=
{
3
}
maxW=
"100%"
overflow=
"hidden"
>
<
Flex
alignItems=
"center"
gap=
{
{
base
:
3
,
lg
:
6
}
}
maxW=
"100%"
overflow=
"hidden"
>
<
Flex
alignItems=
"center"
gap=
{
3
}
>
<
Text
>
Period
</
Text
>
<
ChartIntervalSelect
interval=
{
interval
}
onIntervalChange=
{
setIntervalState
}
/>
</
Flex
>
{
lineQuery
.
data
?.
info
?.
resolutions
&&
lineQuery
.
data
?.
info
?.
resolutions
.
length
>
1
&&
(
<>
<
Text
ml=
{
{
base
:
0
,
lg
:
3
}
}
>
{
isMobile
?
'
Res.
'
:
'
Resolution
'
}
</
Text
>
<
Flex
alignItems=
"center"
gap=
{
3
}
>
<
Text
>
{
isMobile
?
'
Res.
'
:
'
Resolution
'
}
</
Text
>
<
ChartResolutionSelect
resolution=
{
resolution
}
onResolutionChange=
{
setResolution
}
resolutions=
{
lineQuery
.
data
?.
info
?.
resolutions
||
[]
}
/>
</>
</
Flex
>
)
}
{
(
!
isZoomResetInitial
||
resolution
!==
DEFAULT_RESOLUTION
)
&&
(
isMobile
?
(
<
IconButton
aria
-
label=
"Reset"
variant=
"ghost"
size=
"sm"
icon=
{
<
IconSvg
name=
"repeat"
boxSize=
{
5
}
/>
}
onClick=
{
handleReset
}
/>
)
:
(
<
Button
leftIcon=
{
<
IconSvg
name=
"repeat"
w=
{
4
}
h=
{
4
}
/>
}
colorScheme=
"blue"
gridColumn=
{
2
}
justifySelf=
"end"
alignSelf=
"top"
gridRow=
"1/3"
size=
"sm"
variant=
"outline"
{
(
Boolean
(
zoomRange
))
&&
(
<
Link
onClick=
{
handleReset
}
ml=
{
6
}
display=
"flex"
alignItems=
"center"
gap=
{
2
}
>
Reset
</
Button
>
)
<
IconSvg
name=
"repeat"
w=
{
5
}
h=
{
5
}
/>
{
!
isMobile
&&
'
Reset
'
}
</
Link
>
)
}
</
Flex
>
{
!
isMobile
&&
shareAndMenu
}
...
...
@@ -228,9 +219,10 @@ const Chart = () => {
units=
{
info
?.
units
||
undefined
}
isEnlarged
isLoading=
{
lineQuery
.
isPlaceholderData
}
isZoomResetInitial=
{
isZoomResetInitial
}
zoomRange=
{
zoomRange
}
handleZoom=
{
handleZoom
}
emptyText=
"No data for the selected resolution & interval."
resolution=
{
resolution
}
/>
</
Flex
>
</>
...
...
ui/shared/chart/ChartMenu.tsx
View file @
e22db695
...
...
@@ -12,6 +12,7 @@ import domToImage from 'dom-to-image';
import
React
from
'
react
'
;
import
type
{
TimeChartItem
}
from
'
./types
'
;
import
type
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
type
{
Route
}
from
'
nextjs-routes
'
;
import
{
route
}
from
'
nextjs-routes
'
;
...
...
@@ -33,11 +34,27 @@ export type Props = {
isLoading
:
boolean
;
chartRef
:
React
.
RefObject
<
HTMLDivElement
>
;
href
?:
Route
;
resolution
?:
Resolution
;
zoomRange
?:
[
Date
,
Date
];
handleZoom
:
(
range
:
[
Date
,
Date
])
=>
void
;
handleZoomReset
:
()
=>
void
;
}
const
DOWNLOAD_IMAGE_SCALE
=
5
;
const
ChartMenu
=
({
items
,
title
,
description
,
units
,
isLoading
,
chartRef
,
href
}:
Props
)
=>
{
const
ChartMenu
=
({
items
,
title
,
description
,
units
,
isLoading
,
chartRef
,
href
,
resolution
,
zoomRange
,
handleZoom
,
handleZoomReset
,
}:
Props
)
=>
{
const
pngBackgroundColor
=
useColorModeValue
(
'
white
'
,
'
black
'
);
const
[
isFullscreen
,
setIsFullscreen
]
=
React
.
useState
(
false
);
...
...
@@ -172,6 +189,10 @@ const ChartMenu = ({ items, title, description, units, isLoading, chartRef, href
description=
{
description
}
onClose=
{
clearFullscreenChart
}
units=
{
units
}
resolution=
{
resolution
}
zoomRange=
{
zoomRange
}
handleZoom=
{
handleZoom
}
handleZoomReset=
{
handleZoomReset
}
/>
)
}
</>
...
...
ui/shared/chart/ChartTooltip.tsx
View file @
e22db695
import
*
as
d3
from
'
d3
'
;
import
React
from
'
react
'
;
import
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
type
{
TimeChartData
}
from
'
ui/shared/chart/types
'
;
import
ChartTooltipBackdrop
,
{
useRenderBackdrop
}
from
'
./tooltip/ChartTooltipBackdrop
'
;
...
...
@@ -21,9 +22,21 @@ interface Props {
yScale
:
d3
.
ScaleLinear
<
number
,
number
>
;
anchorEl
:
SVGRectElement
|
null
;
noAnimation
?:
boolean
;
resolution
?:
Resolution
;
}
const
ChartTooltip
=
({
xScale
,
yScale
,
width
,
tooltipWidth
=
200
,
height
,
data
,
anchorEl
,
noAnimation
,
...
props
}:
Props
)
=>
{
const
ChartTooltip
=
({
xScale
,
yScale
,
width
,
tooltipWidth
=
200
,
height
,
data
,
anchorEl
,
noAnimation
,
resolution
,
...
props
}:
Props
)
=>
{
const
ref
=
React
.
useRef
<
SVGGElement
>
(
null
);
const
trackerId
=
React
.
useRef
<
number
>
();
const
isVisible
=
React
.
useRef
(
false
);
...
...
@@ -150,8 +163,8 @@ const ChartTooltip = ({ xScale, yScale, width, tooltipWidth = 200, height, data,
{
data
.
map
(({
name
})
=>
<
ChartTooltipPoint
key=
{
name
}
/>)
}
<
ChartTooltipContent
>
<
ChartTooltipBackdrop
/>
<
ChartTooltipTitle
/>
<
ChartTooltipRow
label=
"Date"
lineNum=
{
1
}
/>
<
ChartTooltipTitle
resolution=
{
resolution
}
/>
<
ChartTooltipRow
label=
{
getDateLabel
(
resolution
)
}
lineNum=
{
1
}
/>
{
data
.
map
(({
name
},
index
)
=>
<
ChartTooltipRow
key=
{
name
}
label=
{
name
}
lineNum=
{
index
+
1
}
/>)
}
</
ChartTooltipContent
>
</
g
>
...
...
@@ -159,3 +172,16 @@ const ChartTooltip = ({ xScale, yScale, width, tooltipWidth = 200, height, data,
};
export
default
React
.
memo
(
ChartTooltip
);
function
getDateLabel
(
resolution
?:
Resolution
):
string
{
switch
(
resolution
)
{
case
Resolution
.
WEEK
:
return
'
Dates
'
;
case
Resolution
.
MONTH
:
return
'
Month
'
;
case
Resolution
.
YEAR
:
return
'
Year
'
;
default
:
return
'
Date
'
;
}
}
ui/shared/chart/ChartWidget.tsx
View file @
e22db695
...
...
@@ -17,7 +17,7 @@ import IconSvg from 'ui/shared/IconSvg';
import
ChartMenu
from
'
./ChartMenu
'
;
import
ChartWidgetContent
from
'
./ChartWidgetContent
'
;
import
useZoom
Reset
from
'
./useZoomReset
'
;
import
useZoom
from
'
./useZoom
'
;
export
type
Props
=
{
items
?:
Array
<
TimeChartItem
>
;
...
...
@@ -45,7 +45,7 @@ const ChartWidget = ({
href
,
}:
Props
)
=>
{
const
ref
=
useRef
<
HTMLDivElement
>
(
null
);
const
{
isZoomResetInitial
,
handleZoom
,
handleZoomReset
}
=
useZoomReset
();
const
{
zoomRange
,
handleZoom
,
handleZoomReset
}
=
useZoom
();
const
borderColor
=
useColorModeValue
(
'
gray.200
'
,
'
gray.600
'
);
...
...
@@ -60,7 +60,7 @@ const ChartWidget = ({
title=
{
title
}
emptyText=
{
emptyText
}
handleZoom=
{
handleZoom
}
isZoomResetInitial=
{
isZoomResetInitial
}
zoomRange=
{
zoomRange
}
noAnimation=
{
noAnimation
}
/>
);
...
...
@@ -116,7 +116,7 @@ const ChartWidget = ({
<
Flex
ml=
"auto"
columnGap=
{
2
}
>
<
Tooltip
label=
"Reset zoom"
>
<
IconButton
hidden=
{
isZoomResetInitial
}
hidden=
{
!
zoomRange
}
aria
-
label=
"Reset zoom"
colorScheme=
"blue"
w=
{
9
}
...
...
@@ -137,6 +137,9 @@ const ChartWidget = ({
isLoading=
{
isLoading
}
chartRef=
{
ref
}
units=
{
units
}
handleZoom=
{
handleZoom
}
handleZoomReset=
{
handleZoomReset
}
zoomRange=
{
zoomRange
}
/>
)
}
</
Flex
>
...
...
ui/shared/chart/ChartWidgetContent.tsx
View file @
e22db695
...
...
@@ -2,6 +2,7 @@ import { Box, Center, Flex, Link, Skeleton, Text } from '@chakra-ui/react';
import
React
from
'
react
'
;
import
type
{
TimeChartItem
}
from
'
./types
'
;
import
type
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
{
apos
}
from
'
lib/html-entities
'
;
...
...
@@ -15,10 +16,11 @@ export type Props = {
isLoading
?:
boolean
;
isError
?:
boolean
;
emptyText
?:
string
;
handleZoom
:
()
=>
void
;
isZoomResetInitial
:
boolean
;
zoomRange
?:
[
Date
,
Date
]
;
handleZoom
:
(
range
:
[
Date
,
Date
])
=>
void
;
isEnlarged
?:
boolean
;
noAnimation
?:
boolean
;
resolution
?:
Resolution
;
}
const
ChartWidgetContent
=
({
...
...
@@ -28,10 +30,11 @@ const ChartWidgetContent = ({
isError
,
units
,
emptyText
,
zoomRange
,
handleZoom
,
isZoomResetInitial
,
isEnlarged
,
noAnimation
,
resolution
,
}:
Props
)
=>
{
const
hasItems
=
items
&&
items
.
length
>
2
;
...
...
@@ -71,12 +74,13 @@ const ChartWidgetContent = ({
<
Box
flexGrow=
{
1
}
maxW=
"100%"
position=
"relative"
h=
"100%"
>
<
ChartWidgetGraph
items=
{
items
}
zoomRange=
{
zoomRange
}
onZoom=
{
handleZoom
}
isZoomResetInitial=
{
isZoomResetInitial
}
title=
{
title
}
units=
{
units
}
isEnlarged=
{
isEnlarged
}
noAnimation=
{
noAnimation
}
resolution=
{
resolution
}
/>
<
WatermarkIcon
w=
"162px"
h=
"15%"
/>
</
Box
>
...
...
ui/shared/chart/ChartWidgetGraph.tsx
View file @
e22db695
...
...
@@ -2,9 +2,9 @@ import { useToken } from '@chakra-ui/react';
import
*
as
d3
from
'
d3
'
;
import
React
from
'
react
'
;
import
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
type
{
ChartMargin
,
TimeChartData
,
TimeChartItem
}
from
'
ui/shared/chart/types
'
;
import
dayjs
from
'
lib/date/dayjs
'
;
import
useIsMobile
from
'
lib/hooks/useIsMobile
'
;
import
ChartArea
from
'
ui/shared/chart/ChartArea
'
;
import
ChartAxis
from
'
ui/shared/chart/ChartAxis
'
;
...
...
@@ -20,37 +20,42 @@ interface Props {
title
:
string
;
units
?:
string
;
items
:
Array
<
TimeChartItem
>
;
onZoom
:
()
=>
void
;
isZoomResetInitial
:
boolean
;
zoomRange
?:
[
Date
,
Date
]
;
onZoom
:
(
range
:
[
Date
,
Date
])
=>
void
;
margin
?:
ChartMargin
;
noAnimation
?:
boolean
;
resolution
?:
Resolution
;
}
// temporarily turn off the data aggregation, we need a better algorithm for that
const
MAX_SHOW_ITEMS
=
100
_000_000_000
;
const
DEFAULT_CHART_MARGIN
=
{
bottom
:
20
,
left
:
10
,
right
:
20
,
top
:
10
};
const
ChartWidgetGraph
=
({
isEnlarged
,
items
,
onZoom
,
isZoomResetInitial
,
title
,
margin
:
marginProps
,
units
,
noAnimation
}:
Props
)
=>
{
const
ChartWidgetGraph
=
({
isEnlarged
,
items
,
onZoom
,
title
,
margin
:
marginProps
,
units
,
noAnimation
,
resolution
,
zoomRange
,
}:
Props
)
=>
{
const
isMobile
=
useIsMobile
();
const
color
=
useToken
(
'
colors
'
,
'
blue.200
'
);
const
chartId
=
`chart-
${
title
.
split
(
'
'
).
join
(
''
)
}
-
${
isEnlarged
?
'
fullscreen
'
:
'
small
'
}
`
;
const
overlayRef
=
React
.
useRef
<
SVGRectElement
>
(
null
);
const
[
range
,
setRange
]
=
React
.
useState
<
[
Date
,
Date
]
>
([
items
[
0
].
date
,
items
[
items
.
length
-
1
].
date
]);
const
range
=
React
.
useMemo
(()
=>
zoomRange
||
[
items
[
0
].
date
,
items
[
items
.
length
-
1
].
date
],
[
zoomRange
,
items
]);
const
rangedItems
=
React
.
useMemo
(()
=>
items
.
filter
((
item
)
=>
item
.
date
>=
range
[
0
]
&&
item
.
date
<=
range
[
1
]),
[
items
,
range
]);
const
isGroupedValues
=
rangedItems
.
length
>
MAX_SHOW_ITEMS
;
const
displayedData
=
React
.
useMemo
(()
=>
{
if
(
isGroupedValues
)
{
return
groupChartItemsByWeekNumber
(
rangedItems
);
}
else
{
return
rangedItems
;
}
},
[
isGroupedValues
,
rangedItems
]);
const
displayedData
=
React
.
useMemo
(()
=>
items
.
filter
((
item
)
=>
item
.
date
>=
range
[
0
]
&&
item
.
date
<=
range
[
1
])
.
map
((
item
)
=>
({
...
item
,
dateLabel
:
getDateLabel
(
item
.
date
,
item
.
date_to
,
resolution
),
})),
[
items
,
range
,
resolution
]);
const
chartData
:
TimeChartData
=
React
.
useMemo
(()
=>
([
{
items
:
displayedData
,
name
:
'
Value
'
,
color
,
units
}
]),
[
color
,
displayedData
,
units
]);
...
...
@@ -80,17 +85,6 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
axesConfig
,
});
const
handleRangeSelect
=
React
.
useCallback
((
nextRange
:
[
Date
,
Date
])
=>
{
setRange
([
nextRange
[
0
],
nextRange
[
1
]
]);
onZoom
();
},
[
onZoom
]);
React
.
useEffect
(()
=>
{
if
(
isZoomResetInitial
)
{
setRange
([
items
[
0
].
date
,
items
[
items
.
length
-
1
].
date
]);
}
},
[
isZoomResetInitial
,
items
]);
return
(
<
svg
width=
"100%"
height=
"100%"
ref=
{
ref
}
cursor=
"pointer"
id=
{
chartId
}
opacity=
{
rect
?
1
:
0
}
>
...
...
@@ -143,12 +137,13 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
<
ChartTooltip
anchorEl=
{
overlayRef
.
current
}
width=
{
innerWidth
}
tooltipWidth=
{
isGroupedValues
?
280
:
200
}
tooltipWidth=
{
(
resolution
===
Resolution
.
WEEK
)
?
280
:
200
}
height=
{
innerHeight
}
xScale=
{
axes
.
x
.
scale
}
yScale=
{
axes
.
y
.
scale
}
data=
{
chartData
}
noAnimation=
{
noAnimation
}
resolution=
{
resolution
}
/>
<
ChartSelectionX
...
...
@@ -156,7 +151,7 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
height=
{
innerHeight
}
scale=
{
axes
.
x
.
scale
}
data=
{
chartData
}
onSelect=
{
handleRangeSelect
}
onSelect=
{
onZoom
}
/>
</
ChartOverlay
>
</
g
>
...
...
@@ -166,13 +161,15 @@ const ChartWidgetGraph = ({ isEnlarged, items, onZoom, isZoomResetInitial, title
export
default
React
.
memo
(
ChartWidgetGraph
);
function
groupChartItemsByWeekNumber
(
items
:
Array
<
TimeChartItem
>
):
Array
<
TimeChartItem
>
{
return
d3
.
rollups
(
items
,
(
group
)
=>
({
date
:
group
[
0
].
date
,
value
:
d3
.
sum
(
group
,
(
d
)
=>
d
.
value
),
dateLabel
:
`
${
d3
.
timeFormat
(
'
%e %b %Y
'
)(
group
[
0
].
date
)
}
–
${
d3
.
timeFormat
(
'
%e %b %Y
'
)(
group
[
group
.
length
-
1
].
date
)
}
`
,
}),
(
t
)
=>
`
${
dayjs
(
t
.
date
).
week
()
}
/
${
dayjs
(
t
.
date
).
year
()
}
`
,
).
map
(([
,
v
])
=>
v
);
function
getDateLabel
(
date
:
Date
,
dateTo
?:
Date
,
resolution
?:
Resolution
):
string
{
switch
(
resolution
)
{
case
Resolution
.
WEEK
:
return
d3
.
timeFormat
(
'
%e %b %Y
'
)(
date
)
+
(
dateTo
?
` –
${
d3
.
timeFormat
(
'
%e %b %Y
'
)(
dateTo
)
}
`
:
''
);
case
Resolution
.
MONTH
:
return
d3
.
timeFormat
(
'
%b %Y
'
)(
date
);
case
Resolution
.
YEAR
:
return
d3
.
timeFormat
(
'
%Y
'
)(
date
);
default
:
return
d3
.
timeFormat
(
'
%e %b %Y
'
)(
date
);
}
}
ui/shared/chart/FullscreenChartModal.tsx
View file @
e22db695
import
{
Box
,
Button
,
Grid
,
Heading
,
Modal
,
ModalBody
,
ModalCloseButton
,
ModalContent
,
ModalOverlay
,
Text
}
from
'
@chakra-ui/react
'
;
import
React
,
{
useCallback
}
from
'
react
'
;
import
React
from
'
react
'
;
import
type
{
TimeChartItem
}
from
'
./types
'
;
import
type
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
IconSvg
from
'
ui/shared/IconSvg
'
;
...
...
@@ -14,6 +15,10 @@ type Props = {
items
:
Array
<
TimeChartItem
>
;
onClose
:
()
=>
void
;
units
?:
string
;
resolution
?:
Resolution
;
zoomRange
?:
[
Date
,
Date
];
handleZoom
:
(
range
:
[
Date
,
Date
])
=>
void
;
handleZoomReset
:
()
=>
void
;
}
const
FullscreenChartModal
=
({
...
...
@@ -23,17 +28,11 @@ const FullscreenChartModal = ({
items
,
units
,
onClose
,
resolution
,
zoomRange
,
handleZoom
,
handleZoomReset
,
}:
Props
)
=>
{
const
[
isZoomResetInitial
,
setIsZoomResetInitial
]
=
React
.
useState
(
true
);
const
handleZoom
=
useCallback
(()
=>
{
setIsZoomResetInitial
(
false
);
},
[]);
const
handleZoomReset
=
useCallback
(()
=>
{
setIsZoomResetInitial
(
true
);
},
[]);
return
(
<
Modal
isOpen=
{
isOpen
}
...
...
@@ -69,7 +68,7 @@ const FullscreenChartModal = ({
</
Text
>
)
}
{
!
isZoomResetInitial
&&
(
{
Boolean
(
zoomRange
)
&&
(
<
Button
leftIcon=
{
<
IconSvg
name=
"repeat"
w=
{
4
}
h=
{
4
}
/>
}
colorScheme=
"blue"
...
...
@@ -98,8 +97,9 @@ const FullscreenChartModal = ({
items=
{
items
}
units=
{
units
}
handleZoom=
{
handleZoom
}
isZoomResetInitial=
{
isZoomResetInitial
}
zoomRange=
{
zoomRange
}
title=
{
title
}
resolution=
{
resolution
}
/>
</
ModalBody
>
</
ModalContent
>
...
...
ui/shared/chart/tooltip/ChartTooltipTitle.tsx
View file @
e22db695
...
...
@@ -2,10 +2,15 @@ import { useToken } from '@chakra-ui/react';
import
*
as
d3
from
'
d3
'
;
import
React
from
'
react
'
;
import
{
Resolution
}
from
'
@blockscout/stats-types
'
;
import
{
STATS_RESOLUTIONS
}
from
'
ui/stats/constants
'
;
import
ChartTooltipRow
from
'
./ChartTooltipRow
'
;
const
ChartTooltipTitle
=
()
=>
{
const
ChartTooltipTitle
=
(
{
resolution
=
Resolution
.
DAY
}:
{
resolution
?:
Resolution
}
)
=>
{
const
titleColor
=
useToken
(
'
colors
'
,
'
yellow.300
'
);
const
resolutionTitle
=
STATS_RESOLUTIONS
.
find
(
r
=>
r
.
id
===
resolution
)?.
title
||
'
day
'
;
return
(
<
ChartTooltipRow
lineNum=
{
0
}
>
...
...
@@ -16,7 +21,7 @@ const ChartTooltipTitle = () => {
opacity=
{
0
}
dominantBaseline=
"hanging"
>
Incomplete day
{
`Incomplete ${ resolutionTitle.toLowerCase() }`
}
</
text
>
</
ChartTooltipRow
>
);
...
...
ui/shared/chart/types.tsx
View file @
e22db695
...
...
@@ -6,6 +6,7 @@ export interface TimeChartItemRaw {
export
interface
TimeChartItem
{
date
:
Date
;
date_to
?:
Date
;
dateLabel
?:
string
;
value
:
number
;
isApproximate
?:
boolean
;
...
...
ui/shared/chart/useChartQuery.tsx
View file @
e22db695
...
...
@@ -50,7 +50,7 @@ export default function useChartQuery(id: string, resolution: Resolution, interv
},
[
info
,
lineQuery
.
data
?.
info
,
lineQuery
.
isPlaceholderData
]);
const
items
=
React
.
useMemo
(()
=>
lineQuery
.
data
?.
chart
?.
map
((
item
)
=>
{
return
{
date
:
new
Date
(
item
.
date
),
value
:
Number
(
item
.
value
),
isApproximate
:
item
.
is_approximate
};
return
{
date
:
new
Date
(
item
.
date
),
date_to
:
new
Date
(
item
.
date_to
),
value
:
Number
(
item
.
value
),
isApproximate
:
item
.
is_approximate
};
}),
[
lineQuery
]);
return
{
...
...
ui/shared/chart/useZoom
Reset
.tsx
→
ui/shared/chart/useZoom.tsx
View file @
e22db695
import
React
from
'
react
'
;
export
default
function
useZoom
Reset
()
{
export
default
function
useZoom
()
{
const
[
isZoomResetInitial
,
setIsZoomResetInitial
]
=
React
.
useState
(
true
);
const
[
zoomRange
,
setZoomRange
]
=
React
.
useState
<
[
Date
,
Date
]
|
undefined
>
();
const
handleZoom
=
React
.
useCallback
(()
=>
{
const
handleZoom
=
React
.
useCallback
((
range
:
[
Date
,
Date
])
=>
{
setZoomRange
(
range
);
setIsZoomResetInitial
(
false
);
},
[]);
const
handleZoomReset
=
React
.
useCallback
(()
=>
{
setZoomRange
(
undefined
);
setIsZoomResetInitial
(
true
);
},
[]);
return
{
isZoomResetInitial
,
zoomRange
,
handleZoom
,
handleZoomReset
,
};
...
...
ui/shared/tagGroupSelect/TagGroupSelect.tsx
View file @
e22db695
...
...
@@ -47,6 +47,8 @@ const TagGroupSelect = <T extends string>({ items, value, isMulti, onChange, tag
cursor=
"pointer"
onClick=
{
onItemClick
}
size=
{
tagSize
}
display=
"inline-flex"
justifyContent=
"center"
>
{
item
.
title
}
</
Tag
>
...
...
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