Skip to content
Merged
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
130 changes: 54 additions & 76 deletions dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import { DashboardHeader } from "./common/headerComponents/DashboardHeader";
import { dashboardVersion, DashboardVersion } from "./common/DashboardVersion";
import { Route, Routes } from "react-router";
import { useEffect, useMemo, useState } from "react";
import { NewClient, schemaMapping, enhanceHealthMetrics } from "./utils";
import { NewClient, schemaMapping, enhanceHealthMetrics, processDeploymentData } from "./utils";
import { useQuery } from "@apollo/client";
import { decentralizedNetworkSubgraphsQuery } from "./queries/decentralizedNetworkSubgraphsQuery";

function App() {
console.log("RUNNING VERSION " + dashboardVersion);
const [loading, setLoading] = useState(false);
const [protocolsToQuery, setProtocolsToQuery] = useState<{
[type: string]: { [proto: string]: { [network: string]: string } };
}>({});

const [protocolsToQuery, setProtocolsToQuery] = useState<any>({});
const [issuesMapping, setIssuesMapping] = useState<any>({});
// Add cache timestamp state
const [lastFetchTime, setLastFetchTime] = useState<number>(0);
// Cache expiry time - 15 minutes (in milliseconds)
const CACHE_EXPIRY_TIME = 15 * 60 * 1000;

const getGithubRepoIssues = () => {
try {
Expand Down Expand Up @@ -52,56 +53,56 @@ function App() {
const getDeployments = () => {
if (Object.keys(protocolsToQuery).length === 0) {
setLoading(true);

// Check if cache is still valid (less than 15 minutes old)
const currentTime = Date.now();
const shouldUseCachedData = currentTime - lastFetchTime < CACHE_EXPIRY_TIME;

// If we have cached data that's still valid, use it from local storage
if (shouldUseCachedData) {
try {
const cachedData = localStorage.getItem("deploymentData");
if (cachedData) {
const parsedData = JSON.parse(cachedData);
setProtocolsToQuery(parsedData);
setLoading(false);
console.log("Using cached deployment data");
return;
}
} catch (error) {
console.error("Error retrieving cached data:", error);
// Continue with fetch if cache retrieval fails
}
}

try {
fetch(process.env.REACT_APP_MESSARI_STATUS_URL!, {
method: "GET",
headers: {
Accept: "application/json",
"x-messari-api-key": process.env.REACT_APP_MESSARI_API_KEY!,
},
})
.then(function (res) {
return res.json();
})
.then(function (json) {
// Fetch the raw deployment data directly from GitHub
fetch("https://raw.githubusercontent.com/messari/subgraphs/master/deployment/deployment.json")
.then((response) => response.json())
.then((deploymentData) => {
// Process the deployment data on the fly
const processedData = processDeploymentData(deploymentData);
setLoading(false);
// Hacky fix for the subgraph status API returning an error response, setting protocols to empty object.
// Status Page Will Not Load With This Condition, but the charting will work.
if (JSON.stringify(Object.keys(json)) == JSON.stringify(['error', 'data'])) {
console.log("Error Response from Messari Subgraph Status API. Setting protocols to empty object.");
json = {};
}

// Process the data to ensure all health metrics are properly populated
if (json && typeof json === 'object') {
try {
Object.keys(json).forEach(protocolName => {
const protocol = json[protocolName];
if (protocol.deployments) {
Object.keys(protocol.deployments).forEach(deploymentKey => {
// Enhance the health metrics of each deployment
protocol.deployments[deploymentKey] = enhanceHealthMetrics(protocol.deployments[deploymentKey]);
});

// Debug the first protocol's health metrics
if (Object.keys(json).length > 0) {
debugHealthMetrics(protocol);
}
}
});
} catch (err) {
console.error("Error enhancing health metrics:", err);
}
setProtocolsToQuery(processedData);

// Update cache timestamp and store the processed data in localStorage
setLastFetchTime(currentTime);
try {
localStorage.setItem("deploymentData", JSON.stringify(processedData));
} catch (cacheError) {
console.error("Error caching deployment data:", cacheError);
}

setProtocolsToQuery(json);
})
.catch((err) => {
console.log(err);
setLoading(false);
console.error("Error loading deployment data from GitHub:", err);
// Show empty state instead of trying to fallback to the deleted file
setProtocolsToQuery({});
});
} catch (error) {
setLoading(false);
console.error(error);
console.error("Error in getDeployments:", error);
setProtocolsToQuery({});
}
}
};
Expand All @@ -127,7 +128,7 @@ function App() {
subgraphEndpoints[schemaType][protocolName] = {};
}
}
if (protocol.deployments && typeof protocol.deployments === 'object') {
if (protocol.deployments && typeof protocol.deployments === "object") {
Object.values(protocol.deployments).forEach((depoData: any) => {
if (!depoData?.services) {
return;
Expand Down Expand Up @@ -219,35 +220,12 @@ function App() {
});
setDecentralizedDeployments(decenDepos);
}
}, [decentralized]);

const debugHealthMetrics = (protocol: any) => {
if (!protocol || !protocol.deployments) {
console.warn("No protocol or deployments data found for debugging");
return;
}

try {
// Log a sample of health metrics for the first deployment
const firstDeploymentKey = Object.keys(protocol.deployments)[0];
if (!firstDeploymentKey) {
console.warn("No deployments found for debugging");
return;
}

const deployment = protocol.deployments[firstDeploymentKey];
if (!deployment || !deployment.services) {
console.warn("Invalid deployment data for debugging");
return;
}

const hostedService = deployment.services["hosted-service"];
const decentralizedNetwork = deployment.services["decentralized-network"];
}, [decentralized, decentralizedDeployments]);

} catch (err) {
console.error("Error in debug health metrics:", err);
}
};
// Remove this useEffect when the API service is back online
useEffect(() => {
getDeployments();
}, []); // eslint-disable-line react-hooks/exhaustive-deps

return (
<div>
Expand Down
23 changes: 1 addition & 22 deletions dashboard/src/deployments/DeploymentsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function DeploymentsPage({
navigate(`subgraph?endpoint=${val}&tab=protocol`);
}
}}
placeholder="Subgraph query name ie. messari/balancer-v2-ethereum"
placeholder="Enter subgraph QM hash e.g. QmXMJ2Hnhhoz6bGFNtTBjnf7kAk9CNCQG7r4R5b7fyVjD7"
>
Load Subgraph
</SearchInput>
Expand All @@ -128,27 +128,6 @@ function DeploymentsPage({
>
{showSubgraphCountTable ? "Hide" : "Show"} Subgraph Count Table
</span>
<span
style={{
width: "0",
flex: "1 1 0",
textAlign: "center",
marginTop: "0",
borderRight: "#6656F8 2px solid",
padding: "0 30px",
}}
className="Menu-Options"
onClick={() => navigate("protocols-list")}
>
Protocols To Develop
</span>
<span
style={{ padding: "0 30px", borderRight: "#6656F8 2px solid" }}
className="Menu-Options"
onClick={() => navigate("version-comparison")}
>
Version Comparison
</span>
<span
style={{ padding: "0 30px" }}
className="Menu-Options"
Expand Down
78 changes: 41 additions & 37 deletions dashboard/src/deployments/DeploymentsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,10 @@ function DeploymentsTable({ protocolsToQuery, issuesMapping, getData, decenDepos
if (!deploymentData?.services) {
return;
}

// Enhance the health metrics data
const enhancedDeploymentData = enhanceHealthMetrics(deploymentData);

if (
!!enhancedDeploymentData["services"]["hosted-service"] ||
!!enhancedDeploymentData["services"]["decentralized-network"] ||
Expand Down Expand Up @@ -219,14 +219,24 @@ function DeploymentsTable({ protocolsToQuery, issuesMapping, getData, decenDepos
enhancedDeploymentData?.versions?.methodology,
)
) {
deposToPass[protocol.schema][protocolName]?.methodologyVersions?.push(enhancedDeploymentData?.versions?.methodology);
deposToPass[protocol.schema][protocolName]?.methodologyVersions?.push(
enhancedDeploymentData?.versions?.methodology,
);
}
if (
!deposToPass[protocol.schema][protocolName]?.subgraphVersions?.includes(enhancedDeploymentData?.versions?.subgraph)
!deposToPass[protocol.schema][protocolName]?.subgraphVersions?.includes(
enhancedDeploymentData?.versions?.subgraph,
)
) {
deposToPass[protocol.schema][protocolName]?.subgraphVersions?.push(enhancedDeploymentData?.versions?.subgraph);
deposToPass[protocol.schema][protocolName]?.subgraphVersions?.push(
enhancedDeploymentData?.versions?.subgraph,
);
}
if (!deposToPass[protocol.schema][protocolName]?.schemaVersions?.includes(enhancedDeploymentData?.versions?.schema)) {
if (
!deposToPass[protocol.schema][protocolName]?.schemaVersions?.includes(
enhancedDeploymentData?.versions?.schema,
)
) {
deposToPass[protocol.schema][protocolName]?.schemaVersions?.push(enhancedDeploymentData?.versions?.schema);
}
if (enhancedDeploymentData?.status === "dev") {
Expand All @@ -241,27 +251,33 @@ function DeploymentsTable({ protocolsToQuery, issuesMapping, getData, decenDepos
{Object.entries(deposToPass)
.sort((a, b) => {
// Sections to move to the bottom
const bottomSections = ['bridge', 'erc20', 'erc721'];
const bottomSections = ["bridge", "erc20", "erc721"];

// If a is a bottom section and b is not, move a down
if (bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
!bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase()))
if (
bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
!bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase())
)
return 1;

// If b is a bottom section and a is not, move b down
if (!bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase()))
if (
!bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase())
)
return -1;

// If both are bottom sections, sort them alphabetically among themselves
if (bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase())) {
if (
bottomSections.includes(schemaMapping[a[0]] || a[0].toLowerCase()) &&
bottomSections.includes(schemaMapping[b[0]] || b[0].toLowerCase())
) {
// Order within bottom sections: erc20, erc721, bridge
const aIndex = bottomSections.indexOf(schemaMapping[a[0]] || a[0].toLowerCase());
const bIndex = bottomSections.indexOf(schemaMapping[b[0]] || b[0].toLowerCase());
return aIndex - bIndex;
}

// For all other schemas, keep alphabetical order
return a[0].localeCompare(b[0]);
})
Expand Down Expand Up @@ -404,14 +420,14 @@ function DeploymentsTable({ protocolsToQuery, issuesMapping, getData, decenDepos
additionalStyles = { minHeight: "510px", overflow: "hidden" };
}
return (
<TableContainer
sx={{
my: 8,
<TableContainer
sx={{
my: 8,
...additionalStyles,
'& .MuiTableCell-root': {
borderBottom: 'none'
}
}}
"& .MuiTableCell-root": {
borderBottom: "none",
},
}}
key={"TableContainer-" + schemaType.toUpperCase()}
className="continuous-table-borders"
>
Expand Down Expand Up @@ -442,19 +458,7 @@ function DeploymentsTable({ protocolsToQuery, issuesMapping, getData, decenDepos
</span>
</Typography>
</div>
{schemaMapping[schemaType] ? (
<>
{executeDownloadCSV}
<MultiSelectDropDown
optionsList={validDeployments}
optionsSelected={deposSelected[schemaMapping[schemaType]]}
setOptionsSelected={(x: any) =>
setDeposSelected({ ...deposSelected, [schemaMapping[schemaType]]: x })
}
label="Deployment Selection"
/>
</>
) : null}
{schemaMapping[schemaType] ? <>{executeDownloadCSV}</> : null}
<Table stickyHeader className="continuous-table">
{tableHead}
<TableBody>{tableRows}</TableBody>
Expand Down
Loading
Loading