Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const GET = async (
const filteredFeeds = feeds.filter((feed) =>
feed.price.priceComponents.some((c) => c.publisher === publisher),
);

return new Response(stringify(filteredFeeds), {
headers: {
"Content-Type": "application/json",
Expand Down
60 changes: 19 additions & 41 deletions apps/insights/src/components/Explanations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,25 @@ export const ExplainPermissioned = ({
scoreTime,
}: {
scoreTime?: Date | undefined;
}) => {
return (
<Explain size="xs" title="Permissioned Feeds">
<p>
This is the number of <b>Price Feeds</b> that a <b>Publisher</b> has
permissions to publish to. The publisher is not necessarily pushing data
for all the feeds they have access to, and some feeds may not be live
yet.
</p>
{scoreTime && <EvaluationTime scoreTime={scoreTime} />}
</Explain>
);
};
}) => (
<Explain size="xs" title="Permissioned Feeds">
<p>
This is the number of <b>Price Feeds</b> that a <b>Publisher</b> has
permissions to publish to. The publisher is not necessarily pushing data
for all the feeds they have access to, and some feeds may not be live yet.
</p>
{scoreTime && <EvaluationTime scoreTime={scoreTime} />}
</Explain>
);

export const ExplainUnpermissioned = () => (
<Explain size="xs" title="Unpermissioned Feeds">
<p>
This is the number of <b>Price Feeds</b> that a <b>Publisher</b> does not
have permissions to publish to.
</p>
</Explain>
);

export const ExplainAverage = ({
scoreTime,
Expand Down Expand Up @@ -96,31 +102,3 @@ export const EvaluationTime = ({ scoreTime }: { scoreTime: Date }) => {
</p>
);
};

export const ExplainActive = () => (
<Explain size="xs" title="Active Feeds">
<p>
This is the number of feeds which the publisher is permissioned for, where
the publisher{"'"}s feed has 50% or better uptime over the last day.
</p>
<NeitherActiveNorInactiveNote />
</Explain>
);

export const ExplainInactive = () => (
<Explain size="xs" title="Inactive Feeds">
<p>
This is the number of feeds which the publisher is permissioned for, but
for which the publisher{"'"}s feed has less than 50% uptime over the last
day.
</p>
<NeitherActiveNorInactiveNote />
</Explain>
);

const NeitherActiveNorInactiveNote = () => (
<p>
Note that a publisher{"'"}s feed may not be considered either active or
inactive if Pyth has not yet calculated quality rankings for it.
</p>
);
24 changes: 15 additions & 9 deletions apps/insights/src/components/PriceComponentDrawer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ import type { CategoricalChartState } from "recharts/types/chart/types";
import { z } from "zod";

import { Cluster, ClusterToName } from "../../services/pyth";
import type { Status } from "../../status";
import ConformanceReport from "../ConformanceReport/conformance-report";
import type { Interval } from "../ConformanceReport/types";
import { useDownloadReportForFeed } from "../ConformanceReport/use-download-report-for-feed";
import { LiveComponentValue, LiveConfidence, LivePrice } from "../LivePrices";
import { PriceName } from "../PriceName";
import { Score } from "../Score";
import { Status as StatusComponent } from "../Status";
import { StatusLive } from "../Status";
import styles from "./index.module.scss";
import type { Interval } from "../ConformanceReport/types";
import { useDownloadReportForFeed } from "../ConformanceReport/use-download-report-for-feed";

const LineChart = dynamic(
() => import("recharts").then((recharts) => recharts.LineChart),
Expand All @@ -61,7 +60,6 @@ type PriceComponent = {
feedKey: string;
score: number | undefined;
rank: number | undefined;
status: Status;
identifiesPublisher?: boolean | undefined;
firstEvaluation?: Date | undefined;
cluster: Cluster;
Expand Down Expand Up @@ -137,16 +135,20 @@ export const usePriceComponentDrawer = ({
<RouterProvider navigate={navigate}>
<HeadingExtra
identifiesPublisher={identifiesPublisher}
status={component.status}
cluster={component.cluster}
publisherKey={component.publisherKey}
symbol={component.symbol}
feedKey={component.feedKey}
/>
</RouterProvider>
),
headingAfter: (
<div className={styles.badges}>
<StatusComponent status={component.status} />
<StatusLive
cluster={component.cluster}
feedKey={component.feedKey}
publisherKey={component.publisherKey}
/>
</div>
),
contents: (
Expand Down Expand Up @@ -267,11 +269,11 @@ export const usePriceComponentDrawer = ({
};

type HeadingExtraProps = {
status: Status;
identifiesPublisher?: boolean | undefined;
cluster: Cluster;
publisherKey: string;
symbol: string;
feedKey: string;
};

const HeadingExtra = ({ status, ...props }: HeadingExtraProps) => {
Expand All @@ -293,7 +295,11 @@ const HeadingExtra = ({ status, ...props }: HeadingExtraProps) => {
<>
<ConformanceReport onClick={handleDownloadReport} />
<div className={styles.bigScreenBadges}>
<StatusComponent status={status} />
<StatusLive
cluster={props.cluster}
feedKey={feedKey}
publisherKey={props.publisherKey}
/>
</div>
<OpenButton
variant="ghost"
Expand Down
10 changes: 8 additions & 2 deletions apps/insights/src/components/PriceComponentsCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export type PriceComponent = {
deviationScore: number | undefined;
stalledScore: number | undefined;
cluster: Cluster;
status: StatusType;
status?: StatusType;
feedKey: string;
publisherKey: string;
name: ReactNode;
Expand Down Expand Up @@ -120,6 +120,7 @@ export const ResolvedPriceComponentsCard = <
const logger = useLogger();
const collator = useCollator();
const filter = useFilter({ sensitivity: "base", usage: "search" });

const { selectComponent } = usePriceComponentDrawer({
components: priceComponents,
identifiesPublisher,
Expand Down Expand Up @@ -186,6 +187,9 @@ export const ResolvedPriceComponentsCard = <
}

case "status": {
if (a.status === undefined || b.status === undefined) {
return 0;
}
const resultByStatus = b.status - a.status;
const result =
resultByStatus === 0
Expand Down Expand Up @@ -267,7 +271,9 @@ export const ResolvedPriceComponentsCard = <
cluster={component.cluster}
/>
),
status: <StatusComponent status={component.status} />,
status: component.status !== undefined && (
<StatusComponent status={component.status} />
),
},
})),
[paginatedItems, props.extraColumns, selectComponent],
Expand Down
27 changes: 23 additions & 4 deletions apps/insights/src/components/PriceFeed/publishers-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import { Switch } from "@pythnetwork/component-library/Switch";
import { useLogger } from "@pythnetwork/component-library/useLogger";
import { useQueryState, parseAsBoolean } from "nuqs";
import { parseAsBoolean, useQueryState } from "nuqs";
import { Suspense, useCallback, useMemo } from "react";

import { useLivePriceData } from "../../hooks/use-live-price-data";
import { Cluster } from "../../services/pyth";
import type { PriceComponent } from "../PriceComponentsCard";
import { PriceComponentsCard } from "../PriceComponentsCard";
import { PublisherTag } from "../PublisherTag";
import { getStatus } from "../Status";

type PublishersCardProps =
| { isLoading: true }
Expand All @@ -29,7 +31,10 @@ type ResolvedPublishersCardProps = {
symbol: string;
displaySymbol: string;
assetClass: string;
publishers: Omit<PriceComponent, "symbol" | "displaySymbol" | "assetClass">[];
publishers: Omit<
PriceComponent,
"status" | "symbol" | "displaySymbol" | "assetClass"
>[];
metricsTime?: Date | undefined;
};

Expand All @@ -38,6 +43,7 @@ const ResolvedPublishersCard = ({
...props
}: ResolvedPublishersCardProps) => {
const logger = useLogger();
const data = useLivePriceData(Cluster.Pythnet, publishers[0]?.feedKey);

const [includeTestFeeds, setIncludeTestFeeds] = useQueryState(
"includeTestFeeds",
Expand All @@ -63,22 +69,35 @@ const ResolvedPublishersCard = ({
[includeTestFeeds, publishers],
);

const publishersWithStatus = useMemo(() => {
return publishersFilteredByCluster.map((publisher) => {
return {
...publisher,
status: getStatus(data.current, publisher.publisherKey),
};
});
}, [publishersFilteredByCluster, data]);

return (
<PublishersCardImpl
includeTestFeeds={includeTestFeeds}
updateIncludeTestFeeds={updateIncludeTestFeeds}
publishers={publishersFilteredByCluster}
publishers={publishersWithStatus}
{...props}
/>
);
};

type PublishersCardImplProps =
| { isLoading: true }
| (ResolvedPublishersCardProps & {
| (Omit<ResolvedPublishersCardProps, "publishers"> & {
isLoading?: false | undefined;
includeTestFeeds: boolean;
updateIncludeTestFeeds: (newValue: boolean) => void;
publishers: Omit<
PriceComponent,
"symbol" | "displaySymbol" | "assetClass"
>[];
});

const PublishersCardImpl = (props: PublishersCardImplProps) => (
Expand Down
6 changes: 1 addition & 5 deletions apps/insights/src/components/PriceFeed/publishers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
} from "../../server/pyth";
import { getRankingsBySymbol } from "../../services/clickhouse";
import { Cluster, ClusterToName } from "../../services/pyth";
import { getStatus } from "../../status";
import { PublisherIcon } from "../PublisherIcon";
import { PublisherTag } from "../PublisherTag";
import { PublishersCard } from "./publishers-card";
Expand All @@ -34,7 +33,6 @@ export const Publishers = async ({ params }: Props) => {
const metricsTime = pythnetPublishers.find(
(publisher) => publisher.ranking !== undefined,
)?.ranking?.time;

return feed === undefined ? (
notFound()
) : (
Expand All @@ -44,7 +42,7 @@ export const Publishers = async ({ params }: Props) => {
displaySymbol={feed.product.display_symbol}
assetClass={feed.product.asset_type}
publishers={publishers.map(
({ ranking, publisher, status, cluster, knownPublisher }) => ({
({ ranking, publisher, cluster, knownPublisher }) => ({
id: `${publisher}-${ClusterToName[cluster]}`,
feedKey:
cluster === Cluster.Pythnet
Expand All @@ -55,7 +53,6 @@ export const Publishers = async ({ params }: Props) => {
deviationScore: ranking?.deviation_score,
stalledScore: ranking?.stalled_score,
cluster,
status,
publisherKey: publisher,
rank: ranking?.final_rank,
firstEvaluation: ranking?.first_ranking_time,
Expand Down Expand Up @@ -94,7 +91,6 @@ const getPublishers = async (cluster: Cluster, symbol: string) => {
return {
ranking,
publisher,
status: getStatus(ranking),
cluster,
knownPublisher: lookupPublisher(publisher),
};
Expand Down
2 changes: 0 additions & 2 deletions apps/insights/src/components/Publisher/get-price-feeds.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getFeedsForPublisherRequest } from "../../server/pyth";
import { getRankingsByPublisher } from "../../services/clickhouse";
import { Cluster, ClusterToName } from "../../services/pyth";
import { getStatus } from "../../status";

export const getPriceFeeds = async (cluster: Cluster, key: string) => {
const [feeds, rankings] = await Promise.all([
Expand All @@ -17,7 +16,6 @@ export const getPriceFeeds = async (cluster: Cluster, key: string) => {
return {
ranking,
feed,
status: getStatus(ranking),
};
});
};
Loading
Loading