Skip to content

Commit 18bb98d

Browse files
authored
Merge pull request #3292 from pyth-network/bduran/hood-historical-demo-data
Bduran/hood historical demo data
2 parents eae7eb5 + 2a30c3c commit 18bb98d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1694
-716
lines changed

apps/insights/next.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const config = {
1414
},
1515
},
1616

17+
serverExternalPackages: ["@duckdb/node-api"],
18+
1719
turbopack: {
1820
rules: {
1921
"*.svg": {

apps/insights/package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
},
99
"scripts": {
1010
"build:vercel": "next build",
11+
"build:csv": "tsx ./src/pyth-feed-demo-data/fix-data.ts",
1112
"fix:format": "prettier --write .",
1213
"fix:lint:eslint": "eslint --fix .",
1314
"fix:lint:stylelint": "stylelint --fix 'src/**/*.scss'",
@@ -21,6 +22,7 @@
2122
},
2223
"dependencies": {
2324
"@clickhouse/client": "catalog:",
25+
"@duckdb/node-api": "catalog:",
2426
"@phosphor-icons/react": "catalog:",
2527
"@pythnetwork/client": "catalog:",
2628
"@pythnetwork/component-library": "workspace:*",
@@ -33,16 +35,21 @@
3335
"bs58": "catalog:",
3436
"change-case": "catalog:",
3537
"clsx": "catalog:",
38+
"color": "catalog:",
3639
"date-fns": "catalog:",
3740
"csv-stringify": "catalog:",
41+
"dayjs": "catalog:",
3842
"dnum": "catalog:",
39-
"ioredis": "^5.7.0",
43+
"fs-extra": "catalog:",
44+
"glob": "catalog:",
45+
"ioredis": "catalog:",
4046
"lightweight-charts": "catalog:",
4147
"match-sorter": "catalog:",
4248
"motion": "catalog:",
4349
"next": "catalog:",
4450
"next-themes": "catalog:",
4551
"@pythnetwork/react-hooks": "workspace:",
52+
"papaparse": "catalog:",
4653
"react": "catalog:",
4754
"react-aria": "catalog:",
4855
"react-aria-components": "catalog:",
@@ -51,6 +58,7 @@
5158
"sockette": "catalog:",
5259
"superjson": "catalog:",
5360
"swr": "catalog:",
61+
"tsx": "catalog:",
5462
"zod": "catalog:",
5563
"zod-search-params": "catalog:",
5664
"zod-validation-error": "catalog:"
@@ -62,8 +70,10 @@
6270
"@cprussin/tsconfig": "catalog:",
6371
"@pythnetwork/staking-sdk": "workspace:*",
6472
"@svgr/webpack": "catalog:",
73+
"@types/fs-extra": "catalog:",
6574
"@types/jest": "catalog:",
6675
"@types/node": "catalog:",
76+
"@types/papaparse": "catalog:",
6777
"@types/react": "catalog:",
6878
"@types/react-dom": "catalog:",
6979
"autoprefixer": "catalog:",
30 MB
Binary file not shown.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
3+
import { fetchHistoricalDataForPythFeedsDemo } from "../../../../../../pyth-feed-demo-data/fetch-historical-data-from-db";
4+
import { GetPythFeedsDemoDataRequestSchema } from "../../../../../../schemas/pyth/pyth-pro-demo-schema";
5+
6+
export const GET = async (
7+
req: NextRequest,
8+
ctx: { params: Promise<Record<string, string>> },
9+
) => {
10+
const params = await ctx.params;
11+
const {
12+
nextUrl: { searchParams },
13+
} = req;
14+
const paramsAndQueryValidation = GetPythFeedsDemoDataRequestSchema.safeParse({
15+
params,
16+
searchParams: Object.fromEntries(searchParams),
17+
});
18+
19+
if (paramsAndQueryValidation.error) {
20+
return NextResponse.json(
21+
{
22+
error: paramsAndQueryValidation.error.message,
23+
},
24+
{ status: 400 },
25+
);
26+
}
27+
28+
const {
29+
params: { datasource: datasourceToUse, symbol: symbolToUse },
30+
searchParams: { startAt },
31+
} = paramsAndQueryValidation.data;
32+
33+
try {
34+
const { data, hasNext } = await fetchHistoricalDataForPythFeedsDemo({
35+
datasource: datasourceToUse,
36+
startAt: startAt.toISOString(),
37+
symbol: symbolToUse,
38+
});
39+
40+
return NextResponse.json({
41+
data,
42+
hasNext,
43+
});
44+
} catch (error) {
45+
return NextResponse.json(
46+
{
47+
error: error instanceof Error ? error.message : String(error),
48+
},
49+
{ status: 500 },
50+
);
51+
}
52+
};

apps/insights/src/components/PythProDemoCards/index.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import { isAllowedSymbol } from "../../util/pyth-pro-demo";
1010

1111
export function PythProDemoCards() {
1212
/** context */
13-
const { dataSourcesInUse, metrics, selectedSource } =
14-
usePythProAppStateContext();
13+
const {
14+
dataSourcesInUse,
15+
dataSourceVisibility,
16+
handleToggleDataSourceVisibility,
17+
metrics,
18+
selectedSource,
19+
} = usePythProAppStateContext();
1520
const { tokens } = usePythProApiTokensContext();
1621
const { statuses } = useWebSocketsContext();
1722

@@ -30,9 +35,11 @@ export function PythProDemoCards() {
3035
apiToken={tokens[dataSource]}
3136
currentPriceMetrics={sourceMetrics?.[selectedSource]}
3237
dataSource={dataSource}
38+
key={dataSource}
3339
selectedSource={selectedSource}
3440
socketStatus={socketStatus}
35-
key={dataSource}
41+
sourceVisible={dataSourceVisibility[dataSource]}
42+
toggleDataSourceVisibility={handleToggleDataSourceVisibility}
3643
/>
3744
);
3845
})}

apps/insights/src/components/PythProDemoCards/price-card.module.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ $price-card-width: 250px;
1010
padding-top: 0;
1111
}
1212

13+
.dataSourceName {
14+
align-items: center;
15+
display: flex;
16+
gap: theme.spacing(2);
17+
justify-content: space-between;
18+
}
19+
1320
.price {
1421
font-size: 1.2rem;
1522
font-weight: bold;
@@ -34,6 +41,15 @@ $price-card-width: 250px;
3441
font-style: italic;
3542
}
3643

44+
.toggleVisibilityBtn[data-size="sm"] {
45+
align-items: center;
46+
display: inline-flex;
47+
padding: 0;
48+
height: 2em;
49+
justify-content: center;
50+
width: 2em;
51+
}
52+
3753
.root {
3854
@include theme.elevation("default", 1);
3955

apps/insights/src/components/PythProDemoCards/price-card.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Eye, EyeSlash } from "@phosphor-icons/react/dist/ssr";
2+
import { Button } from "@pythnetwork/component-library/Button";
13
import { Card } from "@pythnetwork/component-library/Card";
24
import type { useWebSocket } from "@pythnetwork/react-hooks/use-websocket";
35
import type { Nullish } from "@pythnetwork/shared-lib/types";
@@ -11,9 +13,10 @@ import type {
1113
AllDataSourcesType,
1214
CurrentPriceMetrics,
1315
} from "../../schemas/pyth/pyth-pro-demo-schema";
16+
import { removeReplaySymbolSuffix } from "../../schemas/pyth/pyth-pro-demo-schema";
1417
import {
1518
datasourceRequiresApiToken,
16-
getColorForSymbol,
19+
getColorForDataSource,
1720
isAllowedSymbol,
1821
} from "../../util/pyth-pro-demo";
1922

@@ -23,6 +26,8 @@ type PriceCardProps = {
2326
dataSource: AllDataSourcesType;
2427
selectedSource: Nullish<AllAllowedSymbols>;
2528
socketStatus: Nullish<ReturnType<typeof useWebSocket>["status"]>;
29+
sourceVisible: boolean;
30+
toggleDataSourceVisibility: (dataSource: AllDataSourcesType) => void;
2631
};
2732

2833
export function PythProDemoCard({
@@ -31,13 +36,17 @@ export function PythProDemoCard({
3136
dataSource,
3237
selectedSource,
3338
socketStatus,
39+
sourceVisible,
40+
toggleDataSourceVisibility,
3441
}: PriceCardProps) {
3542
if (!isAllowedSymbol(selectedSource)) return;
3643

3744
/** local variables */
3845
const requiresToken = datasourceRequiresApiToken(dataSource);
3946

40-
const formattedSymbol = selectedSource.toUpperCase();
47+
const toggleVisibilityTooltip = `${sourceVisible ? "Hide" : "Show"} this data source in the chart`;
48+
const formattedSymbol =
49+
removeReplaySymbolSuffix(selectedSource).toUpperCase();
4150
const formattedDataSource = capitalCase(dataSource);
4251
let priceChangeClassName: Nullish<string> = "";
4352

@@ -55,7 +64,21 @@ export function PythProDemoCard({
5564
className={classes.root}
5665
nonInteractive
5766
title={
58-
<span style={{ color: getColorForSymbol(dataSource) }}>
67+
<span
68+
className={classes.dataSourceName}
69+
style={{ color: getColorForDataSource(dataSource) }}
70+
>
71+
<Button
72+
aria-label={toggleVisibilityTooltip}
73+
className={classes.toggleVisibilityBtn ?? ""}
74+
onPress={() => {
75+
toggleDataSourceVisibility(dataSource);
76+
}}
77+
size="sm"
78+
variant="ghost"
79+
>
80+
{sourceVisible ? <Eye /> : <EyeSlash />}
81+
</Button>
5982
{formattedDataSource}
6083
</span>
6184
}
Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
@use "@pythnetwork/component-library/theme";
22

3-
.root {
4-
height: 300px;
3+
.buttons {
4+
align-items: center;
5+
display: flex;
6+
flex-grow: 0;
7+
flex-shrink: 0;
8+
gap: theme.spacing(2);
9+
justify-content: flex-end;
10+
}
11+
12+
.chartContainer {
13+
flex-grow: 1;
14+
flex-shrink: 0;
15+
}
516

6-
@include theme.breakpoint("sm") {
7-
height: 600px;
8-
}
17+
.verticalDivider {
18+
background-color: theme.color("border");
19+
height: theme.spacing(6);
20+
width: 1px;
21+
}
922

10-
& > canvas {
11-
height: 100%;
12-
width: 100%;
13-
}
23+
.root {
24+
display: flex;
25+
flex-flow: column;
26+
gap: theme.spacing(2);
27+
height: theme.spacing(110);
28+
position: relative;
29+
width: 100%;
1430
}

0 commit comments

Comments
 (0)