mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Merge branch 'main' of github.com:blockscout/frontend into client-api-calls-pt2
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 3c0-.184.15-.333.333-.333h4.334v2c0 .368.298.666.666.666h2v1.334h1.334v-.92c0-.441-.176-.865-.489-1.178L9.431 1.822a1.667 1.667 0 0 0-1.179-.489H4.333c-.92 0-1.666.747-1.666 1.667v3.667H4V3Zm0 10v-1H2.667v1c0 .92.746 1.667 1.666 1.667H11c.92 0 1.667-.746 1.667-1.667v-1h-1.334v1a.333.333 0 0 1-.333.333H4.333A.333.333 0 0 1 4 13Zm1.167-5.833H4.75c-.575 0-1.042.466-1.042 1.041v2.084c0 .575.466 1.041 1.042 1.041h.417a1.04 1.04 0 0 0 1.041-1.041v-.209a.418.418 0 0 0-.416-.416.418.418 0 0 0-.417.416v.209a.209.209 0 0 1-.208.208H4.75a.209.209 0 0 1-.208-.208V8.208c0-.114.093-.208.208-.208h.417a.21.21 0 0 1 .208.208v.209a.417.417 0 0 0 .833 0v-.209a1.04 1.04 0 0 0-1.041-1.041Zm2.666 0a1.21 1.21 0 0 0-.599 2.258l.662.377a.375.375 0 0 1-.188.7h-.666a.418.418 0 0 0-.417.417c0 .23.188.417.417.417h.666a1.21 1.21 0 0 0 .6-2.258l-.662-.377a.375.375 0 0 1 .188-.7h.458a.418.418 0 0 0 0-.833h-.459Zm2.125.416v.823c0 .6.144 1.188.417 1.719a3.737 3.737 0 0 0 .417-1.719v-.823a.417.417 0 0 1 .833 0v.823a4.58 4.58 0 0 1-.77 2.542l-.134.2a.415.415 0 0 1-.692 0l-.133-.2a4.58 4.58 0 0 1-.771-2.542v-.823a.417.417 0 0 1 .833 0Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,19 @@
|
||||
import { unparse } from 'papaparse';
|
||||
|
||||
export default function saveAsCSV(headerRows: Array<string>, dataRows: Array<Array<string>>, filename: string) {
|
||||
const csv = unparse([
|
||||
headerRows,
|
||||
...dataRows,
|
||||
]);
|
||||
|
||||
const blob = new Blob([ csv ], { type: 'text/csv;charset=utf-8;' });
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', filename);
|
||||
link.click();
|
||||
|
||||
link.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
@@ -37,6 +37,7 @@
|
||||
"@sentry/tracing": "^7.24.0",
|
||||
"@tanstack/react-query": "^4.0.10",
|
||||
"@tanstack/react-query-devtools": "^4.0.10",
|
||||
"@types/papaparse": "^5.3.5",
|
||||
"@types/react-scroll": "^1.8.4",
|
||||
"bignumber.js": "^9.1.0",
|
||||
"d3": "^7.6.1",
|
||||
@@ -48,6 +49,7 @@
|
||||
"lodash": "^4.0.0",
|
||||
"next": "12.2.5",
|
||||
"node-fetch": "^3.2.9",
|
||||
"papaparse": "^5.3.2",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"phoenix": "^1.6.15",
|
||||
"pino-http": "^8.2.1",
|
||||
|
||||
@@ -5,9 +5,12 @@ import React, { useRef, useCallback, useState } from 'react';
|
||||
import type { TimeChartItem } from './types';
|
||||
|
||||
import imageIcon from 'icons/image.svg';
|
||||
import repeatArrow from 'icons/repeat_arrow.svg';
|
||||
import repeatArrowIcon from 'icons/repeat_arrow.svg';
|
||||
import scopeIcon from 'icons/scope.svg';
|
||||
import svgFileIcon from 'icons/svg_file.svg';
|
||||
import dotsIcon from 'icons/vertical_dots.svg';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
import saveAsCSV from 'lib/saveAsCSV';
|
||||
|
||||
import ChartWidgetGraph from './ChartWidgetGraph';
|
||||
import ChartWidgetSkeleton from './ChartWidgetSkeleton';
|
||||
@@ -40,18 +43,10 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Prop
|
||||
|
||||
const showChartFullscreen = useCallback(() => {
|
||||
setIsFullscreen(true);
|
||||
|
||||
if (!document.fullscreenElement && document.documentElement.requestFullscreen) {
|
||||
document.documentElement.requestFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const clearFullscreenChart = useCallback(() => {
|
||||
setIsFullscreen(false);
|
||||
|
||||
if (document.fullscreenElement) {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleFileSaveClick = useCallback(() => {
|
||||
@@ -78,6 +73,19 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Prop
|
||||
}
|
||||
}, [ title ]);
|
||||
|
||||
const handleSVGSavingClick = useCallback(() => {
|
||||
if (items) {
|
||||
const headerRows = [
|
||||
'Date', 'Value',
|
||||
];
|
||||
const dataRows = items.map((item) => [
|
||||
dayjs(item.date).format('YYYY-MM-DD'), String(item.value),
|
||||
]);
|
||||
|
||||
saveAsCSV(headerRows, dataRows, `${ title } (Blockscout stats)`);
|
||||
}
|
||||
}, [ items, title ]);
|
||||
|
||||
if (isLoading) {
|
||||
return <ChartWidgetSkeleton hasDescription={ Boolean(description) } chartHeight={ chartHeight }/>;
|
||||
}
|
||||
@@ -132,7 +140,7 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Prop
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={ handleZoomResetClick }
|
||||
icon={ <Icon as={ repeatArrow } w={ 4 } h={ 4 }/> }
|
||||
icon={ <Icon as={ repeatArrowIcon } w={ 4 } h={ 4 }/> }
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
@@ -161,6 +169,7 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Prop
|
||||
<Icon as={ scopeIcon } boxSize={ 4 } mr={ 3 }/>
|
||||
View fullscreen
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
@@ -169,6 +178,15 @@ const ChartWidget = ({ items, title, description, isLoading, chartHeight }: Prop
|
||||
<Icon as={ imageIcon } boxSize={ 4 } mr={ 3 }/>
|
||||
Save as PNG
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
onClick={ handleSVGSavingClick }
|
||||
>
|
||||
<Icon as={ svgFileIcon } boxSize={ 4 } mr={ 3 }/>
|
||||
Save as CSV
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Grid>
|
||||
|
||||
+11
-11
@@ -46,19 +46,10 @@ const StatsFilters = ({
|
||||
templateAreas={{
|
||||
base: `"input input"
|
||||
"section interval"`,
|
||||
lg: `"input section interval"`,
|
||||
lg: `"section interval input"`,
|
||||
}}
|
||||
gridTemplateColumns={{ base: 'repeat(2, minmax(0, 1fr))', lg: '1fr auto auto' }}
|
||||
gridTemplateColumns={{ base: 'repeat(2, minmax(0, 1fr))', lg: 'auto auto 1fr' }}
|
||||
>
|
||||
<GridItem
|
||||
w="100%"
|
||||
area="input"
|
||||
>
|
||||
<FilterInput
|
||||
onChange={ onFilterInputChange }
|
||||
placeholder="Find chart, metric..."/>
|
||||
</GridItem>
|
||||
|
||||
<GridItem
|
||||
w={{ base: '100%', lg: 'auto' }}
|
||||
area="section"
|
||||
@@ -80,6 +71,15 @@ const StatsFilters = ({
|
||||
onSelect={ onIntervalChange }
|
||||
/>
|
||||
</GridItem>
|
||||
|
||||
<GridItem
|
||||
w="100%"
|
||||
area="input"
|
||||
>
|
||||
<FilterInput
|
||||
onChange={ onFilterInputChange }
|
||||
placeholder="Find chart, metric..."/>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3588,6 +3588,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.36.tgz#c0d5f2fe76b47b63e0e0efc3d2049a9970d68794"
|
||||
integrity sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==
|
||||
|
||||
"@types/papaparse@^5.3.5":
|
||||
version "5.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.3.5.tgz#e5ad94b1fe98e2a8ea0b03284b83d2cb252bbf39"
|
||||
integrity sha512-R1icl/hrJPFRpuYj9PVG03WBAlghJj4JW9Py5QdR8FFSxaLmZRyu7xYDCCBZIJNfUv3MYaeBbhBoX958mUTAaw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
@@ -7708,6 +7715,11 @@ p-try@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
|
||||
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
|
||||
|
||||
papaparse@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.2.tgz#d1abed498a0ee299f103130a6109720404fbd467"
|
||||
integrity sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==
|
||||
|
||||
parent-module@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
|
||||
|
||||
Reference in New Issue
Block a user