From fda77170b4fa89b8d3c4ed660b5b39f8d6c8de73 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Mon, 5 Jun 2023 20:07:16 -0300 Subject: [PATCH 01/22] feat: implement the payments graph with echarts --- package-lock.json | 122 ++++++++++++++-- package.json | 5 +- src/client/next.config.js | 10 +- .../src/components/chart/BarChartV2.tsx | 132 ++++++++++++++++++ .../home/reports/flow/TransactionGraph.tsx | 7 +- 5 files changed, 259 insertions(+), 17 deletions(-) create mode 100644 src/client/src/components/chart/BarChartV2.tsx diff --git a/package-lock.json b/package-lock.json index e4a5a5f7..8295563f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,8 @@ "d3-time-format": "^4.1.0", "date-fns": "^2.30.0", "dotenv": "^16.0.3", + "echarts": "^5.4.2", + "echarts-for-react": "^3.0.2", "ecpair": "^2.0.1", "graphql": "^16.6.0", "jest-fetch-mock": "^3.0.3", @@ -57,6 +59,7 @@ "lodash": "^4.17.21", "nest-winston": "^1.9.2", "next": "^13.4.4", + "next-transpile-modules": "^10.0.0", "node-fetch": "^3.3.1", "numeral": "^2.0.6", "otplib": "^12.0.1", @@ -10769,6 +10772,33 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/echarts": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.2.tgz", + "integrity": "sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.4.3" + } + }, + "node_modules/echarts-for-react": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz", + "integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "size-sensor": "^1.0.1" + }, + "peerDependencies": { + "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0", + "react": "^15.0.0 || >=16.0.0" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, "node_modules/ecpair": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", @@ -10947,7 +10977,6 @@ "version": "5.14.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12942,8 +12971,7 @@ "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/grammy": { "version": "1.16.1", @@ -17321,6 +17349,15 @@ } } }, + "node_modules/next-transpile-modules": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-10.0.0.tgz", + "integrity": "sha512-FyeJ++Lm2Fq31gbThiRCrJlYpIY9QaI7A3TjuhQLzOix8ChQrvn5ny4MhfIthS5cy6+uK1AhDRvxVdW17y3Xdw==", + "deprecated": "All features of next-transpile-modules are now natively built-in Next.js 13.1. Please use Next's transpilePackages option :)", + "dependencies": { + "enhanced-resolve": "^5.10.0" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -19898,6 +19935,11 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, + "node_modules/size-sensor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.1.tgz", + "integrity": "sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA==" + }, "node_modules/sjcl": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", @@ -21138,7 +21180,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -22498,6 +22539,19 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zrender": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.3.tgz", + "integrity": "sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" } }, "dependencies": { @@ -30750,6 +30804,31 @@ "safe-buffer": "^5.0.1" } }, + "echarts": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.4.2.tgz", + "integrity": "sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.4.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "echarts-for-react": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz", + "integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==", + "requires": { + "fast-deep-equal": "^3.1.3", + "size-sensor": "^1.0.1" + } + }, "ecpair": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", @@ -30885,7 +30964,6 @@ "version": "5.14.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", - "dev": true, "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -32441,8 +32519,7 @@ "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "grammy": { "version": "1.16.1", @@ -35745,6 +35822,14 @@ "zod": "3.21.4" } }, + "next-transpile-modules": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-10.0.0.tgz", + "integrity": "sha512-FyeJ++Lm2Fq31gbThiRCrJlYpIY9QaI7A3TjuhQLzOix8ChQrvn5ny4MhfIthS5cy6+uK1AhDRvxVdW17y3Xdw==", + "requires": { + "enhanced-resolve": "^5.10.0" + } + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -37685,6 +37770,11 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, + "size-sensor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.1.tgz", + "integrity": "sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA==" + }, "sjcl": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.8.tgz", @@ -38618,8 +38708,7 @@ "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "terser": { "version": "5.17.6", @@ -39615,6 +39704,21 @@ "version": "3.21.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==" + }, + "zrender": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.4.3.tgz", + "integrity": "sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==", + "requires": { + "tslib": "2.3.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } } } } diff --git a/package.json b/package.json index c01b52fc..09d33b5c 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,8 @@ "d3-time-format": "^4.1.0", "date-fns": "^2.30.0", "dotenv": "^16.0.3", + "echarts": "^5.4.2", + "echarts-for-react": "^3.0.2", "ecpair": "^2.0.1", "graphql": "^16.6.0", "jest-fetch-mock": "^3.0.3", @@ -82,6 +84,7 @@ "lodash": "^4.17.21", "nest-winston": "^1.9.2", "next": "^13.4.4", + "next-transpile-modules": "^10.0.0", "node-fetch": "^3.3.1", "numeral": "^2.0.6", "otplib": "^12.0.1", @@ -205,4 +208,4 @@ "tag": true } } -} +} \ No newline at end of file diff --git a/src/client/next.config.js b/src/client/next.config.js index 77cf9331..dfab5341 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -2,11 +2,13 @@ const path = require('path'); // eslint-disable-next-line @typescript-eslint/no-var-requires const dotenv = require('dotenv'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const withTM = require('next-transpile-modules')(['echarts', 'zrender']); -dotenv.config({ path: path.resolve(process.cwd(), '.env.local') }); -dotenv.config({ path: path.resolve(process.cwd(), '.env') }); +dotenv.config({path: path.resolve(process.cwd(), '.env.local')}); +dotenv.config({path: path.resolve(process.cwd(), '.env')}); -module.exports = { +module.exports = withTM({ reactStrictMode: true, poweredByHeader: false, basePath: process.env.BASE_PATH || '', @@ -28,4 +30,4 @@ module.exports = { noVersionCheck: process.env.NO_VERSION_CHECK === 'true', logoutUrl: process.env.LOGOUT_URL || '', }, -}; +}); diff --git a/src/client/src/components/chart/BarChartV2.tsx b/src/client/src/components/chart/BarChartV2.tsx new file mode 100644 index 00000000..c4aac9e9 --- /dev/null +++ b/src/client/src/components/chart/BarChartV2.tsx @@ -0,0 +1,132 @@ +import { useContext, useMemo } from 'react'; +import { BarChart } from 'echarts/charts'; +import { + GraphicComponent, + GridComponent, + LegendComponent, + TitleComponent, + ToolboxComponent, + TooltipComponent, +} from 'echarts/components'; +import * as echarts from 'echarts/core'; +import { CanvasRenderer } from 'echarts/renderers'; +import ReactEChartsCore from 'echarts-for-react/lib/core'; +import { ThemeContext } from 'styled-components'; +import numeral from 'numeral'; +import { timeFormat, timeParse } from 'd3-time-format'; + +echarts.use([ + BarChart, + CanvasRenderer, + GridComponent, + TooltipComponent, + GraphicComponent, + TitleComponent, + LegendComponent, + ToolboxComponent, +]); + +interface BarChartProps { + colorRange: string[]; + data: any; + yAxisLabel: string; + title: string; +} + +export const BarChartV2 = ({ + data, + colorRange, + yAxisLabel, + title, +}: BarChartProps) => { + const themeContext = useContext(ThemeContext); + + const seriesData = useMemo(() => { + if (data.length === 0) return { dates: [], series: [] }; + + const series = [ + { + name: title, + type: 'bar', + emphasis: { focus: 'series' }, + data: data.map(d => d.Invoices), + }, + ]; + + const dates = data.map(d => d.date); + + return { dates, series }; + }, [data, title]); + + const option = useMemo(() => { + const fontColor = themeContext.mode === 'light' ? 'black' : 'white'; + + return { + color: colorRange, + legend: { + textStyle: { color: fontColor }, + orient: 'horizontal', + top: 0, + }, + title: { + text: title, + textStyle: { color: fontColor }, + }, + grid: { + containLabel: true, + top: '50px', + left: '100px', + bottom: '0px', + right: '100px', + }, + tooltip: { + trigger: 'axis', + axisPointer: { + animation: false, + }, + }, + xAxis: { + name: 'Dates', + nameLocation: 'center', + nameGap: 32, + type: 'category', + axisLine: { show: true, lineStyle: { color: fontColor } }, + data: seriesData.dates, + axisLabel: { + formatter: function (value: string) { + const parseDate = timeParse('%Y-%m-%dT%H:%M:%S.%L%Z'); + const formatDate = timeFormat('%b %d'); + return formatDate(parseDate(value) as Date); + }, + }, + }, + yAxis: { + name: yAxisLabel, + nameLocation: 'center', + nameGap: 48, + type: 'value', + axisLine: { show: true, lineStyle: { color: fontColor } }, + splitLine: { show: false }, + axisLabel: { + formatter: function (value: number) { + return numeral(value).format('0.0a'); + }, + }, + }, + series: seriesData.series, + }; + }, [yAxisLabel, colorRange, themeContext, seriesData, title]); + + return ( + + ); +}; diff --git a/src/client/src/views/home/reports/flow/TransactionGraph.tsx b/src/client/src/views/home/reports/flow/TransactionGraph.tsx index 4a5532b9..70b8a978 100644 --- a/src/client/src/views/home/reports/flow/TransactionGraph.tsx +++ b/src/client/src/views/home/reports/flow/TransactionGraph.tsx @@ -1,5 +1,4 @@ import { FC, useMemo } from 'react'; -import { BarChart } from '../../../../components/chart/BarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { chartColors } from '../../../../styles/Themes'; import { getByTime } from '../../../../views/dashboard/widgets/helpers'; @@ -7,6 +6,7 @@ import styled from 'styled-components'; import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated'; import { differenceInDays } from 'date-fns'; import { useGetPaymentsQuery } from '../../../../graphql/queries/__generated__/getPayments.generated'; +import { BarChartV2 } from '../../../../components/chart/BarChartV2'; const S = { row: styled.div` @@ -116,8 +116,7 @@ export const TransactionsGraph: FC = ({ return ( - { return { [showPay ? 'Payments' : 'Invoices']: f?.[type] || 0, @@ -125,6 +124,8 @@ export const TransactionsGraph: FC = ({ }; })} colorRange={finalColor} + yAxisLabel={showPay ? '# of Payments' : '# of Invoices'} + title={showPay ? `Payments ${type}` : `Invoices ${type}`} /> From dffe6d12a4414788add020c3785644a153382b58 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Mon, 5 Jun 2023 21:29:20 -0300 Subject: [PATCH 02/22] fix: improve echarts import in next.config.js --- package-lock.json | 30 +++++++++--------------------- package.json | 3 +-- src/client/next.config.js | 7 +++---- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8295563f..c73e3b24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,6 @@ "lodash": "^4.17.21", "nest-winston": "^1.9.2", "next": "^13.4.4", - "next-transpile-modules": "^10.0.0", "node-fetch": "^3.3.1", "numeral": "^2.0.6", "otplib": "^12.0.1", @@ -10977,6 +10976,7 @@ "version": "5.14.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12971,7 +12971,8 @@ "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "node_modules/grammy": { "version": "1.16.1", @@ -17349,15 +17350,6 @@ } } }, - "node_modules/next-transpile-modules": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-10.0.0.tgz", - "integrity": "sha512-FyeJ++Lm2Fq31gbThiRCrJlYpIY9QaI7A3TjuhQLzOix8ChQrvn5ny4MhfIthS5cy6+uK1AhDRvxVdW17y3Xdw==", - "deprecated": "All features of next-transpile-modules are now natively built-in Next.js 13.1. Please use Next's transpilePackages option :)", - "dependencies": { - "enhanced-resolve": "^5.10.0" - } - }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -21180,6 +21172,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -30964,6 +30957,7 @@ "version": "5.14.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "dev": true, "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -32519,7 +32513,8 @@ "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "grammy": { "version": "1.16.1", @@ -35822,14 +35817,6 @@ "zod": "3.21.4" } }, - "next-transpile-modules": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/next-transpile-modules/-/next-transpile-modules-10.0.0.tgz", - "integrity": "sha512-FyeJ++Lm2Fq31gbThiRCrJlYpIY9QaI7A3TjuhQLzOix8ChQrvn5ny4MhfIthS5cy6+uK1AhDRvxVdW17y3Xdw==", - "requires": { - "enhanced-resolve": "^5.10.0" - } - }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -38708,7 +38695,8 @@ "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true }, "terser": { "version": "5.17.6", diff --git a/package.json b/package.json index 09d33b5c..c8b7d2eb 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,6 @@ "lodash": "^4.17.21", "nest-winston": "^1.9.2", "next": "^13.4.4", - "next-transpile-modules": "^10.0.0", "node-fetch": "^3.3.1", "numeral": "^2.0.6", "otplib": "^12.0.1", @@ -208,4 +207,4 @@ "tag": true } } -} \ No newline at end of file +} diff --git a/src/client/next.config.js b/src/client/next.config.js index dfab5341..dd220065 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -2,16 +2,15 @@ const path = require('path'); // eslint-disable-next-line @typescript-eslint/no-var-requires const dotenv = require('dotenv'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const withTM = require('next-transpile-modules')(['echarts', 'zrender']); dotenv.config({path: path.resolve(process.cwd(), '.env.local')}); dotenv.config({path: path.resolve(process.cwd(), '.env')}); -module.exports = withTM({ +module.exports = { reactStrictMode: true, poweredByHeader: false, basePath: process.env.BASE_PATH || '', + transpilePackages: ['echarts', 'echarts-for-react', 'zrender'], compiler: { styledComponents: true, }, @@ -30,4 +29,4 @@ module.exports = withTM({ noVersionCheck: process.env.NO_VERSION_CHECK === 'true', logoutUrl: process.env.LOGOUT_URL || '', }, -}); +}; From 8cf18bb31de91c2614eefd06e6aac60eac962733 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Mon, 5 Jun 2023 21:55:29 -0300 Subject: [PATCH 03/22] fix: formatting --- src/client/next.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/next.config.js b/src/client/next.config.js index dd220065..415c00c8 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -3,8 +3,8 @@ const path = require('path'); // eslint-disable-next-line @typescript-eslint/no-var-requires const dotenv = require('dotenv'); -dotenv.config({path: path.resolve(process.cwd(), '.env.local')}); -dotenv.config({path: path.resolve(process.cwd(), '.env')}); +dotenv.config({ path: path.resolve(process.cwd(), '.env.local') }); +dotenv.config({ path: path.resolve(process.cwd(), '.env') }); module.exports = { reactStrictMode: true, From 1203e52fc8698979dd003088839abb4e7452a082 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 6 Jun 2023 00:03:22 -0300 Subject: [PATCH 04/22] fix: no-implicity-any --- src/client/src/components/chart/BarChartV2.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/src/components/chart/BarChartV2.tsx b/src/client/src/components/chart/BarChartV2.tsx index c4aac9e9..e2dc674b 100644 --- a/src/client/src/components/chart/BarChartV2.tsx +++ b/src/client/src/components/chart/BarChartV2.tsx @@ -49,11 +49,11 @@ export const BarChartV2 = ({ name: title, type: 'bar', emphasis: { focus: 'series' }, - data: data.map(d => d.Invoices), + data: data.map((d: any) => d.Invoices), }, ]; - const dates = data.map(d => d.date); + const dates = data.map((d: any) => d.date); return { dates, series }; }, [data, title]); From be962ca62781d9fec7bcaf17a9a5bebc11941573 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Sun, 11 Jun 2023 14:28:56 -0300 Subject: [PATCH 05/22] fix: tidy up inconsistencies in echarts implementation --- .../src/components/chart/BarChartV2.tsx | 18 +++++---- src/client/src/components/generic/helpers.tsx | 5 ++- .../src/views/dashboard/widgets/helpers.tsx | 12 +++++- .../home/reports/flow/TransactionGraph.tsx | 39 +++++++++++++++---- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/client/src/components/chart/BarChartV2.tsx b/src/client/src/components/chart/BarChartV2.tsx index e2dc674b..6b1d6a93 100644 --- a/src/client/src/components/chart/BarChartV2.tsx +++ b/src/client/src/components/chart/BarChartV2.tsx @@ -14,6 +14,7 @@ import ReactEChartsCore from 'echarts-for-react/lib/core'; import { ThemeContext } from 'styled-components'; import numeral from 'numeral'; import { timeFormat, timeParse } from 'd3-time-format'; +import { getFormatDate } from '../generic/helpers'; echarts.use([ BarChart, @@ -31,6 +32,7 @@ interface BarChartProps { data: any; yAxisLabel: string; title: string; + dataKey: string; } export const BarChartV2 = ({ @@ -38,6 +40,7 @@ export const BarChartV2 = ({ colorRange, yAxisLabel, title, + dataKey, }: BarChartProps) => { const themeContext = useContext(ThemeContext); @@ -49,7 +52,7 @@ export const BarChartV2 = ({ name: title, type: 'bar', emphasis: { focus: 'series' }, - data: data.map((d: any) => d.Invoices), + data: data.map((d: any) => d[dataKey]), }, ]; @@ -63,11 +66,6 @@ export const BarChartV2 = ({ return { color: colorRange, - legend: { - textStyle: { color: fontColor }, - orient: 'horizontal', - top: 0, - }, title: { text: title, textStyle: { color: fontColor }, @@ -84,6 +82,10 @@ export const BarChartV2 = ({ axisPointer: { animation: false, }, + formatter: (params: any) => { + return `Date: ${getFormatDate(params[0].axisValue)}
+ ${params[0].seriesName}: ${params[0].value}
`; + }, }, xAxis: { name: 'Dates', @@ -105,8 +107,10 @@ export const BarChartV2 = ({ nameLocation: 'center', nameGap: 48, type: 'value', - axisLine: { show: true, lineStyle: { color: fontColor } }, + minInterval: 1, splitLine: { show: false }, + axisLine: { show: true, lineStyle: { color: fontColor } }, + axisTick: { show: true }, axisLabel: { formatter: function (value: number) { return numeral(value).format('0.0a'); diff --git a/src/client/src/components/generic/helpers.tsx b/src/client/src/components/generic/helpers.tsx index b1d1944b..0026cd75 100644 --- a/src/client/src/components/generic/helpers.tsx +++ b/src/client/src/components/generic/helpers.tsx @@ -160,10 +160,11 @@ export const getPastFutureStr = ( }; export const getFormatDate = ( - date: string | null | undefined + date: string | null | undefined, + style?: string ): string | null => { if (!date) return null; - return format(new Date(date), 'dd/MM/yyyy - HH:mm:ss'); + return format(new Date(date), style || 'dd/MM/yyyy - HH:mm:ss'); }; export const getMessageDate = ( diff --git a/src/client/src/views/dashboard/widgets/helpers.tsx b/src/client/src/views/dashboard/widgets/helpers.tsx index 4f2faab3..abd5b534 100644 --- a/src/client/src/views/dashboard/widgets/helpers.tsx +++ b/src/client/src/views/dashboard/widgets/helpers.tsx @@ -12,6 +12,8 @@ import { widgetList, WidgetProps } from './widgetList'; import { GetInvoicesQuery } from '../../../graphql/queries/__generated__/getInvoices.generated'; import { GetPaymentsQuery } from '../../../graphql/queries/__generated__/getPayments.generated'; +const ONE_WEEK = 7; + const getColumns = (width: number): number => { const { lg, md, sm, xs } = defaultGrid.breakpoints; @@ -82,12 +84,14 @@ export const getByTime = (array: ArrayType, time: number): any[] => { fee?: number; }[] = []; + // check to see if we're working in days (isDay = false) or hours (isDay = true) const isDay = time <= 1; const today = isDay ? new Date().setMinutes(0, 0, 0) : new Date().setHours(0, 0, 0, 0); + // Look through each transaction in the array and build an array of transactions with the difference between today and the day (or hour) that the tx occurred array.forEach((transaction: ArrayType[0]) => { if (!transaction?.__typename) return; @@ -149,10 +153,16 @@ export const getByTime = (array: ArrayType, time: number): any[] => { if (!transactions?.length) return []; + // Group the transactionw in the array according to the 'difference' property of the object const grouped = groupBy(transactions, 'difference'); const final: any[] = []; - const differences = Array.from({ length: isDay ? 24 : time }, (_, i) => i); + + // If were working with a single day, divide the array in 24 pieces, one for each hour, otherwise, go back 7 days + const differences = Array.from( + { length: isDay ? 24 : ONE_WEEK }, + (_, i) => i + ); differences.forEach(key => { const group = grouped[key]; diff --git a/src/client/src/views/home/reports/flow/TransactionGraph.tsx b/src/client/src/views/home/reports/flow/TransactionGraph.tsx index 70b8a978..caa44392 100644 --- a/src/client/src/views/home/reports/flow/TransactionGraph.tsx +++ b/src/client/src/views/home/reports/flow/TransactionGraph.tsx @@ -48,12 +48,29 @@ export const TransactionsGraph: FC = ({ showPay, type, }) => { - const { data, loading } = useGetInvoicesQuery(); + const { data: invoiceData, loading } = useGetInvoicesQuery(); const { data: paymentsData, loading: paymentsLoading } = useGetPaymentsQuery(); + const labels = useMemo(() => { + switch (type) { + case 'amount': + return { + yAxisLabel: `# of ${showPay ? 'Payments' : 'Invoices'}`, + title: `# of ${showPay ? 'Payments' : 'Invoices'}`, + }; + case 'tokens': + return { + yAxisLabel: `${showPay ? 'Payments' : 'Invoices'} Volume`, + title: `${showPay ? 'Payments' : 'Invoices'} Volume`, + }; + default: + return {}; + } + }, [type, showPay]); + const invoicesByDate = useMemo(() => { - const invoices = data?.getInvoices.invoices || []; + const invoices = invoiceData?.getInvoices.invoices || []; const filtered = invoices.filter(i => !!i.is_confirmed); if (!filtered.length) { @@ -70,7 +87,7 @@ export const TransactionsGraph: FC = ({ const invoicesByDate = getByTime(filtered, difference); return invoicesByDate; - }, [data]); + }, [invoiceData, showPay]); const paymentsByDate = useMemo(() => { const payments = paymentsData?.getPayments.payments || []; @@ -90,7 +107,7 @@ export const TransactionsGraph: FC = ({ const paymentsByDate = getByTime(filtered, difference); return paymentsByDate; - }, [paymentsData]); + }, [paymentsData, showPay]); if (loading || paymentsLoading) { return ( @@ -102,10 +119,15 @@ export const TransactionsGraph: FC = ({ ); } - if (!data?.getInvoices.invoices.length) { + if ( + (!showPay && !invoiceData?.getInvoices.invoices.length) || + (showPay && !paymentsData?.getPayments.payments.length) + ) { return ( - No transactions for this period. + + No {showPay ? 'payments' : 'invoices'} for this period. + ); } @@ -124,8 +146,9 @@ export const TransactionsGraph: FC = ({ }; })} colorRange={finalColor} - yAxisLabel={showPay ? '# of Payments' : '# of Invoices'} - title={showPay ? `Payments ${type}` : `Invoices ${type}`} + yAxisLabel={labels.yAxisLabel || ''} + title={labels.title || ''} + dataKey={showPay ? 'Payments' : 'Invoices'} /> From 79b48493f198249443b6444193647232c2cb86a6 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 13 Jun 2023 12:48:07 -0300 Subject: [PATCH 06/22] feat: improve a number of aspects about echarts implementation as per suggestions --- src/client/src/components/chart/BarChartV2.tsx | 12 +++++------- src/client/src/components/generic/helpers.tsx | 2 +- .../src/views/home/reports/flow/TransactionGraph.tsx | 9 ++++----- src/client/src/views/home/reports/flow/index.tsx | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/client/src/components/chart/BarChartV2.tsx b/src/client/src/components/chart/BarChartV2.tsx index 6b1d6a93..25aec8f0 100644 --- a/src/client/src/components/chart/BarChartV2.tsx +++ b/src/client/src/components/chart/BarChartV2.tsx @@ -15,6 +15,7 @@ import { ThemeContext } from 'styled-components'; import numeral from 'numeral'; import { timeFormat, timeParse } from 'd3-time-format'; import { getFormatDate } from '../generic/helpers'; +import { formatSats } from '../../utils/helpers'; echarts.use([ BarChart, @@ -30,7 +31,6 @@ echarts.use([ interface BarChartProps { colorRange: string[]; data: any; - yAxisLabel: string; title: string; dataKey: string; } @@ -38,7 +38,6 @@ interface BarChartProps { export const BarChartV2 = ({ data, colorRange, - yAxisLabel, title, dataKey, }: BarChartProps) => { @@ -73,9 +72,9 @@ export const BarChartV2 = ({ grid: { containLabel: true, top: '50px', - left: '100px', + left: '25px', bottom: '0px', - right: '100px', + right: '25px', }, tooltip: { trigger: 'axis', @@ -84,7 +83,7 @@ export const BarChartV2 = ({ }, formatter: (params: any) => { return `Date: ${getFormatDate(params[0].axisValue)}
- ${params[0].seriesName}: ${params[0].value}
`; + ${params[0].seriesName}: ${formatSats(params[0].value)}
`; }, }, xAxis: { @@ -103,7 +102,6 @@ export const BarChartV2 = ({ }, }, yAxis: { - name: yAxisLabel, nameLocation: 'center', nameGap: 48, type: 'value', @@ -119,7 +117,7 @@ export const BarChartV2 = ({ }, series: seriesData.series, }; - }, [yAxisLabel, colorRange, themeContext, seriesData, title]); + }, [colorRange, themeContext, seriesData, title]); return ( { if (!date) return null; - return format(new Date(date), style || 'dd/MM/yyyy - HH:mm:ss'); + return format(new Date(date), style || 'yyyy.MM.dd - HH:mm:ss'); }; export const getMessageDate = ( diff --git a/src/client/src/views/home/reports/flow/TransactionGraph.tsx b/src/client/src/views/home/reports/flow/TransactionGraph.tsx index caa44392..3b831c22 100644 --- a/src/client/src/views/home/reports/flow/TransactionGraph.tsx +++ b/src/client/src/views/home/reports/flow/TransactionGraph.tsx @@ -56,13 +56,13 @@ export const TransactionsGraph: FC = ({ switch (type) { case 'amount': return { - yAxisLabel: `# of ${showPay ? 'Payments' : 'Invoices'}`, - title: `# of ${showPay ? 'Payments' : 'Invoices'}`, + yAxisLabel: `Amount of ${showPay ? 'Payments' : 'Invoices'}`, + title: `Amount of ${showPay ? 'Payments' : 'Invoices'}`, }; case 'tokens': return { - yAxisLabel: `${showPay ? 'Payments' : 'Invoices'} Volume`, - title: `${showPay ? 'Payments' : 'Invoices'} Volume`, + yAxisLabel: `${showPay ? 'Payments' : 'Invoices'} Volume (sats)`, + title: `${showPay ? 'Payments' : 'Invoices'} Volume (sats)`, }; default: return {}; @@ -146,7 +146,6 @@ export const TransactionsGraph: FC = ({ }; })} colorRange={finalColor} - yAxisLabel={labels.yAxisLabel || ''} title={labels.title || ''} dataKey={showPay ? 'Payments' : 'Invoices'} /> diff --git a/src/client/src/views/home/reports/flow/index.tsx b/src/client/src/views/home/reports/flow/index.tsx index aaf202ef..34690bfe 100644 --- a/src/client/src/views/home/reports/flow/index.tsx +++ b/src/client/src/views/home/reports/flow/index.tsx @@ -43,7 +43,7 @@ const options = [ const typeOptions = [ { label: 'Count', value: 'amount' }, - { label: 'Amount', value: 'tokens' }, + { label: 'Volume', value: 'tokens' }, ]; export const FlowBox = () => { From 7f17736ffb181015a5e2908027ddf18e74bd6bbb Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 20 Jun 2023 20:52:25 -0300 Subject: [PATCH 07/22] feat: move forwards chart to echarts --- src/client/src/views/dashboard/widgets/helpers.tsx | 2 +- .../src/views/home/reports/forwardReport/ForwardsGraph.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/client/src/views/dashboard/widgets/helpers.tsx b/src/client/src/views/dashboard/widgets/helpers.tsx index abd5b534..b9fd4cee 100644 --- a/src/client/src/views/dashboard/widgets/helpers.tsx +++ b/src/client/src/views/dashboard/widgets/helpers.tsx @@ -160,7 +160,7 @@ export const getByTime = (array: ArrayType, time: number): any[] => { // If were working with a single day, divide the array in 24 pieces, one for each hour, otherwise, go back 7 days const differences = Array.from( - { length: isDay ? 24 : ONE_WEEK }, + { length: isDay ? 24 : time ? time : ONE_WEEK }, (_, i) => i ); diff --git a/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx b/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx index e3efd475..705965fc 100644 --- a/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx +++ b/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { BarChart } from '../../../../components/chart/BarChart'; +import { BarChartV2 } from '../../../../components/chart/BarChartV2'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/getForwards.generated'; import { chartColors } from '../../../../styles/Themes'; @@ -82,13 +82,14 @@ export const ForwardsGraph: FC = ({ days, type }) => { return ( - ({ Forward: f[type.value] || 0, date: f.date, }))} colorRange={[chartColors.purple]} + dataKey="Forward" /> From 6b8aff34107f74b9115bbee8a009d11889936309 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Wed, 21 Jun 2023 11:42:44 -0300 Subject: [PATCH 08/22] chore: move invoice, payment, forward graphs to new BarChart. move liquidityGraph to new HorizontalBarChart --- src/client/src/components/chart/BarChart.tsx | 235 ------------------ .../components/chart/HorizontalBarChartV2.tsx | 142 +++++++++++ .../widgets/lightning/forwardsGraph.tsx | 7 +- .../widgets/lightning/invoiceGraph.tsx | 7 +- .../widgets/lightning/liquidityGraph.tsx | 6 +- .../widgets/lightning/paymentGraph.tsx | 8 +- .../reports/liquidReport/LiquidityGraph.tsx | 18 +- 7 files changed, 166 insertions(+), 257 deletions(-) delete mode 100644 src/client/src/components/chart/BarChart.tsx create mode 100644 src/client/src/components/chart/HorizontalBarChartV2.tsx diff --git a/src/client/src/components/chart/BarChart.tsx b/src/client/src/components/chart/BarChart.tsx deleted file mode 100644 index 1a63c77a..00000000 --- a/src/client/src/components/chart/BarChart.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import { Group } from '@visx/group'; -import { BarGroup } from '@visx/shape'; -import { AxisBottom, AxisLeft } from '@visx/axis'; -import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'; -import { timeParse, timeFormat } from 'd3-time-format'; -import { ParentSize } from '@visx/responsive'; -import { chartColors } from '../../../src/styles/Themes'; -import { ThemeContext } from 'styled-components'; -import { useContext } from 'react'; -import { TooltipWithBounds, defaultStyles, useTooltip } from '@visx/tooltip'; -import { localPoint } from '@visx/event'; -import { Price } from '../price/Price'; - -type BarGroupProps = { - width: number; - height: number; -} & BarChartProps; - -type BarChartProps = { - data: any[]; - margin?: { top: number; right: number; bottom: number; left: number }; - events?: boolean; - colorRange?: string[]; - priceLabel?: boolean; -}; - -const defaultMargin = { top: 40, right: 0, bottom: 40, left: 0 }; -const defaultColorRange = [ - chartColors.green, - chartColors.orange, - chartColors.lightblue, -]; - -const amountOfYTicks = (height: number) => { - switch (true) { - case height < 300: - return 3; - case height < 400: - return 6; - default: - return 10; - } -}; - -const amountOfXTicks = (width: number) => { - switch (true) { - case width < 300: - return 2; - case width < 400: - return 6; - default: - return 10; - } -}; - -const parseDate = timeParse('%Y-%m-%dT%H:%M:%S.%L%Z'); -const formatDate = timeFormat('%b %d'); -const formatTime = timeFormat('%H:%M'); -const tickFormatDate = (date: string) => formatDate(parseDate(date) as Date); -const tickFormatTime = (date: string) => formatTime(parseDate(date) as Date); - -const tooltipStyles = { - ...defaultStyles, - minWidth: 60, - backgroundColor: 'rgba(0,0,0,0.9)', - color: 'white', -}; - -const Chart = ({ - width, - height, - margin = defaultMargin, - data = [], - colorRange = defaultColorRange, - priceLabel, -}: BarGroupProps) => { - const { - tooltipData, - tooltipLeft, - tooltipTop, - tooltipOpen, - showTooltip, - hideTooltip, - } = useTooltip(); - - const themeContext = useContext(ThemeContext); - - const axisColor = themeContext.mode === 'light' ? 'black' : 'white'; - - const keys = Object.keys(data[0] || {}).filter(d => d !== 'date'); - - if (!keys.length) return null; - - let tooltipTimeout: number; - - const getDate = (d: any) => d.date; - - const xScale = scaleBand({ - domain: data.map(getDate), - padding: 0.2, - }); - - const barScale = scaleBand({ - domain: keys, - padding: 0.1, - }); - - const yScale = scaleLinear({ - domain: [ - 0, - Math.max(...data.map(d => Math.max(...keys.map(key => Number(d[key]))))), - ], - }); - - const colorScale = scaleOrdinal({ - domain: keys, - range: colorRange, - }); - - // bounds - const xMax = width - margin.left - margin.right; - const yMax = height - margin.top - margin.bottom; - - // update scale output dimensions - xScale.rangeRound([0, xMax]); - yScale.rangeRound([yMax, 0]); - barScale.rangeRound([0, xScale.bandwidth()]); - - return ( -
- - - - {barGroups => - barGroups.map(barGroup => ( - - {barGroup.bars.map(bar => ( - { - if (tooltipTimeout) clearTimeout(tooltipTimeout); - - const coords = localPoint(e.target.ownerSVGElement, e); - if (!coords) return; - - showTooltip({ - tooltipLeft: coords.x, - tooltipTop: coords.y, - tooltipData: bar, - }); - }} - onMouseLeave={() => { - tooltipTimeout = window.setTimeout(() => { - hideTooltip(); - }, 300); - }} - /> - ))} - - )) - } - - - ({ - fill: axisColor, - fontSize: 11, - textAnchor: 'end', - dy: '0.33em', - dx: '-0.33em', - })} - /> - ({ - fill: axisColor, - fontSize: 11, - textAnchor: 'middle', - })} - /> - - {tooltipOpen && tooltipData ? ( - -
- {tooltipData.key} -
- {priceLabel ? ( - - ) : ( - tooltipData.value - )} -
- ) : null} -
- ); -}; - -export const BarChart = (props: BarChartProps) => ( - - {parent => } - -); diff --git a/src/client/src/components/chart/HorizontalBarChartV2.tsx b/src/client/src/components/chart/HorizontalBarChartV2.tsx new file mode 100644 index 00000000..a2ae8aa5 --- /dev/null +++ b/src/client/src/components/chart/HorizontalBarChartV2.tsx @@ -0,0 +1,142 @@ +import { chartColors } from '../../../src/styles/Themes'; +import { ThemeContext } from 'styled-components'; +import { useContext, useMemo } from 'react'; +import { BarChart } from 'echarts/charts'; +import { + GraphicComponent, + GridComponent, + LegendComponent, + TitleComponent, + ToolboxComponent, + TooltipComponent, +} from 'echarts/components'; +import * as echarts from 'echarts/core'; +import { CanvasRenderer } from 'echarts/renderers'; +import ReactEChartsCore from 'echarts-for-react/lib/core'; + +echarts.use([ + BarChart, + CanvasRenderer, + GridComponent, + TooltipComponent, + GraphicComponent, + TitleComponent, + LegendComponent, + ToolboxComponent, +]); + +type HorizontalBarChartProps = { + data: any[]; + dataKey: string; + colorRange?: string[]; +}; + +const defaultColorRange = [ + chartColors.green, + chartColors.orange, + chartColors.lightblue, +]; + +export const HorizontalBarChartV2 = ({ + data = [], + colorRange = defaultColorRange, + dataKey, +}: HorizontalBarChartProps) => { + const themeContext = useContext(ThemeContext); + + const keys = Object.keys(data[0] || {}).filter(d => d !== 'label'); + + const maxValue = Math.max( + ...data.map(d => Math.max(...keys.map(key => Number(d[key])))) + ); + + const seriesData = useMemo(() => { + if (data.length === 0) return [{ type: 'bar', data: [], barWidth: 25 }]; + + return [ + { + type: 'bar', + data: data.map((d: any) => d[dataKey]), + barWidth: '25', + }, + ]; + }, [data, dataKey]); + + const yLabels = useMemo(() => { + if (!data.length) return []; + return data.map(d => d.label); + }, [data]); + + const option = useMemo(() => { + const themeColor = themeContext.mode === 'light' ? 'black' : 'white'; + + return { + color: colorRange, + grid: { + left: '25px', + bottom: '0px', + right: '25px', + }, + tooltip: { + trigger: 'axis', + axisPointer: { + animation: false, + }, + }, + xAxis: { + max: maxValue * 1.2, + show: false, + }, + yAxis: { + axisPointer: { + show: true, + type: 'none', + triggerTooltip: true, + }, + lineStyle: { + color: themeColor, + type: 'solid', + }, + axisLine: { + onZero: false, + lineStyle: { + color: themeColor, + type: 'solid', + }, + }, + axisLabel: { + inside: true, + interval: 'auto', + }, + axisTick: { + show: true, + alignWithLabel: true, + interval: 'auto', + inside: true, + }, + data: yLabels, + type: 'category', + inverse: true, + max: 5, + position: 'right', + }, + legend: { show: true }, + series: seriesData, + }; + }, [colorRange, themeContext, seriesData, yLabels]); + + if (!keys.length) return null; + + return ( +
+ +
+ ); +}; diff --git a/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx index 4e81e1c1..46b6be21 100644 --- a/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; -import { BarChart } from '../../../../components/chart/BarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { SmallSelectWithValue } from '../../../../components/select'; import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/getForwards.generated'; import { chartColors } from '../../../../styles/Themes'; import styled from 'styled-components'; import { getByTime } from '../helpers'; +import { BarChartV2 } from '../../../../components/chart/BarChartV2'; const S = { row: styled.div` @@ -109,12 +109,13 @@ export const ForwardsGraph = () => {
- ({ Forward: f[type.value] || 0, date: f.date, }))} + dataKey="Forward" + title="Forwards Report" colorRange={[chartColors.purple]} /> diff --git a/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx index a4b07e9f..e7640a5b 100644 --- a/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx @@ -1,5 +1,4 @@ import { useMemo, useState } from 'react'; -import { BarChart } from '../../../../components/chart/BarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { SmallSelectWithValue } from '../../../../components/select'; import { chartColors } from '../../../../styles/Themes'; @@ -7,6 +6,7 @@ import styled from 'styled-components'; import { getByTime } from '../helpers'; import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated'; import { differenceInDays } from 'date-fns'; +import { BarChartV2 } from '../../../../components/chart/BarChartV2'; const S = { row: styled.div` @@ -107,14 +107,15 @@ export const InvoicesGraph = () => {
- { return { Invoices: f?.[type.value] || 0, date: f.date, }; })} + dataKey="Invoices" + title="Invoices" colorRange={[chartColors.orange2]} /> diff --git a/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx index 1bdf43eb..431fbe09 100644 --- a/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx @@ -1,4 +1,4 @@ -import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart'; +import { HorizontalBarChartV2 } from '../../../../components/chart/HorizontalBarChartV2'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { useGetLiquidReportQuery } from '../../../../graphql/queries/__generated__/getChannelReport.generated'; import { chartColors } from '../../../../styles/Themes'; @@ -61,10 +61,10 @@ export const LiquidityGraph = () => { return ( - ); diff --git a/src/client/src/views/dashboard/widgets/lightning/paymentGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/paymentGraph.tsx index ff5b3b85..147ecce7 100644 --- a/src/client/src/views/dashboard/widgets/lightning/paymentGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/paymentGraph.tsx @@ -1,6 +1,4 @@ import { useMemo, useState } from 'react'; - -import { BarChart } from '../../../../components/chart/BarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { SmallSelectWithValue } from '../../../../components/select'; import { chartColors } from '../../../../styles/Themes'; @@ -8,6 +6,7 @@ import styled from 'styled-components'; import { getByTime } from '../helpers'; import { useGetPaymentsQuery } from '../../../../graphql/queries/__generated__/getPayments.generated'; import { differenceInDays } from 'date-fns'; +import { BarChartV2 } from '../../../../components/chart/BarChartV2'; const S = { row: styled.div` @@ -107,8 +106,7 @@ export const PaymentsGraph = () => {
- { return { Payments: f?.[type.value] || 0, @@ -116,6 +114,8 @@ export const PaymentsGraph = () => { }; })} colorRange={[chartColors.darkyellow]} + title="Payments" + dataKey="Payments" /> diff --git a/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx b/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx index ee080177..61e8ad91 100644 --- a/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx +++ b/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx @@ -1,4 +1,3 @@ -import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart'; import { Card, CardWithTitle, @@ -10,6 +9,7 @@ import { useGetLiquidReportQuery } from '../../../../graphql/queries/__generated import { chartColors } from '../../../../styles/Themes'; import styled from 'styled-components'; import { WarningText } from '../../../../views/stats/styles'; +import { HorizontalBarChartV2 } from '../../../../components/chart/HorizontalBarChartV2'; const S = { row: styled.div` @@ -76,11 +76,11 @@ export const LiquidityGraph = () => { } = data.getChannelReport; const liquidity = [ - { label: 'Total Commit', Value: commit }, - { label: 'Max Outgoing', Value: maxOut }, - { label: 'Max Incoming', Value: maxIn }, - { label: 'Local Balance', Value: local }, { label: 'Remote Balance', Value: remote }, + { label: 'Local Balance', Value: local }, + { label: 'Max Incoming', Value: maxIn }, + { label: 'Max Outgoing', Value: maxOut }, + { label: 'Total Commit', Value: commit }, ]; const htlc = [ @@ -95,8 +95,8 @@ export const LiquidityGraph = () => { Liquidity Report - @@ -118,8 +118,8 @@ export const LiquidityGraph = () => { ) : ( - From 6e7f92834ad20c47884afffab656de16aa9a24c3 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Wed, 21 Jun 2023 11:53:00 -0300 Subject: [PATCH 09/22] chore: remove V2 from new graphs --- .../chart/{BarChartV2.tsx => BarChart.tsx} | 6 +- .../components/chart/HorizontalBarChart.tsx | 279 ++++++++---------- .../components/chart/HorizontalBarChartV2.tsx | 142 --------- .../widgets/lightning/forwardsGraph.tsx | 4 +- .../widgets/lightning/invoiceGraph.tsx | 4 +- .../widgets/lightning/liquidityGraph.tsx | 4 +- .../widgets/lightning/paymentGraph.tsx | 4 +- .../home/reports/flow/TransactionGraph.tsx | 4 +- .../reports/forwardReport/ForwardsGraph.tsx | 4 +- .../reports/liquidReport/LiquidityGraph.tsx | 6 +- 10 files changed, 133 insertions(+), 324 deletions(-) rename src/client/src/components/chart/{BarChartV2.tsx => BarChart.tsx} (97%) delete mode 100644 src/client/src/components/chart/HorizontalBarChartV2.tsx diff --git a/src/client/src/components/chart/BarChartV2.tsx b/src/client/src/components/chart/BarChart.tsx similarity index 97% rename from src/client/src/components/chart/BarChartV2.tsx rename to src/client/src/components/chart/BarChart.tsx index 25aec8f0..28ee3852 100644 --- a/src/client/src/components/chart/BarChartV2.tsx +++ b/src/client/src/components/chart/BarChart.tsx @@ -1,5 +1,5 @@ import { useContext, useMemo } from 'react'; -import { BarChart } from 'echarts/charts'; +import { BarChart as EBarChart } from 'echarts/charts'; import { GraphicComponent, GridComponent, @@ -18,7 +18,7 @@ import { getFormatDate } from '../generic/helpers'; import { formatSats } from '../../utils/helpers'; echarts.use([ - BarChart, + EBarChart, CanvasRenderer, GridComponent, TooltipComponent, @@ -35,7 +35,7 @@ interface BarChartProps { dataKey: string; } -export const BarChartV2 = ({ +export const BarChart = ({ data, colorRange, title, diff --git a/src/client/src/components/chart/HorizontalBarChart.tsx b/src/client/src/components/chart/HorizontalBarChart.tsx index 6a4553eb..23f729ec 100644 --- a/src/client/src/components/chart/HorizontalBarChart.tsx +++ b/src/client/src/components/chart/HorizontalBarChart.tsx @@ -1,191 +1,142 @@ -import { Group } from '@visx/group'; -import { BarGroupHorizontal, Bar } from '@visx/shape'; -import { AxisLeft } from '@visx/axis'; -import { scaleBand, scaleLinear, scaleOrdinal } from '@visx/scale'; -import { ParentSize } from '@visx/responsive'; -import { chartColors } from '../../../src/styles/Themes'; +import { chartColors } from '../../styles/Themes'; import { ThemeContext } from 'styled-components'; -import { useContext } from 'react'; -import { TooltipWithBounds, defaultStyles, useTooltip } from '@visx/tooltip'; -import { localPoint } from '@visx/event'; -import { Price } from '../price/Price'; - -type BarGroupProps = { - width: number; - height: number; -} & BarChartProps; - -type BarChartProps = { +import { useContext, useMemo } from 'react'; +import { BarChart } from 'echarts/charts'; +import { + GraphicComponent, + GridComponent, + LegendComponent, + TitleComponent, + ToolboxComponent, + TooltipComponent, +} from 'echarts/components'; +import * as echarts from 'echarts/core'; +import { CanvasRenderer } from 'echarts/renderers'; +import ReactEChartsCore from 'echarts-for-react/lib/core'; + +echarts.use([ + BarChart, + CanvasRenderer, + GridComponent, + TooltipComponent, + GraphicComponent, + TitleComponent, + LegendComponent, + ToolboxComponent, +]); + +type HorizontalBarChartProps = { data: any[]; - margin?: { top: number; right: number; bottom: number; left: number }; - events?: boolean; + dataKey: string; colorRange?: string[]; - priceLabel?: boolean; }; -const defaultMargin = { top: 40, right: 0, bottom: 40, left: 0 }; const defaultColorRange = [ chartColors.green, chartColors.orange, chartColors.lightblue, ]; -const tooltipStyles = { - ...defaultStyles, - minWidth: 60, - backgroundColor: 'rgba(0,0,0,0.9)', - color: 'white', -}; - -const Chart = ({ - width, - height, - margin = defaultMargin, +export const HorizontalBarChart = ({ data = [], colorRange = defaultColorRange, - priceLabel, -}: BarGroupProps) => { - const { - tooltipData, - tooltipLeft, - tooltipTop, - tooltipOpen, - showTooltip, - hideTooltip, - } = useTooltip(); - + dataKey, +}: HorizontalBarChartProps) => { const themeContext = useContext(ThemeContext); - const axisColor = themeContext.mode === 'light' ? 'black' : 'white'; const keys = Object.keys(data[0] || {}).filter(d => d !== 'label'); - if (!keys.length) return null; - const maxValue = Math.max( ...data.map(d => Math.max(...keys.map(key => Number(d[key])))) ); - let tooltipTimeout: number; - - const getLabel = (d: any) => d.label; - - const yScale = scaleBand({ - domain: data.map(getLabel), - }); + const seriesData = useMemo(() => { + if (data.length === 0) return [{ type: 'bar', data: [], barWidth: 25 }]; + + return [ + { + type: 'bar', + data: data.map((d: any) => d[dataKey]), + barWidth: '25', + }, + ]; + }, [data, dataKey]); + + const yLabels = useMemo(() => { + if (!data.length) return []; + return data.map(d => d.label); + }, [data]); + + const option = useMemo(() => { + const themeColor = themeContext.mode === 'light' ? 'black' : 'white'; + + return { + color: colorRange, + grid: { + left: '25px', + bottom: '0px', + right: '25px', + }, + tooltip: { + trigger: 'axis', + axisPointer: { + animation: false, + }, + }, + xAxis: { + max: maxValue * 1.2, + show: false, + }, + yAxis: { + axisPointer: { + show: true, + type: 'none', + triggerTooltip: true, + }, + lineStyle: { + color: themeColor, + type: 'solid', + }, + axisLine: { + onZero: false, + lineStyle: { + color: themeColor, + type: 'solid', + }, + }, + axisLabel: { + inside: true, + interval: 'auto', + }, + axisTick: { + show: true, + alignWithLabel: true, + interval: 'auto', + inside: true, + }, + data: yLabels, + type: 'category', + inverse: true, + max: 5, + position: 'right', + }, + legend: { show: true }, + series: seriesData, + }; + }, [colorRange, themeContext, seriesData, yLabels]); - const barScale = scaleBand({ - domain: keys, - padding: 0.1, - }); - - const xScale = scaleLinear({ - domain: [0, maxValue + 0.1 * maxValue], - }); - - const colorScale = scaleOrdinal({ - domain: keys, - range: colorRange, - }); - - // bounds - const xMax = width - margin.left - margin.right; - const yMax = height - margin.top - margin.bottom; - - // update scale output dimensions - xScale.rangeRound([0, xMax]); - yScale.rangeRound([yMax, 0]); - barScale.rangeRound([0, yScale.bandwidth()]); + if (!keys.length) return null; return ( -
- - - - {barGroups => - barGroups.map(barGroup => ( - - {barGroup.bars.map(bar => ( - { - if (tooltipTimeout) clearTimeout(tooltipTimeout); - - const coords = localPoint(e.target.ownerSVGElement, e); - if (!coords) return; - - showTooltip({ - tooltipLeft: coords.x, - tooltipTop: coords.y, - tooltipData: bar, - }); - }} - onMouseLeave={() => { - tooltipTimeout = window.setTimeout(() => { - hideTooltip(); - }, 300); - }} - /> - ))} - - )) - } - - - ({ - fill: axisColor, - fontSize: 11, - textAnchor: 'end', - dy: '0.33em', - dx: '-0.33em', - })} - /> - - {tooltipOpen && tooltipData ? ( - -
- {tooltipData.key} -
- {priceLabel ? ( - - ) : ( - tooltipData.value - )} -
- ) : null} +
+
); }; - -export const HorizontalBarChart = (props: BarChartProps) => ( - - {parent => } - -); diff --git a/src/client/src/components/chart/HorizontalBarChartV2.tsx b/src/client/src/components/chart/HorizontalBarChartV2.tsx deleted file mode 100644 index a2ae8aa5..00000000 --- a/src/client/src/components/chart/HorizontalBarChartV2.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { chartColors } from '../../../src/styles/Themes'; -import { ThemeContext } from 'styled-components'; -import { useContext, useMemo } from 'react'; -import { BarChart } from 'echarts/charts'; -import { - GraphicComponent, - GridComponent, - LegendComponent, - TitleComponent, - ToolboxComponent, - TooltipComponent, -} from 'echarts/components'; -import * as echarts from 'echarts/core'; -import { CanvasRenderer } from 'echarts/renderers'; -import ReactEChartsCore from 'echarts-for-react/lib/core'; - -echarts.use([ - BarChart, - CanvasRenderer, - GridComponent, - TooltipComponent, - GraphicComponent, - TitleComponent, - LegendComponent, - ToolboxComponent, -]); - -type HorizontalBarChartProps = { - data: any[]; - dataKey: string; - colorRange?: string[]; -}; - -const defaultColorRange = [ - chartColors.green, - chartColors.orange, - chartColors.lightblue, -]; - -export const HorizontalBarChartV2 = ({ - data = [], - colorRange = defaultColorRange, - dataKey, -}: HorizontalBarChartProps) => { - const themeContext = useContext(ThemeContext); - - const keys = Object.keys(data[0] || {}).filter(d => d !== 'label'); - - const maxValue = Math.max( - ...data.map(d => Math.max(...keys.map(key => Number(d[key])))) - ); - - const seriesData = useMemo(() => { - if (data.length === 0) return [{ type: 'bar', data: [], barWidth: 25 }]; - - return [ - { - type: 'bar', - data: data.map((d: any) => d[dataKey]), - barWidth: '25', - }, - ]; - }, [data, dataKey]); - - const yLabels = useMemo(() => { - if (!data.length) return []; - return data.map(d => d.label); - }, [data]); - - const option = useMemo(() => { - const themeColor = themeContext.mode === 'light' ? 'black' : 'white'; - - return { - color: colorRange, - grid: { - left: '25px', - bottom: '0px', - right: '25px', - }, - tooltip: { - trigger: 'axis', - axisPointer: { - animation: false, - }, - }, - xAxis: { - max: maxValue * 1.2, - show: false, - }, - yAxis: { - axisPointer: { - show: true, - type: 'none', - triggerTooltip: true, - }, - lineStyle: { - color: themeColor, - type: 'solid', - }, - axisLine: { - onZero: false, - lineStyle: { - color: themeColor, - type: 'solid', - }, - }, - axisLabel: { - inside: true, - interval: 'auto', - }, - axisTick: { - show: true, - alignWithLabel: true, - interval: 'auto', - inside: true, - }, - data: yLabels, - type: 'category', - inverse: true, - max: 5, - position: 'right', - }, - legend: { show: true }, - series: seriesData, - }; - }, [colorRange, themeContext, seriesData, yLabels]); - - if (!keys.length) return null; - - return ( -
- -
- ); -}; diff --git a/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx index 46b6be21..fa71b0b5 100644 --- a/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/forwardsGraph.tsx @@ -5,7 +5,7 @@ import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/g import { chartColors } from '../../../../styles/Themes'; import styled from 'styled-components'; import { getByTime } from '../helpers'; -import { BarChartV2 } from '../../../../components/chart/BarChartV2'; +import { BarChart } from '../../../../components/chart/BarChart'; const S = { row: styled.div` @@ -109,7 +109,7 @@ export const ForwardsGraph = () => {
- ({ Forward: f[type.value] || 0, date: f.date, diff --git a/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx index e7640a5b..c941b9ba 100644 --- a/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/invoiceGraph.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { getByTime } from '../helpers'; import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated'; import { differenceInDays } from 'date-fns'; -import { BarChartV2 } from '../../../../components/chart/BarChartV2'; +import { BarChart } from '../../../../components/chart/BarChart'; const S = { row: styled.div` @@ -107,7 +107,7 @@ export const InvoicesGraph = () => {
- { return { Invoices: f?.[type.value] || 0, diff --git a/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx b/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx index 431fbe09..ce1ce036 100644 --- a/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx +++ b/src/client/src/views/dashboard/widgets/lightning/liquidityGraph.tsx @@ -1,4 +1,4 @@ -import { HorizontalBarChartV2 } from '../../../../components/chart/HorizontalBarChartV2'; +import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { useGetLiquidReportQuery } from '../../../../graphql/queries/__generated__/getChannelReport.generated'; import { chartColors } from '../../../../styles/Themes'; @@ -61,7 +61,7 @@ export const LiquidityGraph = () => { return ( - {
- { return { Payments: f?.[type.value] || 0, diff --git a/src/client/src/views/home/reports/flow/TransactionGraph.tsx b/src/client/src/views/home/reports/flow/TransactionGraph.tsx index 3b831c22..776258da 100644 --- a/src/client/src/views/home/reports/flow/TransactionGraph.tsx +++ b/src/client/src/views/home/reports/flow/TransactionGraph.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { useGetInvoicesQuery } from '../../../../graphql/queries/__generated__/getInvoices.generated'; import { differenceInDays } from 'date-fns'; import { useGetPaymentsQuery } from '../../../../graphql/queries/__generated__/getPayments.generated'; -import { BarChartV2 } from '../../../../components/chart/BarChartV2'; +import { BarChart } from '../../../../components/chart/BarChart'; const S = { row: styled.div` @@ -138,7 +138,7 @@ export const TransactionsGraph: FC = ({ return ( - { return { [showPay ? 'Payments' : 'Invoices']: f?.[type] || 0, diff --git a/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx b/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx index 705965fc..9cce5e5a 100644 --- a/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx +++ b/src/client/src/views/home/reports/forwardReport/ForwardsGraph.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { BarChartV2 } from '../../../../components/chart/BarChartV2'; +import { BarChart } from '../../../../components/chart/BarChart'; import { LoadingCard } from '../../../../components/loading/LoadingCard'; import { useGetForwardsQuery } from '../../../../graphql/queries/__generated__/getForwards.generated'; import { chartColors } from '../../../../styles/Themes'; @@ -82,7 +82,7 @@ export const ForwardsGraph: FC = ({ days, type }) => { return ( - ({ Forward: f[type.value] || 0, diff --git a/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx b/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx index 61e8ad91..afe18276 100644 --- a/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx +++ b/src/client/src/views/home/reports/liquidReport/LiquidityGraph.tsx @@ -9,7 +9,7 @@ import { useGetLiquidReportQuery } from '../../../../graphql/queries/__generated import { chartColors } from '../../../../styles/Themes'; import styled from 'styled-components'; import { WarningText } from '../../../../views/stats/styles'; -import { HorizontalBarChartV2 } from '../../../../components/chart/HorizontalBarChartV2'; +import { HorizontalBarChart } from '../../../../components/chart/HorizontalBarChart'; const S = { row: styled.div` @@ -95,7 +95,7 @@ export const LiquidityGraph = () => { Liquidity Report - { ) : ( - Date: Wed, 21 Jun 2023 17:19:38 -0300 Subject: [PATCH 10/22] feat: implement Sankey chart for forwards --- src/client/pages/forwards.tsx | 5 + src/client/src/components/sankey/index.tsx | 96 +++++++++++++++++++ .../src/views/forwards/forwardSankey.tsx | 72 ++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 src/client/src/components/sankey/index.tsx create mode 100644 src/client/src/views/forwards/forwardSankey.tsx diff --git a/src/client/pages/forwards.tsx b/src/client/pages/forwards.tsx index 3951efc2..1adc40fa 100644 --- a/src/client/pages/forwards.tsx +++ b/src/client/pages/forwards.tsx @@ -18,6 +18,7 @@ import { CardTitle, Separation, } from '../src/components/generic/Styled'; +import { ForwardSankey } from '../src/views/forwards/forwardSankey'; const S = { options: styled.div` @@ -89,6 +90,10 @@ const ForwardsView = () => { + Sankey + + + )} diff --git a/src/client/src/components/sankey/index.tsx b/src/client/src/components/sankey/index.tsx new file mode 100644 index 00000000..61fbf5b8 --- /dev/null +++ b/src/client/src/components/sankey/index.tsx @@ -0,0 +1,96 @@ +import { useContext, useMemo } from 'react'; +import { + GraphicComponent, + GridComponent, + LegendComponent, + TitleComponent, + ToolboxComponent, + TooltipComponent, +} from 'echarts/components'; +import * as echarts from 'echarts/core'; +import { SankeyChart } from 'echarts/charts'; +import { CanvasRenderer } from 'echarts/renderers'; +import ReactEChartsCore from 'echarts-for-react/lib/core'; +import { ThemeContext } from 'styled-components'; + +echarts.use([ + SankeyChart, + CanvasRenderer, + GridComponent, + TooltipComponent, + GraphicComponent, + TitleComponent, + LegendComponent, + ToolboxComponent, +]); + +export type SankeyProps = { + width: number; + height: number; + data: SankeyData; +}; + +interface SankeyNode { + name: string; +} + +interface SankeyLink { + source: string; + target: string; + value: number; +} + +export interface SankeyData { + links: SankeyLink[]; + nodes: SankeyNode[]; +} + +export const Sankey = ({ data, width, height }: SankeyProps) => { + const themeContext = useContext(ThemeContext); + + const option = useMemo(() => { + const fontColor = themeContext.mode === 'light' ? 'black' : 'white'; + return { + tooltip: { + trigger: 'item', + triggerOn: 'mousemove', + }, + series: [ + { + type: 'sankey', + nodeAlign: 'left', + layoutIterations: 32, + data: data.nodes, + links: data.links, + nodeGap: 100, + dragable: false, + label: { + show: true, + color: fontColor, + }, + emphasis: { + focus: 'adjacency', + }, + lineStyle: { + color: 'gradient', + curveness: 0.25, + }, + itemStyle: { + borderWidth: 50, + }, + }, + ], + }; + }, [data, themeContext]); + + return ( + + ); +}; diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx new file mode 100644 index 00000000..405ef736 --- /dev/null +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -0,0 +1,72 @@ +import React, { useMemo } from 'react'; +import { toast } from 'react-toastify'; +import { getErrorContent } from '../../utils/error'; +import { ParentSize } from '@visx/responsive'; +import styled from 'styled-components'; +import { mediaWidths } from '../../styles/Themes'; +import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated'; +import { Sankey, SankeyData } from '../../components/sankey'; +import { Forward } from '../../graphql/types'; + +const Wrapper = styled.div` + height: 400px; + width: 100%; + + @media (${mediaWidths.mobile}) { + height: 300px; + } +`; + +export const ForwardSankey = ({ days }: { days: number }) => { + const { data, loading } = useGetForwardsQuery({ + ssr: false, + variables: { days }, + onError: error => toast.error(getErrorContent(error)), + }); + + const sankeyData = useMemo(() => { + if (loading || !data || !data.getForwards.length) + return { links: [], nodes: [] }; + const orderedData: SankeyData = { links: [], nodes: [] }; + const nodeArr: string[] = []; + + // We need to put unique nodes in an array for future sorting + data.getForwards.map((forward: Forward) => { + if (nodeArr.indexOf(forward.incoming_channel) === -1) + nodeArr.push(forward.incoming_channel); + if (nodeArr.indexOf(forward.outgoing_channel) === -1) + nodeArr.push(forward.outgoing_channel); + orderedData.links.push({ + source: forward.incoming_channel, + target: forward.outgoing_channel, + value: forward.tokens, + }); + }); + + orderedData.nodes = nodeArr.map(node => { + return { name: node }; + }); + + return orderedData; + }, [data]); + + if (loading || !data?.getForwards?.length) { + return null; + } + + return ( + <> + + + {parent => ( + + )} + + + + ); +}; From 9f52d3609fd22f62f8428b4968dbfcc4560d5346 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Wed, 21 Jun 2023 18:06:07 -0300 Subject: [PATCH 11/22] chore: change justification on Sankey Graph --- src/client/src/components/sankey/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/components/sankey/index.tsx b/src/client/src/components/sankey/index.tsx index 61fbf5b8..83f8dc04 100644 --- a/src/client/src/components/sankey/index.tsx +++ b/src/client/src/components/sankey/index.tsx @@ -58,7 +58,7 @@ export const Sankey = ({ data, width, height }: SankeyProps) => { series: [ { type: 'sankey', - nodeAlign: 'left', + nodeAlign: 'justify', layoutIterations: 32, data: data.nodes, links: data.links, From b7c64d2f704fa18fec3140beff4c013a70771577 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 27 Jun 2023 14:57:53 -0300 Subject: [PATCH 12/22] feat: add Sankey graph --- src/client/src/views/forwards/forwardSankey.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx index 405ef736..c24dfabf 100644 --- a/src/client/src/views/forwards/forwardSankey.tsx +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -9,7 +9,7 @@ import { Sankey, SankeyData } from '../../components/sankey'; import { Forward } from '../../graphql/types'; const Wrapper = styled.div` - height: 400px; + height: 800px; width: 100%; @media (${mediaWidths.mobile}) { @@ -32,13 +32,13 @@ export const ForwardSankey = ({ days }: { days: number }) => { // We need to put unique nodes in an array for future sorting data.getForwards.map((forward: Forward) => { - if (nodeArr.indexOf(forward.incoming_channel) === -1) - nodeArr.push(forward.incoming_channel); - if (nodeArr.indexOf(forward.outgoing_channel) === -1) - nodeArr.push(forward.outgoing_channel); + const source = `source: ${forward.incoming_channel}`; + const target = `target: ${forward.outgoing_channel}`; + if (nodeArr.indexOf(source) === -1) nodeArr.push(source); + if (nodeArr.indexOf(target) === -1) nodeArr.push(target); orderedData.links.push({ - source: forward.incoming_channel, - target: forward.outgoing_channel, + source, + target, value: forward.tokens, }); }); From eac975347de79634c6572d77f29cbc2425928c99 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 27 Jun 2023 15:05:28 -0300 Subject: [PATCH 13/22] chore: remove chord graph --- src/client/pages/forwards.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/client/pages/forwards.tsx b/src/client/pages/forwards.tsx index 1adc40fa..12aebf30 100644 --- a/src/client/pages/forwards.tsx +++ b/src/client/pages/forwards.tsx @@ -4,7 +4,6 @@ import { getProps } from '../src/utils/ssr'; import { ForwardsList } from '../src/views/forwards/index'; import { ForwardChannelsReport } from '../src/views/home/reports/forwardReport/ForwardChannelReport'; import { useState } from 'react'; -import { ForwardChord } from '../src/views/forwards/forwardChord'; import { ForwardTable } from '../src/views/forwards/ForwardTable'; import { options, typeOptions } from '../src/views/home/reports/forwardReport'; import { ForwardsGraph } from '../src/views/home/reports/forwardReport/ForwardsGraph'; @@ -86,10 +85,6 @@ const ForwardsView = () => { - Chord Graph - - - Sankey From 9becda4608f49a4c5fb25676ce17a968ce95cdcf Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 27 Jun 2023 15:18:47 -0300 Subject: [PATCH 14/22] chore: remove chord graph and update package.json --- package-lock.json | 676 +----------------- package.json | 8 - src/client/src/components/chord/index.tsx | 108 --- src/client/src/components/sankey/index.tsx | 4 +- .../src/views/forwards/forwardChord.tsx | 161 ----- .../src/views/forwards/forwardSankey.tsx | 15 +- src/client/src/views/forwards/helpers.tsx | 46 -- 7 files changed, 14 insertions(+), 1004 deletions(-) delete mode 100644 src/client/src/components/chord/index.tsx delete mode 100644 src/client/src/views/forwards/forwardChord.tsx diff --git a/package-lock.json b/package-lock.json index 75013a5a..dbe4b85f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,14 +24,6 @@ "@nestjs/throttler": "^4.0.0", "@nestjs/websockets": "^9.4.2", "@tanstack/react-table": "^8.9.1", - "@visx/axis": "^2.12.2", - "@visx/chord": "^2.10.0", - "@visx/event": "^2.6.0", - "@visx/group": "^2.10.0", - "@visx/responsive": "^2.10.0", - "@visx/scale": "^2.2.2", - "@visx/shape": "^2.12.2", - "@visx/tooltip": "^2.16.0", "apollo-server-express": "^3.12.0", "balanceofsatoshis": "^15.8.2", "bcryptjs": "^2.4.3", @@ -5228,11 +5220,6 @@ "lodash.get": "^4.4.2" } }, - "node_modules/@juggle/resize-observer": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz", - "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" - }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -6556,50 +6543,6 @@ "integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==", "dev": true }, - "node_modules/@types/d3-chord": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz", - "integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg==" - }, - "node_modules/@types/d3-color": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz", - "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==" - }, - "node_modules/@types/d3-interpolate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz", - "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==", - "dependencies": { - "@types/d3-color": "^1" - } - }, - "node_modules/@types/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==" - }, - "node_modules/@types/d3-scale": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz", - "integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==", - "dependencies": { - "@types/d3-time": "^2" - } - }, - "node_modules/@types/d3-shape": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", - "dependencies": { - "@types/d3-path": "^1" - } - }, - "node_modules/@types/d3-time": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz", - "integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg==" - }, "node_modules/@types/d3-time-format": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", @@ -6759,7 +6702,8 @@ "node_modules/@types/lodash": { "version": "4.14.195", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", - "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==" + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true }, "node_modules/@types/long": { "version": "4.0.2", @@ -6878,14 +6822,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-dom": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", - "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-grid-layout": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz", @@ -7257,171 +7193,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@visx/axis": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/@visx/axis/-/axis-2.14.0.tgz", - "integrity": "sha512-/mJuPiAUN/YdatSlXkkXD/8Pb4gVclbucNZkpUk6JVhnrmow0a1x73QiMXKuH2qDO5GDaqQS0C3Ly9lI3qTQ5Q==", - "dependencies": { - "@types/react": "*", - "@visx/group": "2.10.0", - "@visx/point": "2.6.0", - "@visx/scale": "2.2.2", - "@visx/shape": "2.12.2", - "@visx/text": "2.12.2", - "classnames": "^2.3.1", - "prop-types": "^15.6.0" - }, - "peerDependencies": { - "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/bounds": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-2.16.0.tgz", - "integrity": "sha512-KJoSSJt5SOLzprEbmsmdxR46PLudau0kWOgxavrah9D/49RsHwGdUdxHLKdXz4OdCruEfgGo4yxiuYLYmUWl4A==", - "dependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "prop-types": "^15.5.10" - }, - "peerDependencies": { - "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0", - "react-dom": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/chord": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/chord/-/chord-2.10.0.tgz", - "integrity": "sha512-p2ZQ9uiyiXV4Yu9DL+cqKbZbh1umMgCUWTP2CpgwSN5p822QHQjzpe1nafWOmNSLpANIBDDYIbtIgOZXUHkelA==", - "dependencies": { - "@types/d3-chord": "^1.0.9", - "@types/react": "*", - "classnames": "^2.3.1", - "d3-chord": "^1.0.4", - "prop-types": "^15.6.1" - }, - "peerDependencies": { - "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/curve": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-2.1.0.tgz", - "integrity": "sha512-9b6JOnx91gmOQiSPhUOxdsvcnW88fgqfTPKoVgQxidMsD/I3wksixtwo8TR/vtEz2aHzzsEEhlv1qK7Y3yaSDw==", - "dependencies": { - "@types/d3-shape": "^1.3.1", - "d3-shape": "^1.0.6" - } - }, - "node_modules/@visx/event": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@visx/event/-/event-2.6.0.tgz", - "integrity": "sha512-WGp91g82s727g3NAnENF1ppC3ZAlvWg+Y+GG0WFg34NmmOZbvPI/PTOqTqZE3x6B8EUn8NJiMxRjxIMbi+IvRw==", - "dependencies": { - "@types/react": "*", - "@visx/point": "2.6.0" - } - }, - "node_modules/@visx/group": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/group/-/group-2.10.0.tgz", - "integrity": "sha512-DNJDX71f65Et1+UgQvYlZbE66owYUAfcxTkC96Db6TnxV221VKI3T5l23UWbnMzwFBP9dR3PWUjjqhhF12N5pA==", - "dependencies": { - "@types/react": "*", - "classnames": "^2.3.1", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/point": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz", - "integrity": "sha512-amBi7yMz4S2VSchlPdliznN41TuES64506ySI22DeKQ+mc1s1+BudlpnY90sM1EIw4xnqbKmrghTTGfy6SVqvQ==" - }, - "node_modules/@visx/responsive": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-2.10.0.tgz", - "integrity": "sha512-NssDPpuUYp7hqVISuYkKZ5zk6ob0++RdTIaUjRcUdyFEbvzb9+zIb8QToOkvI90L2EC/MY4Jx0NpDbEe79GpAw==", - "dependencies": { - "@juggle/resize-observer": "^3.3.1", - "@types/lodash": "^4.14.172", - "@types/react": "*", - "lodash": "^4.17.21", - "prop-types": "^15.6.1" - }, - "peerDependencies": { - "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/scale": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-2.2.2.tgz", - "integrity": "sha512-3aDySGUTpe6VykDQmF+g2nz5paFu9iSPTcCOEgkcru0/v5tmGzUdvivy8CkYbr87HN73V/Jc53lGm+kJUQcLBw==", - "dependencies": { - "@types/d3-interpolate": "^1.3.1", - "@types/d3-scale": "^3.3.0", - "@types/d3-time": "^2.0.0", - "d3-interpolate": "^1.4.0", - "d3-scale": "^3.3.0", - "d3-time": "^2.1.1" - } - }, - "node_modules/@visx/shape": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-2.12.2.tgz", - "integrity": "sha512-4gN0fyHWYXiJ+Ck8VAazXX0i8TOnLJvOc5jZBnaJDVxgnSIfCjJn0+Nsy96l9Dy/bCMTh4DBYUBv9k+YICBUOA==", - "dependencies": { - "@types/d3-path": "^1.0.8", - "@types/d3-shape": "^1.3.1", - "@types/lodash": "^4.14.172", - "@types/react": "*", - "@visx/curve": "2.1.0", - "@visx/group": "2.10.0", - "@visx/scale": "2.2.2", - "classnames": "^2.3.1", - "d3-path": "^1.0.5", - "d3-shape": "^1.2.0", - "lodash": "^4.17.21", - "prop-types": "^15.5.10" - }, - "peerDependencies": { - "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/text": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@visx/text/-/text-2.12.2.tgz", - "integrity": "sha512-Sv9YEolggfv2Nf6+l28ESG3VXVR1+s4u/Cz17QpgOxygcbOM8LfLtriWtBsBMKdMbYKeUpoUro0clx55TUwzew==", - "dependencies": { - "@types/lodash": "^4.14.172", - "@types/react": "*", - "classnames": "^2.3.1", - "lodash": "^4.17.21", - "prop-types": "^15.7.2", - "reduce-css-calc": "^1.3.0" - }, - "peerDependencies": { - "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, - "node_modules/@visx/tooltip": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-2.16.0.tgz", - "integrity": "sha512-kCjVtNGYpYm6AuMc1fT9cIwqpBivfQ8A5Qd7fQMC2xm4YVmehFdbyRr0nVft8zNXyUW3lDxbcq5bPIMRYhuhlA==", - "dependencies": { - "@types/react": "*", - "@visx/bounds": "2.16.0", - "classnames": "^2.3.1", - "prop-types": "^15.5.10", - "react-use-measure": "^2.0.4" - }, - "peerDependencies": { - "react": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0", - "react-dom": "^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -10268,84 +10039,6 @@ "node": ">=12" } }, - "node_modules/d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", - "dependencies": { - "d3-array": "1", - "d3-path": "1" - } - }, - "node_modules/d3-chord/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "node_modules/d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "node_modules/d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" - }, - "node_modules/d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "node_modules/d3-scale": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", - "dependencies": { - "d3-array": "^2.3.0", - "d3-format": "1 - 2", - "d3-interpolate": "1.2.0 - 2", - "d3-time": "^2.1.1", - "d3-time-format": "2 - 3" - } - }, - "node_modules/d3-scale/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-scale/node_modules/d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", - "dependencies": { - "d3-time": "1 - 2" - } - }, - "node_modules/d3-scale/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - }, - "node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "dependencies": { - "d3-path": "1" - } - }, "node_modules/d3-time": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", @@ -10434,7 +10127,8 @@ "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true }, "node_modules/debug": { "version": "4.3.4", @@ -16892,11 +16586,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/math-expression-evaluator": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz", - "integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==" - }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -19267,18 +18956,6 @@ "react-dom": ">=16.6.0" } }, - "node_modules/react-use-measure": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", - "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "dependencies": { - "debounce": "^1.2.1" - }, - "peerDependencies": { - "react": ">=16.13", - "react-dom": ">=16.13" - } - }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -19412,29 +19089,6 @@ "node": ">=8" } }, - "node_modules/reduce-css-calc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", - "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", - "dependencies": { - "balanced-match": "^0.4.2", - "math-expression-evaluator": "^1.2.14", - "reduce-function-call": "^1.0.1" - } - }, - "node_modules/reduce-css-calc/node_modules/balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==" - }, - "node_modules/reduce-function-call": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", - "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", @@ -26534,11 +26188,6 @@ "lodash.get": "^4.4.2" } }, - "@juggle/resize-observer": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz", - "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" - }, "@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -27487,50 +27136,6 @@ "integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==", "dev": true }, - "@types/d3-chord": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.11.tgz", - "integrity": "sha512-0DdfJ//bxyW3G9Nefwq/LDgazSKNN8NU0lBT3Cza6uVuInC2awMNsAcv1oKyRFLn9z7kXClH5XjwpveZjuz2eg==" - }, - "@types/d3-color": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.2.tgz", - "integrity": "sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA==" - }, - "@types/d3-interpolate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz", - "integrity": "sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg==", - "requires": { - "@types/d3-color": "^1" - } - }, - "@types/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==" - }, - "@types/d3-scale": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.3.2.tgz", - "integrity": "sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==", - "requires": { - "@types/d3-time": "^2" - } - }, - "@types/d3-shape": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", - "requires": { - "@types/d3-path": "^1" - } - }, - "@types/d3-time": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.1.tgz", - "integrity": "sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg==" - }, "@types/d3-time-format": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.0.tgz", @@ -27692,7 +27297,8 @@ "@types/lodash": { "version": "4.14.195", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", - "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==" + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true }, "@types/long": { "version": "4.0.2", @@ -27810,14 +27416,6 @@ "@types/react": "*" } }, - "@types/react-dom": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", - "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", - "requires": { - "@types/react": "*" - } - }, "@types/react-grid-layout": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.2.tgz", @@ -28100,145 +27698,6 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@visx/axis": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/@visx/axis/-/axis-2.14.0.tgz", - "integrity": "sha512-/mJuPiAUN/YdatSlXkkXD/8Pb4gVclbucNZkpUk6JVhnrmow0a1x73QiMXKuH2qDO5GDaqQS0C3Ly9lI3qTQ5Q==", - "requires": { - "@types/react": "*", - "@visx/group": "2.10.0", - "@visx/point": "2.6.0", - "@visx/scale": "2.2.2", - "@visx/shape": "2.12.2", - "@visx/text": "2.12.2", - "classnames": "^2.3.1", - "prop-types": "^15.6.0" - } - }, - "@visx/bounds": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@visx/bounds/-/bounds-2.16.0.tgz", - "integrity": "sha512-KJoSSJt5SOLzprEbmsmdxR46PLudau0kWOgxavrah9D/49RsHwGdUdxHLKdXz4OdCruEfgGo4yxiuYLYmUWl4A==", - "requires": { - "@types/react": "*", - "@types/react-dom": "*", - "prop-types": "^15.5.10" - } - }, - "@visx/chord": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/chord/-/chord-2.10.0.tgz", - "integrity": "sha512-p2ZQ9uiyiXV4Yu9DL+cqKbZbh1umMgCUWTP2CpgwSN5p822QHQjzpe1nafWOmNSLpANIBDDYIbtIgOZXUHkelA==", - "requires": { - "@types/d3-chord": "^1.0.9", - "@types/react": "*", - "classnames": "^2.3.1", - "d3-chord": "^1.0.4", - "prop-types": "^15.6.1" - } - }, - "@visx/curve": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-2.1.0.tgz", - "integrity": "sha512-9b6JOnx91gmOQiSPhUOxdsvcnW88fgqfTPKoVgQxidMsD/I3wksixtwo8TR/vtEz2aHzzsEEhlv1qK7Y3yaSDw==", - "requires": { - "@types/d3-shape": "^1.3.1", - "d3-shape": "^1.0.6" - } - }, - "@visx/event": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@visx/event/-/event-2.6.0.tgz", - "integrity": "sha512-WGp91g82s727g3NAnENF1ppC3ZAlvWg+Y+GG0WFg34NmmOZbvPI/PTOqTqZE3x6B8EUn8NJiMxRjxIMbi+IvRw==", - "requires": { - "@types/react": "*", - "@visx/point": "2.6.0" - } - }, - "@visx/group": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/group/-/group-2.10.0.tgz", - "integrity": "sha512-DNJDX71f65Et1+UgQvYlZbE66owYUAfcxTkC96Db6TnxV221VKI3T5l23UWbnMzwFBP9dR3PWUjjqhhF12N5pA==", - "requires": { - "@types/react": "*", - "classnames": "^2.3.1", - "prop-types": "^15.6.2" - } - }, - "@visx/point": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@visx/point/-/point-2.6.0.tgz", - "integrity": "sha512-amBi7yMz4S2VSchlPdliznN41TuES64506ySI22DeKQ+mc1s1+BudlpnY90sM1EIw4xnqbKmrghTTGfy6SVqvQ==" - }, - "@visx/responsive": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-2.10.0.tgz", - "integrity": "sha512-NssDPpuUYp7hqVISuYkKZ5zk6ob0++RdTIaUjRcUdyFEbvzb9+zIb8QToOkvI90L2EC/MY4Jx0NpDbEe79GpAw==", - "requires": { - "@juggle/resize-observer": "^3.3.1", - "@types/lodash": "^4.14.172", - "@types/react": "*", - "lodash": "^4.17.21", - "prop-types": "^15.6.1" - } - }, - "@visx/scale": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-2.2.2.tgz", - "integrity": "sha512-3aDySGUTpe6VykDQmF+g2nz5paFu9iSPTcCOEgkcru0/v5tmGzUdvivy8CkYbr87HN73V/Jc53lGm+kJUQcLBw==", - "requires": { - "@types/d3-interpolate": "^1.3.1", - "@types/d3-scale": "^3.3.0", - "@types/d3-time": "^2.0.0", - "d3-interpolate": "^1.4.0", - "d3-scale": "^3.3.0", - "d3-time": "^2.1.1" - } - }, - "@visx/shape": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-2.12.2.tgz", - "integrity": "sha512-4gN0fyHWYXiJ+Ck8VAazXX0i8TOnLJvOc5jZBnaJDVxgnSIfCjJn0+Nsy96l9Dy/bCMTh4DBYUBv9k+YICBUOA==", - "requires": { - "@types/d3-path": "^1.0.8", - "@types/d3-shape": "^1.3.1", - "@types/lodash": "^4.14.172", - "@types/react": "*", - "@visx/curve": "2.1.0", - "@visx/group": "2.10.0", - "@visx/scale": "2.2.2", - "classnames": "^2.3.1", - "d3-path": "^1.0.5", - "d3-shape": "^1.2.0", - "lodash": "^4.17.21", - "prop-types": "^15.5.10" - } - }, - "@visx/text": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@visx/text/-/text-2.12.2.tgz", - "integrity": "sha512-Sv9YEolggfv2Nf6+l28ESG3VXVR1+s4u/Cz17QpgOxygcbOM8LfLtriWtBsBMKdMbYKeUpoUro0clx55TUwzew==", - "requires": { - "@types/lodash": "^4.14.172", - "@types/react": "*", - "classnames": "^2.3.1", - "lodash": "^4.17.21", - "prop-types": "^15.7.2", - "reduce-css-calc": "^1.3.0" - } - }, - "@visx/tooltip": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@visx/tooltip/-/tooltip-2.16.0.tgz", - "integrity": "sha512-kCjVtNGYpYm6AuMc1fT9cIwqpBivfQ8A5Qd7fQMC2xm4YVmehFdbyRr0nVft8zNXyUW3lDxbcq5bPIMRYhuhlA==", - "requires": { - "@types/react": "*", - "@visx/bounds": "2.16.0", - "classnames": "^2.3.1", - "prop-types": "^15.5.10", - "react-use-measure": "^2.0.4" - } - }, "@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -30517,88 +29976,6 @@ "internmap": "1 - 2" } }, - "d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", - "requires": { - "d3-array": "1", - "d3-path": "1" - }, - "dependencies": { - "d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - } - } - }, - "d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "d3-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", - "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" - }, - "d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "requires": { - "d3-color": "1" - } - }, - "d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "d3-scale": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", - "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", - "requires": { - "d3-array": "^2.3.0", - "d3-format": "1 - 2", - "d3-interpolate": "1.2.0 - 2", - "d3-time": "^2.1.1", - "d3-time-format": "2 - 3" - }, - "dependencies": { - "d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "requires": { - "internmap": "^1.0.0" - } - }, - "d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", - "requires": { - "d3-time": "1 - 2" - } - }, - "internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" - } - } - }, - "d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "requires": { - "d3-path": "1" - } - }, "d3-time": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", @@ -30670,7 +30047,8 @@ "debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true }, "debug": { "version": "4.3.4", @@ -35613,11 +34991,6 @@ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, - "math-expression-evaluator": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz", - "integrity": "sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw==" - }, "md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -37370,14 +36743,6 @@ "prop-types": "^15.6.2" } }, - "react-use-measure": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", - "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "requires": { - "debounce": "^1.2.1" - } - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -37485,31 +36850,6 @@ } } }, - "reduce-css-calc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", - "integrity": "sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA==", - "requires": { - "balanced-match": "^0.4.2", - "math-expression-evaluator": "^1.2.14", - "reduce-function-call": "^1.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg==" - } - } - }, - "reduce-function-call": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz", - "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==", - "requires": { - "balanced-match": "^1.0.0" - } - }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", diff --git a/package.json b/package.json index 61ed1f4c..184511f2 100644 --- a/package.json +++ b/package.json @@ -49,14 +49,6 @@ "@nestjs/throttler": "^4.0.0", "@nestjs/websockets": "^9.4.2", "@tanstack/react-table": "^8.9.1", - "@visx/axis": "^2.12.2", - "@visx/chord": "^2.10.0", - "@visx/event": "^2.6.0", - "@visx/group": "^2.10.0", - "@visx/responsive": "^2.10.0", - "@visx/scale": "^2.2.2", - "@visx/shape": "^2.12.2", - "@visx/tooltip": "^2.16.0", "apollo-server-express": "^3.12.0", "balanceofsatoshis": "^15.8.2", "bcryptjs": "^2.4.3", diff --git a/src/client/src/components/chord/index.tsx b/src/client/src/components/chord/index.tsx deleted file mode 100644 index acc209dd..00000000 --- a/src/client/src/components/chord/index.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react'; -import { Arc } from '@visx/shape'; -import { Group } from '@visx/group'; -import { Chord, Ribbon } from '@visx/chord'; -import { scaleOrdinal } from '@visx/scale'; - -const pink = '#ff2fab'; -const orange = '#ffc62e'; -const purple = '#dc04ff'; -const purple2 = '#7324ff'; -const red = '#d04376'; -const green = '#52f091'; -const blue = '#04a6ff'; -const lime = '#00ddc6'; - -function descending(a: number, b: number): number { - return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; -} - -export type SingleGroupProps = { - endAngle: number; - index: number; - startAngle: number; - value: number; -}; - -export type SingleChordProps = { - source: SingleGroupProps; - target: SingleGroupProps; -}; - -const groupColor = scaleOrdinal({ - domain: [0, 1, 2, 3, 4, 5, 6, 7], - range: [pink, orange, purple, purple2, red, green, blue, lime], -}); - -export type ChordProps = { - matrix: number[][]; - width: number; - height: number; - centerSize?: number; - groupCallback?: (group: SingleGroupProps) => void; - chordCallback?: (chord: SingleChordProps) => void; -}; - -export const ChordGraph = ({ - matrix, - width, - height, - centerSize = 20, - groupCallback, - chordCallback, -}: ChordProps) => { - const outerRadius = Math.min(width, height) * 0.5 - (centerSize + 10); - const innerRadius = outerRadius - centerSize; - - return width < 10 ? null : ( -
- - - - {({ chords }) => ( - - {chords.groups.map((group, i) => ( - { - groupCallback && groupCallback(group); - }} - /> - ))} - {chords.map((chord, i) => { - return ( - { - chordCallback && chordCallback(chord); - }} - /> - ); - })} - - )} - - - - -
- ); -}; diff --git a/src/client/src/components/sankey/index.tsx b/src/client/src/components/sankey/index.tsx index 83f8dc04..98d1765c 100644 --- a/src/client/src/components/sankey/index.tsx +++ b/src/client/src/components/sankey/index.tsx @@ -25,8 +25,8 @@ echarts.use([ ]); export type SankeyProps = { - width: number; - height: number; + width: string; + height: string; data: SankeyData; }; diff --git a/src/client/src/views/forwards/forwardChord.tsx b/src/client/src/views/forwards/forwardChord.tsx deleted file mode 100644 index f9daff7f..00000000 --- a/src/client/src/views/forwards/forwardChord.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { toast } from 'react-toastify'; -import { getErrorContent } from '../../utils/error'; -import { Forward } from '../../graphql/types'; -import { ParentSize } from '@visx/responsive'; -import { - ChordGraph, - SingleGroupProps, - SingleChordProps, -} from '../../components/chord'; -import styled from 'styled-components'; -import { renderLine } from '../../components/generic/helpers'; -import { DarkSubTitle } from '../../components/generic/Styled'; -import { mediaWidths } from '../../styles/Themes'; -import { usePriceState } from '../../context/PriceContext'; -import { getPrice } from '../../components/price/Price'; -import { useConfigState } from '../../context/ConfigContext'; -import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated'; -import { ChannelAlias } from '../home/reports/forwardReport/ChannelAlias'; -import { getChordMatrix } from './helpers'; - -const Wrapper = styled.div` - height: 800px; - width: 100%; - - @media (${mediaWidths.mobile}) { - height: 300px; - } -`; - -const Center = styled.div` - width: '100%'; - text-align: center; -`; - -type SelectedProps = - | { type: 'group'; group: SingleGroupProps } - | { type: 'chord'; chord: SingleChordProps } - | null; - -const getTitle = (order: string) => { - switch (order) { - case 'fee': - return 'Total Fees (sats)'; - case 'tokens': - return 'Total Tokens (sats)'; - default: - return 'Total Amount (Forwards)'; - } -}; - -export const ForwardChord = ({ - days, - order, -}: { - days: number; - order: string; -}) => { - const [selected, setSelected] = useState(); - - useEffect(() => { - setSelected(null); - }, [order]); - - const { data, loading } = useGetForwardsQuery({ - ssr: false, - variables: { days }, - onError: error => toast.error(getErrorContent(error)), - }); - - const { currency, displayValues } = useConfigState(); - const priceContext = usePriceState(); - const format = getPrice(currency, displayValues, priceContext); - - if (loading || !data?.getForwards?.length) { - return null; - } - - const { matrix, uniqueNodes } = getChordMatrix( - order, - data.getForwards as Forward[] - ); - - const handleGroupClick = (group: SingleGroupProps) => { - setSelected({ type: 'group', group }); - }; - const handleChordClick = (chord: SingleChordProps) => { - setSelected({ type: 'chord', chord }); - }; - - const renderInfo = () => { - if (!selected) { - return ( -
- Click the graph for specific info! -
- ); - } - if (selected.type === 'group') { - return ( - <> - {renderLine( - 'With', - - )} - {renderLine('Channel Id', uniqueNodes[selected.group.index])} - {renderLine( - getTitle(order), - format({ amount: selected.group.value, noUnit: order === 'amount' }) - )} - - ); - } - if (selected.type === 'chord') { - return ( - <> - {renderLine( - 'Between', - <> - - {` - `} - - - )} - {renderLine( - 'Channel Ids', - `${uniqueNodes[selected.chord.source.index]} - ${ - uniqueNodes[selected.chord.target.index] - }` - )} - {renderLine( - getTitle(order), - format({ - amount: selected.chord.source.value, - noUnit: order === 'amount', - }) - )} - - ); - } - }; - - return ( - <> - {renderInfo()} - - - {parent => ( - - )} - - - - ); -}; diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx index c24dfabf..97c46564 100644 --- a/src/client/src/views/forwards/forwardSankey.tsx +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -1,15 +1,16 @@ import React, { useMemo } from 'react'; import { toast } from 'react-toastify'; import { getErrorContent } from '../../utils/error'; -import { ParentSize } from '@visx/responsive'; import styled from 'styled-components'; import { mediaWidths } from '../../styles/Themes'; import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated'; import { Sankey, SankeyData } from '../../components/sankey'; import { Forward } from '../../graphql/types'; +const SANKEY_HEIGHT = '800px'; + const Wrapper = styled.div` - height: 800px; + height: ${SANKEY_HEIGHT}; width: 100%; @media (${mediaWidths.mobile}) { @@ -57,15 +58,7 @@ export const ForwardSankey = ({ days }: { days: number }) => { return ( <> - - {parent => ( - - )} - + ); diff --git a/src/client/src/views/forwards/helpers.tsx b/src/client/src/views/forwards/helpers.tsx index eaaa30d8..67a39ad2 100644 --- a/src/client/src/views/forwards/helpers.tsx +++ b/src/client/src/views/forwards/helpers.tsx @@ -1,52 +1,6 @@ import { sortBy } from 'lodash'; import { Forward } from '../../graphql/types'; -export const getChordMatrix = (order: string, forwardArray: Forward[]) => { - const cleaned = forwardArray.map(f => { - let value = 1; - - if (order === 'fee') { - value = f.fee; - } else if (order === 'tokens') { - value = f.tokens; - } - - return { - incoming_channel: f.incoming_channel, - outgoing_channel: f.outgoing_channel, - value, - }; - }); - - const incomingNodes = cleaned.map(f => f.incoming_channel); - const outgoingNodes = cleaned.map(f => f.outgoing_channel); - - const uniqueNodes = [ - ...Array.from(new Set(incomingNodes)), - ...Array.from(new Set(outgoingNodes)), - ]; - const nodeLength = uniqueNodes.length; - - const matrix = new Array(nodeLength); - - for (let i = 0; i < matrix.length; i++) { - matrix[i] = new Array(nodeLength).fill(0); - } - - cleaned.forEach(f => { - const inIndex = uniqueNodes.indexOf(f.incoming_channel); - const outIndex = uniqueNodes.indexOf(f.outgoing_channel); - - const previousValue = matrix[inIndex][outIndex]; - const previousOutValue = matrix[outIndex][inIndex]; - - matrix[inIndex][outIndex] = previousValue + f.value; - matrix[outIndex][inIndex] = previousOutValue + f.value; - }); - - return { uniqueNodes, matrix }; -}; - export const sortByNode = (order: string, forwardArray: Forward[]) => { const cleaned = forwardArray.map(f => { let value = 1; From b1cedd4509ff3c02a7adb155a50393440d86bda2 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 27 Jun 2023 15:20:17 -0300 Subject: [PATCH 15/22] chore: remove stray console log --- src/client/pages/transactions.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client/pages/transactions.tsx b/src/client/pages/transactions.tsx index b707eb05..df902aa8 100644 --- a/src/client/pages/transactions.tsx +++ b/src/client/pages/transactions.tsx @@ -110,8 +110,6 @@ const TransactionsView = () => { return ''; } } - - console.log(lastInvoice, lastPayment); }, [invoiceQuery.data, paymentQuery.data, show]); const renderInvoices = useCallback(() => { From fbd31e2725ec654e88af527347bb1b4e694bc877 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Tue, 27 Jun 2023 15:30:20 -0300 Subject: [PATCH 16/22] chore: format numbers on y axis to be integer values --- src/client/src/components/chart/BarChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/components/chart/BarChart.tsx b/src/client/src/components/chart/BarChart.tsx index 28ee3852..98aca1ce 100644 --- a/src/client/src/components/chart/BarChart.tsx +++ b/src/client/src/components/chart/BarChart.tsx @@ -111,7 +111,7 @@ export const BarChart = ({ axisTick: { show: true }, axisLabel: { formatter: function (value: number) { - return numeral(value).format('0.0a'); + return numeral(value).format('0'); }, }, }, From b70b040a7c10542b4f642bd80d175ff5a9fe0878 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Wed, 5 Jul 2023 21:39:10 -0300 Subject: [PATCH 17/22] feat: tidy echarts implementation --- src/client/src/components/chart/BarChart.tsx | 13 ++++--------- .../src/components/chart/HorizontalBarChart.tsx | 10 +++++++--- src/client/src/components/generic/helpers.tsx | 2 +- src/client/src/views/forwards/forwardSankey.tsx | 8 ++++---- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/client/src/components/chart/BarChart.tsx b/src/client/src/components/chart/BarChart.tsx index 98aca1ce..8ff31b04 100644 --- a/src/client/src/components/chart/BarChart.tsx +++ b/src/client/src/components/chart/BarChart.tsx @@ -65,15 +65,11 @@ export const BarChart = ({ return { color: colorRange, - title: { - text: title, - textStyle: { color: fontColor }, - }, grid: { containLabel: true, top: '50px', left: '25px', - bottom: '0px', + bottom: '25px', right: '25px', }, tooltip: { @@ -111,7 +107,8 @@ export const BarChart = ({ axisTick: { show: true }, axisLabel: { formatter: function (value: number) { - return numeral(value).format('0'); + const format = value < 1000 ? '0a' : '0.0a'; + return numeral(value).format(format); }, }, }, @@ -126,9 +123,7 @@ export const BarChart = ({ notMerge={true} lazyUpdate={true} showLoading={false} - style={{ - height: '100%', - }} + style={{ height: '100%' }} /> ); }; diff --git a/src/client/src/components/chart/HorizontalBarChart.tsx b/src/client/src/components/chart/HorizontalBarChart.tsx index 23f729ec..75ba8743 100644 --- a/src/client/src/components/chart/HorizontalBarChart.tsx +++ b/src/client/src/components/chart/HorizontalBarChart.tsx @@ -74,7 +74,8 @@ export const HorizontalBarChart = ({ color: colorRange, grid: { left: '25px', - bottom: '0px', + bottom: '25px', + top: '25px', right: '25px', }, tooltip: { @@ -84,8 +85,11 @@ export const HorizontalBarChart = ({ }, }, xAxis: { - max: maxValue * 1.2, + max: maxValue * 1.4, show: false, + alignTicks: 'value', + zIndex: 10, + z: 10, }, yAxis: { axisPointer: { @@ -117,7 +121,7 @@ export const HorizontalBarChart = ({ data: yLabels, type: 'category', inverse: true, - max: 5, + max: 4, position: 'right', }, legend: { show: true }, diff --git a/src/client/src/components/generic/helpers.tsx b/src/client/src/components/generic/helpers.tsx index 1228f3aa..9008a56c 100644 --- a/src/client/src/components/generic/helpers.tsx +++ b/src/client/src/components/generic/helpers.tsx @@ -164,7 +164,7 @@ export const getFormatDate = ( style?: string ): string | null => { if (!date) return null; - return format(new Date(date), style || 'yyyy.MM.dd - HH:mm:ss'); + return format(new Date(date), style || 'yyyy.MM.dd - H:mm:ss'); }; export const getMessageDate = ( diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx index 97c46564..52d0a887 100644 --- a/src/client/src/views/forwards/forwardSankey.tsx +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -7,14 +7,14 @@ import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForw import { Sankey, SankeyData } from '../../components/sankey'; import { Forward } from '../../graphql/types'; -const SANKEY_HEIGHT = '800px'; +const SANKEY_HEIGHT_DESKTOP = '800px'; const Wrapper = styled.div` - height: ${SANKEY_HEIGHT}; + height: ${SANKEY_HEIGHT_DESKTOP}; width: 100%; @media (${mediaWidths.mobile}) { - height: 300px; + height: ${SANKEY_HEIGHT_DESKTOP}; } `; @@ -58,7 +58,7 @@ export const ForwardSankey = ({ days }: { days: number }) => { return ( <> - + ); From 4c4acf56878d667c0b2a546d5b57e9bef2915e6f Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Thu, 6 Jul 2023 14:38:07 -0300 Subject: [PATCH 18/22] feat: revamp tooltip --- src/client/src/components/chart/BarChart.tsx | 9 ++++++--- src/client/src/components/chart/HorizontalBarChart.tsx | 9 +++++++++ src/client/src/components/chart/common.ts | 9 +++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/client/src/components/chart/common.ts diff --git a/src/client/src/components/chart/BarChart.tsx b/src/client/src/components/chart/BarChart.tsx index 8ff31b04..3c167191 100644 --- a/src/client/src/components/chart/BarChart.tsx +++ b/src/client/src/components/chart/BarChart.tsx @@ -14,8 +14,8 @@ import ReactEChartsCore from 'echarts-for-react/lib/core'; import { ThemeContext } from 'styled-components'; import numeral from 'numeral'; import { timeFormat, timeParse } from 'd3-time-format'; -import { getFormatDate } from '../generic/helpers'; import { formatSats } from '../../utils/helpers'; +import { COMMON_CHART_STYLES } from './common'; echarts.use([ EBarChart, @@ -78,9 +78,12 @@ export const BarChart = ({ animation: false, }, formatter: (params: any) => { - return `Date: ${getFormatDate(params[0].axisValue)}
- ${params[0].seriesName}: ${formatSats(params[0].value)}
`; + return `${title}
+ ${formatSats(params[0].value)}
`; }, + ...COMMON_CHART_STYLES.tooltip, }, xAxis: { name: 'Dates', diff --git a/src/client/src/components/chart/HorizontalBarChart.tsx b/src/client/src/components/chart/HorizontalBarChart.tsx index 75ba8743..eeaf1d89 100644 --- a/src/client/src/components/chart/HorizontalBarChart.tsx +++ b/src/client/src/components/chart/HorizontalBarChart.tsx @@ -13,6 +13,8 @@ import { import * as echarts from 'echarts/core'; import { CanvasRenderer } from 'echarts/renderers'; import ReactEChartsCore from 'echarts-for-react/lib/core'; +import { formatSats } from '../../utils/helpers'; +import { COMMON_CHART_STYLES } from './common'; echarts.use([ BarChart, @@ -83,6 +85,13 @@ export const HorizontalBarChart = ({ axisPointer: { animation: false, }, + formatter: (params: any) => { + return `Value
+ ${formatSats(params[0].value)}`; + }, + ...COMMON_CHART_STYLES.tooltip, }, xAxis: { max: maxValue * 1.4, diff --git a/src/client/src/components/chart/common.ts b/src/client/src/components/chart/common.ts new file mode 100644 index 00000000..4234a361 --- /dev/null +++ b/src/client/src/components/chart/common.ts @@ -0,0 +1,9 @@ +export const COMMON_CHART_STYLES = { + tooltip: { + backgroundColor: 'black', + borderColor: 'black', + textStyle: { + color: 'white', + }, + }, +}; From 78e5e13e674ce73dc85f7282733b5f9050548a45 Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Sun, 30 Jul 2023 20:25:04 -0300 Subject: [PATCH 19/22] feat: bound the size of the sankey chart --- src/client/src/components/sankey/index.tsx | 7 ++++++- src/client/src/views/forwards/forwardSankey.tsx | 9 ++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/client/src/components/sankey/index.tsx b/src/client/src/components/sankey/index.tsx index 98d1765c..9c95a6c7 100644 --- a/src/client/src/components/sankey/index.tsx +++ b/src/client/src/components/sankey/index.tsx @@ -51,19 +51,24 @@ export const Sankey = ({ data, width, height }: SankeyProps) => { const option = useMemo(() => { const fontColor = themeContext.mode === 'light' ? 'black' : 'white'; return { + resize: true, tooltip: { trigger: 'item', triggerOn: 'mousemove', }, series: [ { + height, type: 'sankey', nodeAlign: 'justify', + nodeGap: 3, layoutIterations: 32, data: data.nodes, links: data.links, - nodeGap: 100, dragable: false, + left: 'left', + bottom: '5', + top: 'top', label: { show: true, color: fontColor, diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx index 52d0a887..bd690515 100644 --- a/src/client/src/views/forwards/forwardSankey.tsx +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -11,6 +11,7 @@ const SANKEY_HEIGHT_DESKTOP = '800px'; const Wrapper = styled.div` height: ${SANKEY_HEIGHT_DESKTOP}; + maxheight: ${SANKEY_HEIGHT_DESKTOP}; width: 100%; @media (${mediaWidths.mobile}) { @@ -56,10 +57,8 @@ export const ForwardSankey = ({ days }: { days: number }) => { } return ( - <> - - - - + + + ); }; From e362890586c3eda9ebb1d65c4274aa691d9f025d Mon Sep 17 00:00:00 2001 From: AmbossKeegan Date: Sun, 30 Jul 2023 20:25:43 -0300 Subject: [PATCH 20/22] feat: provide function that creates a mock sankey dataset of arbitrary size --- .../helpers/generate-mock-sankey-forwards.ts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/client/src/views/forwards/helpers/generate-mock-sankey-forwards.ts diff --git a/src/client/src/views/forwards/helpers/generate-mock-sankey-forwards.ts b/src/client/src/views/forwards/helpers/generate-mock-sankey-forwards.ts new file mode 100644 index 00000000..ff215ac7 --- /dev/null +++ b/src/client/src/views/forwards/helpers/generate-mock-sankey-forwards.ts @@ -0,0 +1,93 @@ +export function generateUniqueSourcesAndTargets( + numSources: number, + numTargets: number, + numRecords: number +) { + const sources: string[] = []; + const targets: string[] = []; + + // Generate unique sources + for (let i = 0; i < numSources; i++) { + const randomSource = `${Math.floor(Math.random() * 10000) + 1}x1x1`; + sources.push(randomSource); + } + + // Generate unique targets + for (let i = 0; i < numTargets; i++) { + const randomTarget = `${Math.floor(Math.random() * 10000) + 1}x1x1`; + targets.push(randomTarget); + } + + // Build a graph to represent the relationships between sources and targets + const graph: { [key: string]: string[] } = {}; + for (const target of targets) { + graph[target] = []; + } + + const links = []; + + // Generate items while ensuring no circular references + const orderedTargets = topologicalSort(graph); + + for (const source of sources) { + for (const target of orderedTargets) { + const randomValue = Math.floor(Math.random() * 1000000) + 1; + + const newItem = { + source: `source: ${source}`, + target: `target: ${target}`, + value: randomValue, + }; + + links.push(newItem); + graph[source] = graph[source] || []; + graph[source].push(target); + + // If the desired number of records is reached, exit the loop early + if (links.length === numRecords) { + break; + } + } + // If the desired number of records is reached, exit the loop early + if (links.length === numRecords) { + break; + } + } + + // Extract unique nodes from links + const uniqueNodesSet = new Set(); + for (const link of links) { + uniqueNodesSet.add(link.source); + uniqueNodesSet.add(link.target); + } + + const nodes = Array.from(uniqueNodesSet).map(node => ({ name: node })); + + return { links, nodes }; +} + +// Function to perform topological sorting +function topologicalSort(graph: { [key: string]: string[] }): string[] { + const visited = new Set(); + const stack: string[] = []; + + function dfs(node: string) { + if (visited.has(node)) return; + visited.add(node); + + const neighbors = graph[node]; + if (neighbors) { + for (const neighbor of neighbors) { + dfs(neighbor); + } + } + + stack.push(node); + } + + for (const node of Object.keys(graph)) { + dfs(node); + } + + return stack.reverse(); +} From 2859f294fc0990571b2ec53df171ffc043b5e5e4 Mon Sep 17 00:00:00 2001 From: secondl1ght Date: Tue, 1 Aug 2023 11:27:09 -0600 Subject: [PATCH 21/22] fix: missing memo dependencies and css --- src/client/src/components/sankey/index.tsx | 2 +- src/client/src/views/forwards/forwardSankey.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/src/components/sankey/index.tsx b/src/client/src/components/sankey/index.tsx index 9c95a6c7..32deaa51 100644 --- a/src/client/src/components/sankey/index.tsx +++ b/src/client/src/components/sankey/index.tsx @@ -86,7 +86,7 @@ export const Sankey = ({ data, width, height }: SankeyProps) => { }, ], }; - }, [data, themeContext]); + }, [data, themeContext, height]); return ( { }); return orderedData; - }, [data]); + }, [data, loading]); if (loading || !data?.getForwards?.length) { return null; From ff95759ce4b56a402ab3e4f1b93546ce0c5ceee5 Mon Sep 17 00:00:00 2001 From: Anthony Potdevin Date: Fri, 18 Aug 2023 18:08:29 +0200 Subject: [PATCH 22/22] chore: small changes --- src/client/next.config.js | 2 +- src/client/pages/forwards.tsx | 5 +- .../src/views/forwards/forwardSankey.tsx | 98 +++++++++++++------ 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/client/next.config.js b/src/client/next.config.js index 415c00c8..29589dc1 100644 --- a/src/client/next.config.js +++ b/src/client/next.config.js @@ -10,7 +10,7 @@ module.exports = { reactStrictMode: true, poweredByHeader: false, basePath: process.env.BASE_PATH || '', - transpilePackages: ['echarts', 'echarts-for-react', 'zrender'], + transpilePackages: ['echarts', 'zrender'], compiler: { styledComponents: true, }, diff --git a/src/client/pages/forwards.tsx b/src/client/pages/forwards.tsx index 12aebf30..a036564c 100644 --- a/src/client/pages/forwards.tsx +++ b/src/client/pages/forwards.tsx @@ -87,7 +87,10 @@ const ForwardsView = () => {
Sankey - + )} diff --git a/src/client/src/views/forwards/forwardSankey.tsx b/src/client/src/views/forwards/forwardSankey.tsx index fb1967e3..c2e3cfc5 100644 --- a/src/client/src/views/forwards/forwardSankey.tsx +++ b/src/client/src/views/forwards/forwardSankey.tsx @@ -1,64 +1,100 @@ -import React, { useMemo } from 'react'; +import React, { FC, useMemo } from 'react'; import { toast } from 'react-toastify'; import { getErrorContent } from '../../utils/error'; import styled from 'styled-components'; import { mediaWidths } from '../../styles/Themes'; import { useGetForwardsQuery } from '../../graphql/queries/__generated__/getForwards.generated'; import { Sankey, SankeyData } from '../../components/sankey'; -import { Forward } from '../../graphql/types'; +import { groupBy, orderBy, reduce, uniq } from 'lodash'; -const SANKEY_HEIGHT_DESKTOP = '800px'; - -const Wrapper = styled.div` - height: ${SANKEY_HEIGHT_DESKTOP}; - max-height: ${SANKEY_HEIGHT_DESKTOP}; +const Wrapper = styled.div<{ $height: number }>` + height: ${props => props.$height}px; + max-height: ${props => props.$height}px; width: 100%; @media (${mediaWidths.mobile}) { - height: ${SANKEY_HEIGHT_DESKTOP}; + height: ${props => props.$height}px; } `; -export const ForwardSankey = ({ days }: { days: number }) => { +export const ForwardSankey: FC<{ + days: number; + type: 'amount' | 'fee' | 'tokens'; +}> = ({ days, type }) => { const { data, loading } = useGetForwardsQuery({ ssr: false, variables: { days }, onError: error => toast.error(getErrorContent(error)), }); - const sankeyData = useMemo(() => { - if (loading || !data || !data.getForwards.length) + const sankeyData: SankeyData = useMemo(() => { + if (loading || !data || !data.getForwards.length) { return { links: [], nodes: [] }; - const orderedData: SankeyData = { links: [], nodes: [] }; - const nodeArr: string[] = []; - - // We need to put unique nodes in an array for future sorting - data.getForwards.map((forward: Forward) => { - const source = `source: ${forward.incoming_channel}`; - const target = `target: ${forward.outgoing_channel}`; - if (nodeArr.indexOf(source) === -1) nodeArr.push(source); - if (nodeArr.indexOf(target) === -1) nodeArr.push(target); - orderedData.links.push({ - source, - target, - value: forward.tokens, + } + + const mapped = data.getForwards.map(d => ({ + ...d, + group: `${d.incoming_channel}-${d.outgoing_channel}`, + })); + + const grouped = groupBy(mapped, 'group'); + + const aggregated: { + incoming_channel: string; + outgoing_channel: string; + fee: number; + tokens: number; + amount: number; + }[] = []; + + Object.entries(grouped).forEach(([, value]) => { + const totalFees = value.map(v => v.fee).reduce((p, c) => p + c, 0); + const totalTokens = value.map(v => v.tokens).reduce((p, c) => p + c, 0); + const totalAmount = value.length; + + const firstValue = value[0]; + + aggregated.push({ + incoming_channel: firstValue.incoming_channel, + outgoing_channel: firstValue.outgoing_channel, + fee: totalFees, + tokens: totalTokens, + amount: totalAmount, }); }); - orderedData.nodes = nodeArr.map(node => { - return { name: node }; - }); + const finalData = reduce( + aggregated, + (p, c) => { + const source = `source: ${c.incoming_channel}`; + const target = `target: ${c.outgoing_channel}`; - return orderedData; - }, [data, loading]); + return { + links: [...p.links, { source, target, value: c[type] || 0 }], + nodes: [...p.nodes, source, target], + }; + }, + { + links: [] as { source: string; target: string; value: number }[], + nodes: [] as string[], + } + ); + + return { + links: orderBy(finalData.links, 'value', 'desc'), + nodes: uniq(finalData.nodes).map(n => ({ name: n })), + }; + }, [data, loading, type]); if (loading || !data?.getForwards?.length) { return null; } + const graphHeight = 800 + 10 * sankeyData.links.length; + return ( - - + + ); };