Skip to content

Commit 4eb4428

Browse files
uri-99OppenMarcosNicolauPatStilesavilagaston9
authored
feat(explorer): New Version (#1658)
Co-authored-by: Mario Rugiero <[email protected]> Co-authored-by: Marcos Nicolau <[email protected]> Co-authored-by: PatStiles <[email protected]> Co-authored-by: Avila Gastón <[email protected]> Co-authored-by: Marcos Nicolau <[email protected]> Co-authored-by: nicolau <[email protected]>
1 parent dadd1e1 commit 4eb4428

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

+1637
-389
lines changed

explorer/.env.dev

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ DEBUG_ERRORS=true
2222
TRACKER_API_URL=http://localhost:3030
2323

2424
MAX_BATCH_SIZE=268435456 # 256 MiB
25+
26+
# Time we wait for a batch to be verified before marking it stale
27+
BATCH_TTL_MINUTES=5

explorer/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ DEBUG_ERRORS=<true|false>
2020

2121
# Tracker API
2222
TRACKER_API_URL=<tracker_api_url>
23+
24+
# Time we wait for a batch to be verified before marking it stale
25+
BATCH_TTL_MINUTES=5

explorer/assets/css/app.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@import "tailwindcss/base";
22
@import "tailwindcss/components";
33
@import "tailwindcss/utilities";
4+
@import "./tooltip.css";
45

56
@layer base {
67
:root {

explorer/assets/css/tooltip.css

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
.chart-tooltip-container {
2+
display: flex;
3+
flex-direction: column;
4+
align-items: center;
5+
position: relative;
6+
}
7+
8+
.chart-tooltip-dot {
9+
height: 10px;
10+
width: 10px;
11+
bottom: -5px;
12+
border-radius: 100%;
13+
background-color: hsl(var(--accent));
14+
position: absolute;
15+
transition: all 0.2s;
16+
}
17+
18+
.chart-tooltip-dot:hover {
19+
transform: scale(1.2);
20+
cursor: pointer;
21+
}
22+
23+
.chart-tooltip-items-container {
24+
min-height: 50px;
25+
min-width: 250px;
26+
padding: 20px;
27+
margin-bottom: 8px;
28+
background-color: hsl(var(--card));
29+
border-radius: 8px;
30+
border-width: 1px;
31+
border-color: hsl(var(--foreground) / 20%);
32+
}
33+
34+
.chart-tooltip-title {
35+
text-align: center;
36+
color: hsl(var(--foreground));
37+
margin-bottom: 10px;
38+
font-weight: 700;
39+
}
40+
41+
.chart-tooltip-items {
42+
display: flex;
43+
flex-direction: column;
44+
gap: 5px;
45+
}
46+
47+
.chart-tooltip-item {
48+
display: flex;
49+
justify-content: space-between;
50+
gap: 5px;
51+
width: 100%;
52+
}
53+
54+
.chart-tooltip-item-title {
55+
color: hsl(var(--muted-foreground));
56+
}
57+
58+
.chart-tooltip-item-value {
59+
color: hsl(var(--foreground));
60+
}
61+

explorer/assets/js/app.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,30 @@ import darkModeHook from "../vendor/dark_mode";
77
import searchFocusHook from "../vendor/search_focus";
88
import tooltipHook from "../vendor/tooltip";
99
import copyToClipboardHook from "../vendor/clipboard";
10+
import chartHook from "../vendor/charts";
1011

11-
let Hooks = {};
12-
Hooks.DarkThemeToggle = darkModeHook;
13-
Hooks.SearchFocus = searchFocusHook;
14-
Hooks.TooltipHook = tooltipHook;
15-
Hooks.CopyToClipboard = copyToClipboardHook;
12+
let hooks = {};
13+
hooks.DarkThemeToggle = darkModeHook;
14+
hooks.SearchFocus = searchFocusHook;
15+
hooks.TooltipHook = tooltipHook;
16+
hooks.CopyToClipboard = copyToClipboardHook;
17+
hooks.ChartHook = chartHook;
1618

1719
let csrfToken = document
1820
.querySelector("meta[name='csrf-token']")
1921
.getAttribute("content");
2022

2123
let liveSocket = new LiveSocket("/live", Socket, {
2224
params: { _csrf_token: csrfToken },
23-
hooks: Hooks
25+
hooks: hooks,
2426
});
2527

2628
topbar.config({
2729
barColors: { 0: "#18FF7F" },
2830
shadowColor: "rgba(0, 0, 0, .3)"
2931
});
30-
window.addEventListener("phx:page-loading-start", (_info) =>
31-
topbar.show(50)
32-
);
33-
window.addEventListener("phx:page-loading-stop", (_info) =>
34-
topbar.hide()
35-
);
32+
window.addEventListener("phx:page-loading-start", (_info) => topbar.show(50));
33+
window.addEventListener("phx:page-loading-stop", (_info) => topbar.hide());
3634

3735
liveSocket.connect();
3836

explorer/assets/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"dependencies": {
3-
"@floating-ui/dom": "^1.6.8"
3+
"@floating-ui/dom": "^1.6.8",
4+
"chart.js": "^4.4.7"
45
},
56
"devDependencies": {
67
"tailwindcss-animate": "^1.0.7"

explorer/assets/pnpm-lock.yaml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { yTickCallbackShowMinAndMaxValues } from "./helpers";
2+
import { alignedTooltip } from "./tooltip";
3+
4+
export const batchSizeCustomOptions = (options, data) => {
5+
// show only min and max values
6+
options.scales.y.ticks.callback = yTickCallbackShowMinAndMaxValues(
7+
data,
8+
(val) => `${val} proofs`
9+
);
10+
11+
// show age min, mean and max age in x axis
12+
options.scales.x.ticks.callback = (_value, index, values) => {
13+
const age = data.datasets[0].age;
14+
if (index === 0) return age[0];
15+
if (index === Math.floor((age.length - 1) / 2))
16+
return age[Math.floor((age.length - 1) / 2)];
17+
if (index === values.length - 1) return age[age.length - 1];
18+
return "";
19+
};
20+
21+
options.plugins.tooltip.external = (context) =>
22+
alignedTooltip(context, {
23+
name: "batch-size",
24+
title: "Batch size",
25+
items: [
26+
{ title: "Fee per proof", id: "cost" },
27+
{ title: "Age", id: "age" },
28+
{ title: "Merkle root", id: "merkle_root" },
29+
{ title: "Block number", id: "block_number" },
30+
{ title: "Amount of proofs", id: "amount_of_proofs" },
31+
],
32+
onTooltipClick: (tooltipModel) => {
33+
const dataset = tooltipModel.dataPoints[0].dataset;
34+
const idx = tooltipModel.dataPoints[0].dataIndex;
35+
const merkleRootHash = dataset.merkle_root[idx];
36+
window.location.href = `/batches/${merkleRootHash}`;
37+
},
38+
onTooltipUpdate: (tooltipModel) => {
39+
const dataset = tooltipModel.dataPoints[0].dataset;
40+
const idx = tooltipModel.dataPoints[0].dataIndex;
41+
const amount_of_proofs = dataset.data[idx].y;
42+
const age = dataset.age[idx];
43+
const merkleRootHash = dataset.merkle_root[idx];
44+
const merkle_root = `${merkleRootHash.slice(
45+
0,
46+
6
47+
)}...${merkleRootHash.slice(merkleRootHash.length - 4)}`;
48+
const block_number = dataset.data[idx].x;
49+
const cost = `${dataset.fee_per_proof[idx]} USD`;
50+
51+
return {
52+
cost,
53+
age,
54+
merkle_root,
55+
block_number,
56+
amount_of_proofs,
57+
};
58+
},
59+
});
60+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { yTickCallbackShowMinAndMaxValues } from "./helpers";
2+
import { alignedTooltip } from "./tooltip";
3+
4+
export const costPerProofCustomOptions = (options, data) => {
5+
// show only 0, min and max values
6+
options.scales.y.ticks.callback = yTickCallbackShowMinAndMaxValues(
7+
data,
8+
(val) => `${val} USD`
9+
);
10+
11+
// show age min, mean and max age in x axis
12+
options.scales.x.ticks.callback = (_value, index, values) => {
13+
const age = data.datasets[0].age;
14+
if (index === 0) return age[0];
15+
if (index === Math.floor((age.length - 1) / 2))
16+
return age[Math.floor((age.length - 1) / 2)];
17+
if (index === values.length - 1) return age[age.length - 1];
18+
return "";
19+
};
20+
21+
options.plugins.tooltip.external = (context) =>
22+
alignedTooltip(context, {
23+
name: "cost-per-proof",
24+
title: "Cost per proof",
25+
items: [
26+
{ title: "Fee per proof", id: "cost" },
27+
{ title: "Age", id: "age" },
28+
{ title: "Merkle root", id: "merkle_root" },
29+
{ title: "Block number", id: "block_number" },
30+
{ title: "Amount of proofs", id: "amount_of_proofs" },
31+
],
32+
onTooltipClick: (tooltipModel) => {
33+
const dataset = tooltipModel.dataPoints[0].dataset;
34+
const idx = tooltipModel.dataPoints[0].dataIndex;
35+
const merkleRootHash = dataset.merkle_root[idx];
36+
window.location.href = `/batches/${merkleRootHash}`;
37+
},
38+
onTooltipUpdate: (tooltipModel) => {
39+
const dataset = tooltipModel.dataPoints[0].dataset;
40+
const idx = tooltipModel.dataPoints[0].dataIndex;
41+
42+
const cost = `${dataset.data[idx].y} USD`;
43+
const age = dataset.age[idx];
44+
const merkleRootHash = dataset.merkle_root[idx];
45+
const merkle_root = `${merkleRootHash.slice(
46+
0,
47+
6
48+
)}...${merkleRootHash.slice(merkleRootHash.length - 4)}`;
49+
const block_number = dataset.data[idx].x;
50+
const amount_of_proofs = dataset.amount_of_proofs[idx];
51+
52+
return {
53+
cost,
54+
age,
55+
merkle_root,
56+
block_number,
57+
amount_of_proofs,
58+
};
59+
},
60+
});
61+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const findClosestIndex = (target, values) => {
2+
let closestIndex = 0;
3+
let smallestDiff = Math.abs(values[0] - target);
4+
for (let i = 1; i < values.length; i++) {
5+
const diff = Math.abs(values[i] - target);
6+
if (diff < smallestDiff) {
7+
closestIndex = i;
8+
smallestDiff = diff;
9+
}
10+
}
11+
return closestIndex;
12+
};
13+
14+
/**
15+
* A callback function to customize y-axis tick labels by showing only the zero, minimum and maximum data values.
16+
*
17+
* @param {Object} data - The chart data object containing datasets and their values.
18+
* @param {Function} renderText - A function to format and render text for the tick labels.
19+
* @returns {Function} - A callback function for Chart.js tick customization.
20+
*
21+
* The returned function compares the current tick index with the indices of the values closest
22+
* to the minimum and maximum data points, and displays these values formatted using the
23+
* `renderText` function.
24+
*
25+
* @example
26+
* options.scales.y.ticks.callback = yTickCallbackShowMinAndMaxValues(data, (val) => `${val} USD`);
27+
*/
28+
export const yTickCallbackShowMinAndMaxValues =
29+
(data, renderText) => (_value, index, values) => {
30+
if (index === 0) return renderText(0);
31+
32+
const dataY = data.datasets[0].data.map((point) => parseFloat(point.y));
33+
const sortedData = dataY.sort((a, b) => b - a);
34+
const min = sortedData[0];
35+
const max = sortedData[sortedData.length - 1];
36+
const valsData = values.map((item) => item.value);
37+
const idxClosestToMin = findClosestIndex(min, valsData);
38+
const idxClosestToMax = findClosestIndex(max, valsData);
39+
40+
if (index == idxClosestToMin) return renderText(min);
41+
if (index == idxClosestToMax) return renderText(max);
42+
return "";
43+
};

0 commit comments

Comments
 (0)