{
padding: 0 12px;
}
+.setting_item {
+ min-height: 24px;
+}
+
+.chart_selector {
+ padding: 4px 6px 4px 6px;
+ box-shadow: inset 0 0 0 1px var(--op-10);
+ border-radius: 5px;
+ cursor: pointer;
+ transition: all 1s ease-in-out;
+}
+
.data {
border-radius: 4px 4px 8px 8px;
background: var(--card-background);
diff --git a/components/modules/namespace/tables/BlobsTable.vue b/components/modules/namespace/tables/BlobsTable.vue
index 8ca07b9b..9a73aa1d 100644
--- a/components/modules/namespace/tables/BlobsTable.vue
+++ b/components/modules/namespace/tables/BlobsTable.vue
@@ -83,15 +83,15 @@ const handleViewBlob = (blob) => {
-
+
-
+
-
+
- {{ blob.signer }}
+ {{ blob.signer.hash }}
diff --git a/components/modules/navigation/NavLink.vue b/components/modules/navigation/NavLink.vue
index 7f9985c5..cb911566 100644
--- a/components/modules/navigation/NavLink.vue
+++ b/components/modules/navigation/NavLink.vue
@@ -10,6 +10,58 @@ const props = defineProps({
const isExpanded = ref(props.link.children?.some((l) => l.path === route.path) ? true : (props.link.name === 'Rollups' ? true : false))
+const isSubRouteActive = (link) => {
+ let res = false
+ if (link.queryParam) {
+ const queryString = route.fullPath.split('?')[1]
+ const params = new URLSearchParams(queryString)
+
+ for (const [key, value] of params.entries()) {
+ if (link.queryParam[key] === value) {
+ res = true
+ break;
+ }
+ }
+ }
+
+ return res
+}
+
+const isAnyChildrenActive = computed(() => {
+ let res = false
+
+ if (props.link.children?.length) {
+ for (const link of props.link.children) {
+ if (isSubRouteActive(link)) {
+ res = true
+ break;
+ }
+ }
+ }
+
+ return res
+})
+
+const isActive = computed(() => {
+ let res = false
+
+ if (props.link.queryParam) {
+ res = isSubRouteActive(props.link)
+ } else {
+ if (route.path?.includes("/txs")) {
+ if (props.link.name === "Transactions") {
+ res = !route.fullPath?.includes("message_type=MsgPayForBlobs")
+ } else if (props.link.name === "Pay for Blobs") {
+ res = route.fullPath?.includes("message_type=MsgPayForBlobs")
+ }
+ } else {
+ res = route.path === props.link.path
+ }
+ }
+
+ return res
+})
+
const handleClick = () => {
emit("onClose")
if (props.link.callback) props.link.callback()
@@ -18,7 +70,12 @@ const handleClick = () => {
-
+
{{ link.name }}
@@ -70,6 +127,16 @@ const handleClick = () => {
fill: var(--brand);
}
}
+
+ &.parentActive {
+ & span {
+ color: var(--txt-primary);
+ }
+
+ & .link_icon:first-of-type {
+ fill: var(--brand);
+ }
+ }
}
.chevron_icon {
diff --git a/components/modules/navigation/Search.vue b/components/modules/navigation/Search.vue
index a232586f..d9812cce 100644
--- a/components/modules/navigation/Search.vue
+++ b/components/modules/navigation/Search.vue
@@ -13,6 +13,9 @@ import Spinner from "@/components/ui/Spinner.vue"
/** API */
import { search } from "@/services/api/search"
+/** Services */
+import { shortHex } from "@/services/utils"
+
const wrapperEl = ref()
const inputRef = ref()
const searchTerm = ref("")
@@ -57,7 +60,20 @@ const debouncedSearch = useDebounceFn(async () => {
isSearching.value = true
const { data } = await search(searchTerm.value.trim())
- results.value = data.value
+ if (data.value?.length) {
+ results.value = data.value.map(res => {
+ const metadata = getResultMetadata(res)
+ return {
+ ...res,
+ type: metadata.type,
+ title: metadata.title,
+ subtitle: metadata.subtitle,
+ routerLink: metadata.routerLink,
+ }
+ })
+ } else {
+ results.value = []
+ }
isSearching.value = false
}, 250)
@@ -68,7 +84,7 @@ const handleInput = () => {
}
const getResultMetadata = (target) => {
- let metadata = { type: null, title: null, routerLink: null }
+ let metadata = { type: null, title: null, subtitle: null, routerLink: null }
switch (target.type.toLowerCase()) {
case "tx":
@@ -92,7 +108,7 @@ const getResultMetadata = (target) => {
case "address":
metadata.type = target.type
- metadata.title = target.result.alias || target.result.hash
+ metadata.title = target.result.celestials?.name || target.result.alias || target.result.hash
metadata.routerLink = `/address/${target.bookmark ? target.result.id : target.result.hash}`
break
@@ -152,11 +168,11 @@ const handleSelect = () => {
Results
-
-
-
-
- {{ getResultMetadata(result).title }}
+
+
+
+
+ {{ result.title }}
{{ result.type }}
@@ -202,7 +218,8 @@ const handleSelect = () => {
.popup {
position: absolute;
max-width: 600px;
- top: 40px;
+ /* top: 40px; */
+ top: calc(100% + 10px);
left: 0;
right: 0;
z-index: 1000;
@@ -239,19 +256,36 @@ const handleSelect = () => {
&:hover {
background: var(--op-5);
}
+
+ .title_wrapper {
+ width: 90%;
+
+ .title {
+ max-width: 100%;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+ }
}
@media (max-width: 800px) {
.wrapper {
- position: initial;
+ position: relative;
}
.popup {
max-width: initial;
- top: 160px;
+ /* top: 160px; */
left: 12px;
right: 12px;
}
+
+ .item {
+ .title_wrapper {
+ width: 70%;
+ }
+ }
}
diff --git a/components/modules/rollup/RollupCharts.vue b/components/modules/rollup/RollupCharts.vue
index ebbfbecc..c025c53e 100644
--- a/components/modules/rollup/RollupCharts.vue
+++ b/components/modules/rollup/RollupCharts.vue
@@ -9,13 +9,19 @@ import Button from "@/components/ui/Button.vue"
import { Dropdown, DropdownItem } from "@/components/ui/Dropdown"
import Input from "@/components/ui/Input.vue"
import Popover from "@/components/ui/Popover.vue"
+import Toggle from "@/components/ui/Toggle.vue"
+import Tooltip from "@/components/ui/Tooltip.vue"
/** Services */
import { abbreviate, formatBytes, sortArrayOfObjects, spaces, tia } from "@/services/utils"
/** API */
import { fetchRollupSeries } from "@/services/api/stats"
-import { fetchRollups } from "@/services/api/rollup"
+import { fetchRollups, fetchRollupTVL } from "@/services/api/rollup"
+
+/** Store */
+import { useSettingsStore } from "@/store/settings"
+const settingsStore = useSettingsStore()
const props = defineProps({
rollup: {
@@ -24,7 +30,8 @@ const props = defineProps({
},
})
-const selectedPeriodIdx = ref(0)
+/** Chart settings */
+const selectedPeriodIdx = ref(2)
const periods = ref([
{
title: "Last 24 hours",
@@ -48,20 +55,48 @@ const periods = ref([
},
])
const selectedPeriod = computed(() => periods.value[selectedPeriodIdx.value])
+const chartView = ref("line")
+const loadLastValue = ref(true)
+
+const isOpen = ref(false)
+const handleOpen = () => {
+ isOpen.value = true
+}
+const handleClose = () => {
+ isOpen.value = false
+}
+
+const handleChangeChartView = () => {
+ if (chartView.value === 'line') {
+ chartView.value = 'bar'
+ } else {
+ chartView.value = 'line'
+ }
+}
+
+const updateUserSettings = () => {
+ settingsStore.chart = {
+ ...settingsStore.chart,
+ view: chartView.value,
+ loadLastValue: loadLastValue.value,
+ }
+}
/** Charts */
const chartWrapperEl = ref()
const sizeSeriesChartEl = ref()
const pfbSeriesChartEl = ref()
const feeSeriesChartEl = ref()
+const tvlSeriesChartEl = ref()
const comparisonChartEl = ref()
-const barWidth = ref(0)
+const comparisonBarWidth = ref(0)
/** Data */
const isLoading = ref(false)
const sizeSeries = ref([])
const pfbSeries = ref([])
const feeSeries = ref([])
+const tvlSeries = ref([])
const rollupsList = ref()
const comparisonData = ref([])
const selectedRollup = ref()
@@ -70,7 +105,7 @@ const selectedRollup = ref()
const showSeriesTooltip = ref(false)
const showPfbTooltip = ref(false)
const showFeeTooltip = ref(false)
-const showComparisonTooltip = ref(false)
+const showTVLTooltip = ref(false)
const tooltipEl = ref()
const tooltipXOffset = ref(0)
const tooltipYOffset = ref(0)
@@ -82,13 +117,44 @@ const badgeEl = ref()
const badgeText = ref("")
const badgeOffset = ref(0)
-const buildChart = (chartEl, data, onEnter, onLeave) => {
+const getXAxisLabels = (start, tvl = false) => {
+ let res = ""
+
+ let tf = selectedPeriod.value.timeframe
+ let periodValue = selectedPeriod.value.value
+ if ( tvl && ["hour", "week"].includes(selectedPeriod.value.timeframe)) {
+ tf = "day"
+ periodValue = 30
+ }
+
+ switch (tf) {
+ case "month":
+ start
+ ? res = DateTime.now().minus({ months: periodValue - 1 }).toFormat("LLL y")
+ : res = loadLastValue.value ? DateTime.now().toFormat("LLL") : DateTime.now().minus({ months: 1 }).toFormat("LLL")
+ break;
+ case "day":
+ start
+ ? res = DateTime.now().minus({ days: periodValue - 1 }).toFormat("LLL dd")
+ : res = loadLastValue.value ? "Today" : DateTime.now().minus({ days: 1 }).toFormat("LLL dd")
+ break;
+ default:
+ start
+ ? res = DateTime.now().minus({ hours: periodValue - 1 }).set({ minutes: 0 }).toFormat("hh:mm a")
+ : res = loadLastValue.value ? "Now" : DateTime.now().minus({ hours: 1 }).set({ minutes: 0 }).toFormat("hh:mm a")
+ break;
+ }
+
+ return res
+}
+
+const buildLineChart = (chartEl, data, onEnter, onLeave, metric) => {
const width = chartWrapperEl.value.wrapper.getBoundingClientRect().width
const height = 180
const marginTop = 0
const marginRight = 0
const marginBottom = 24
- const marginLeft = 40
+ const marginLeft = 52
const MAX_VALUE = d3.max(data, (d) => d.value) ? d3.max(data, (d) => d.value) : 1
@@ -123,20 +189,25 @@ const buildChart = (chartEl, data, onEnter, onLeave) => {
}
}
+ let tf = selectedPeriod.value.timeframe
+ if (metric === "tvl" && ["hour", "week"].includes(selectedPeriod.value.timeframe)) {
+ tf = "day"
+ }
badgeText.value =
- selectedPeriod.value.timeframe === "month"
+ tf === "month"
? DateTime.fromJSDate(data[idx].date).toFormat("LLL")
- : selectedPeriod.value.timeframe === "day"
+ : tf === "day"
? DateTime.fromJSDate(data[idx].date).toFormat("LLL dd")
: DateTime.fromJSDate(data[idx].date).set({ minutes: 0 }).toFormat("hh:mm a")
if (!badgeEl.value) return
- if (idx < 2) {
+ const badgeWidth = badgeEl.value.getBoundingClientRect().width
+ if (tooltipXOffset.value - marginLeft < badgeWidth / 2) {
badgeOffset.value = 0
- } else if (idx > selectedPeriod.value.value - 3) {
- badgeOffset.value = badgeEl.value.getBoundingClientRect().width
+ } else if (badgeWidth + tooltipXOffset.value > width) {
+ badgeOffset.value = Math.abs(width - (badgeWidth + tooltipXOffset.value)) + ((data.length - 1 - idx) * 2)
} else {
- badgeOffset.value = badgeEl.value.getBoundingClientRect().width / 2
+ badgeOffset.value = badgeWidth / 2
}
}
const onPointerleft = () => {
@@ -177,27 +248,229 @@ const buildChart = (chartEl, data, onEnter, onLeave) => {
.attr("d", `M${0},${height - marginBottom - 6} L${width},${height - marginBottom - 6}`)
/** Chart Line */
+ let path1 = null
+ let path2 = null
+ path1 = svg
+ .append("path")
+ .attr("fill", "none")
+ .attr("stroke", "var(--brand)")
+ .attr("stroke-width", 2)
+ .attr("stroke-linecap", "round")
+ .attr("stroke-linejoin", "round")
+ .attr("d", line(loadLastValue.value ? data.slice(0, data.length - 1) : data))
+
+ if (loadLastValue.value) {
+ // Create pattern
+ const defs = svg.append("defs")
+ const pattern = defs.append("pattern")
+ .attr("id", "dashedPattern")
+ .attr("width", 8)
+ .attr("height", 2)
+ .attr("patternUnits", "userSpaceOnUse")
+ pattern.append("rect")
+ .attr("width", 4)
+ .attr("height", 2)
+ .attr("fill", "var(--brand)")
+ pattern.append("rect")
+ .attr("x", 8)
+ .attr("width", 4)
+ .attr("height", 2)
+ .attr("fill", "transparent")
+
+ // Last dash segment
+ path2 = svg
+ .append("path")
+ .attr("fill", "none")
+ .attr("stroke", "url(#dashedPattern)")
+ .attr("stroke-width", 2)
+ .attr("stroke-linecap", "round")
+ .attr("stroke-linejoin", "round")
+ .attr("d", line(data.slice(data.length - 2, data.length)))
+ }
+
+ const totalDuration = 1_000
+ const path1Duration = loadLastValue.value ? totalDuration / data.length * (data.length - 1) : totalDuration
+ const path1Length = path1.node().getTotalLength()
+
+ path1
+ .attr("stroke-dasharray", path1Length)
+ .attr("stroke-dashoffset", path1Length)
+ .transition()
+ .duration(path1Duration)
+ .ease(d3.easeLinear)
+ .attr("stroke-dashoffset", 0)
+
+ if (loadLastValue.value) {
+ const path2Duration = totalDuration / data.length
+ const path2Length = path2.node().getTotalLength() + 1
+
+ path2
+ .attr("stroke-dasharray", path2Length)
+ .attr("stroke-dashoffset", path2Length)
+ .transition()
+ .duration(path2Duration)
+ .ease(d3.easeLinear)
+ .delay(path1Duration)
+ .attr("stroke-dashoffset", 0)
+ }
+
+ const point = svg.append("circle")
+ .attr("cx", x(data[data.length - 1].date))
+ .attr("cy", y(data[data.length - 1].value))
+ .attr("fill", "var(--brand)")
+ .attr("r", 3)
+ .attr("opacity", 0)
+
+ point.transition()
+ .delay(totalDuration)
+ .duration(200)
+ .attr("opacity", 1)
+
+ if (chartEl.children[0]) chartEl.children[0].remove()
+ chartEl.append(svg.node())
+}
+
+const buildBarChart = (chartEl, data, onEnter, onLeave, metric) => {
+ const width = chartWrapperEl.value.wrapper.getBoundingClientRect().width
+ const height = 180
+ const marginTop = 0
+ const marginRight = 2
+ const marginBottom = 24
+ const marginLeft = 52
+
+ const barWidth = Math.max(Math.round((width - marginLeft - marginRight) / data.length - (data.length > 7 ? 4 : 8)), 4)
+
+ const MAX_VALUE = d3.max(data, (d) => d.value) ? d3.max(data, (d) => d.value) : 1
+
+ /** Scale */
+ const x = d3.scaleUtc(
+ d3.extent(data, (d) => d.date),
+ [marginLeft, width - marginRight - barWidth],
+ )
+ const y = d3.scaleLinear([0, MAX_VALUE], [height - marginBottom, marginTop])
+
+ /** Tooltip */
+ const bisect = d3.bisector((d) => d.date).center
+ const onPointermoved = (event) => {
+ onEnter()
+
+ // const idx = bisect(data, x.invert(d3.pointer(event)[0]))
+ const idx = bisect(data, x.invert(d3.pointer(event)[0] - barWidth / 2))
+
+ const elements = document.querySelectorAll(`[metric="${metric}"]`)
+ elements.forEach(el => {
+ if (+el.getAttribute('data-index') === idx) {
+ el.style.filter = "brightness(1.2)"
+ } else {
+ el.style.filter = "brightness(0.6)"
+ }
+
+ })
+
+ tooltipXOffset.value = x(data[idx].date)
+ tooltipYDataOffset.value = y(data[idx].value)
+ tooltipYOffset.value = event.layerY
+ tooltipText.value = data[idx].value
+
+ if (tooltipEl.value) {
+ if (idx > parseInt(selectedPeriod.value.value / 2)) {
+ tooltipDynamicXPosition.value = tooltipXOffset.value - tooltipEl.value.wrapper.getBoundingClientRect().width - 16
+ } else {
+ tooltipDynamicXPosition.value = tooltipXOffset.value + 16
+ }
+ }
+
+ let tf = selectedPeriod.value.timeframe
+ if (metric === "tvl" && ["hour", "week"].includes(selectedPeriod.value.timeframe)) {
+ tf = "day"
+ }
+ badgeText.value =
+ tf === "month"
+ ? DateTime.fromJSDate(data[idx].date).toFormat("LLL")
+ : tf === "day"
+ ? DateTime.fromJSDate(data[idx].date).toFormat("LLL dd")
+ : DateTime.fromJSDate(data[idx].date).set({ minutes: 0 }).toFormat("hh:mm a")
+
+ if (!badgeEl.value) return
+ const badgeWidth = badgeEl.value.getBoundingClientRect().width
+ if (tooltipXOffset.value - marginLeft < badgeWidth / 2) {
+ badgeOffset.value = 0
+ } else if (badgeWidth + tooltipXOffset.value > width) {
+ badgeOffset.value = Math.abs(width - (badgeWidth + tooltipXOffset.value)) + ((data.length - 1 - idx) * 2)
+ } else {
+ badgeOffset.value = (badgeWidth - barWidth) / 2
+ }
+ }
+ const onPointerleft = () => {
+ onLeave()
+
+ const elements = document.querySelectorAll('[data-index]')
+ elements.forEach(el => {
+ el.style.filter = ""
+ })
+ badgeText.value = ""
+ }
+
+ /** SVG Container */
+ const svg = d3
+ .create("svg")
+ .attr("width", width)
+ .attr("height", height)
+ .attr("viewBox", [0, 0, width, height])
+ .attr("preserveAspectRatio", "none")
+ .attr("style", "max-width: 100%; height: intrinsic;")
+ .style("-webkit-tap-highlight-color", "transparent")
+ .on("pointerenter pointermove", onPointermoved)
+ .on("pointerleave", onPointerleft)
+ .on("touchstart", (event) => event.preventDefault())
+
+ /** Vertical Lines */
svg.append("path")
.attr("fill", "none")
- .attr("stroke", "var(--brand)")
+ .attr("stroke", "var(--op-10)")
.attr("stroke-width", 2)
- .attr("stroke-linecap", "round")
- .attr("stroke-linejoin", "round")
- .attr("d", line(data.slice(0, data.length - 1)))
+ .attr("d", `M${marginLeft},${height - marginBottom + 2} L${marginLeft},${height - marginBottom - 5}`)
svg.append("path")
.attr("fill", "none")
- .attr("stroke", "var(--brand)")
+ .attr("stroke", "var(--op-10)")
.attr("stroke-width", 2)
- .attr("stroke-linecap", "round")
- .attr("stroke-linejoin", "round")
- .attr("stroke-dasharray", "8")
- .attr("d", line(data.slice(data.length - 2, data.length)))
+ .attr("d", `M${width - 1},${height - marginBottom + 2} L${width - 1},${height - marginBottom - 5}`)
- svg.append("circle")
- .attr("cx", x(data[data.length - 1].date))
- .attr("cy", y(data[data.length - 1].value))
- .attr("fill", "var(--brand)")
- .attr("r", 3)
+ /** Default Horizontal Line */
+ svg.append("path")
+ .attr("fill", "none")
+ .attr("stroke", "var(--op-10)")
+ .attr("stroke-width", 2)
+ .attr("d", `M${0},${height - marginBottom - 6} L${width},${height - marginBottom - 6}`)
+
+ /** Chart Bars */
+ svg.append("defs")
+ .append("pattern")
+ .attr("id", "diagonal-stripe")
+ .attr("width", 6)
+ .attr("height", 6)
+ .attr("patternUnits", "userSpaceOnUse")
+ .attr("patternTransform", "rotate(45)")
+ .append("rect")
+ .attr("width", 2)
+ .attr("height", 6)
+ .attr("transform", "translate(0,0)")
+ .attr("fill", "var(--brand)")
+
+ svg.append('g')
+ .selectAll("g")
+ .data(data)
+ .enter().append("rect")
+ .attr("class", "bar")
+ .attr('data-index', (d, i) => i)
+ .attr('metric', metric)
+ .attr("x", d => x(new Date(d.date)))
+ .attr('y', d => y(d.value))
+ .attr("width", barWidth)
+ .attr('fill', (d, i) => (loadLastValue.value && i === data.length - 1) ? `url(#diagonal-stripe)` : "var(--brand)")
+ .transition()
+ .duration(1_000)
+ .attr('height', d => Math.max(height - marginBottom - 6 - y(d.value), 0))
if (chartEl.children[0]) chartEl.children[0].remove()
chartEl.append(svg.node())
@@ -211,12 +484,12 @@ const getRollupsList = async () => {
rollupsList.value = sortArrayOfObjects(data, 'slug').filter(r => r.id !== props.rollup.id)
}
-const fetchData = async (rollup, metric) => {
+const fetchData = async (rollup, metric, from, timeframe) => {
const data = await fetchRollupSeries({
id: rollup.id,
name: metric,
- timeframe: selectedPeriod.value.timeframe,
- from: parseInt(
+ timeframe: timeframe ? timeframe : selectedPeriod.value.timeframe,
+ from: from ? from : parseInt(
DateTime.now().minus({
days: selectedPeriod.value.timeframe === "day" ? selectedPeriod.value.value : 0,
hours: selectedPeriod.value.timeframe === "hour" ? selectedPeriod.value.value : 0,
@@ -248,7 +521,8 @@ const getSizeSeries = async () => {
days: selectedPeriod.value.timeframe === "day" ? selectedPeriod.value.value - i : 0,
hours: selectedPeriod.value.timeframe === "hour" ? selectedPeriod.value.value - i : 0,
})
- } sizeSeries.value.push({
+ }
+ sizeSeries.value.push({
date: dt.toJSDate(),
value: parseInt(sizeSeriesMap[dt.toFormat(["day", "month"].includes(selectedPeriod.value.timeframe) ? "y-LL-dd" : "y-LL-dd-HH")]) || 0,
})
@@ -313,6 +587,48 @@ const getFeeSeries = async () => {
}
}
+const getTVLSeries = async () => {
+ tvlSeries.value = []
+
+ let from = ""
+ let tf = selectedPeriod.value.timeframe
+ let periodValue = selectedPeriod.value.value
+ if (["hour", "week"].includes(selectedPeriod.value.timeframe)) {
+ from = parseInt(DateTime.now().minus({ days: 30 }).ts / 1_000)
+ tf = "day"
+ periodValue = 30
+ }
+
+ const tvlSeriesRawData = await fetchRollupTVL({
+ slug: props.rollup.slug,
+ period: tf,
+ from,
+ })
+
+ const tvlSeriesMap = {}
+ tvlSeriesRawData.forEach((item) => {
+ tvlSeriesMap[DateTime.fromISO(item.time).toFormat(["day", "month"].includes(tf) ? "y-LL-dd" : "y-LL-dd-HH")] = item.value
+ })
+
+ for (let i = 1; i < periodValue + 1; i++) {
+ let dt
+ if (tf === "month") {
+ dt = DateTime.now().startOf('month').minus({
+ months: tf === "month" ? periodValue - i : 0,
+ })
+ } else {
+ dt = DateTime.now().minus({
+ days: tf === "day" ? periodValue - i : 0,
+ hours: tf === "hour" ? periodValue - i : 0,
+ })
+ }
+ tvlSeries.value.push({
+ date: dt.toJSDate(),
+ value: parseFloat(tvlSeriesMap[dt.toFormat(["day", "month"].includes(tf) ? "y-LL-dd" : "y-LL-dd-HH")]) || 0,
+ })
+ }
+}
+
const prepareComparisonData = async () => {
isLoading.value = true
@@ -362,39 +678,79 @@ const filteredRollupsList = computed(() => {
return rollupsList.value.filter((r) => r.name.toLowerCase().includes(searchTerm.value.trim().toLowerCase()))
})
-const buildRollupCharts = async () => {
+const buildRollupCharts = async (loadData = true) => {
isLoading.value = true
- await getRollupsList()
- if (!selectedRollup.value) {
- selectedRollup.value = rollupsList.value[0]
- }
+ if (loadData) {
+ await getRollupsList()
+ if (!selectedRollup.value) {
+ selectedRollup.value = rollupsList.value[0]
+ }
- barWidth.value = comparisonChartEl.value.wrapper.getBoundingClientRect().width
+ comparisonBarWidth.value = comparisonChartEl.value.wrapper.getBoundingClientRect().width
- await getSizeSeries()
- buildChart(
- sizeSeriesChartEl.value.wrapper,
- sizeSeries.value,
- () => (showSeriesTooltip.value = true),
- () => (showSeriesTooltip.value = false),
- )
-
- await getPfbSeries()
- buildChart(
- pfbSeriesChartEl.value.wrapper,
- pfbSeries.value,
- () => (showPfbTooltip.value = true),
- () => (showPfbTooltip.value = false),
- )
+ await getSizeSeries()
+ await getPfbSeries()
+ await getFeeSeries()
+ await getTVLSeries()
+ }
- await getFeeSeries()
- buildChart(
- feeSeriesChartEl.value.wrapper,
- feeSeries.value,
- () => (showFeeTooltip.value = true),
- () => (showFeeTooltip.value = false),
- )
+ if (chartView.value === "line") {
+ buildLineChart(
+ sizeSeriesChartEl.value.wrapper,
+ loadLastValue.value ? sizeSeries.value : sizeSeries.value.slice(0, sizeSeries.value.length - 1),
+ () => (showSeriesTooltip.value = true),
+ () => (showSeriesTooltip.value = false),
+ )
+ buildLineChart(
+ pfbSeriesChartEl.value.wrapper,
+ loadLastValue.value ? pfbSeries.value : pfbSeries.value.slice(0, pfbSeries.value.length - 1),
+ () => (showPfbTooltip.value = true),
+ () => (showPfbTooltip.value = false),
+ )
+ buildLineChart(
+ feeSeriesChartEl.value.wrapper,
+ loadLastValue.value ? feeSeries.value : feeSeries.value.slice(0, feeSeries.value.length - 1),
+ () => (showFeeTooltip.value = true),
+ () => (showFeeTooltip.value = false),
+ )
+ buildLineChart(
+ tvlSeriesChartEl.value.wrapper,
+ loadLastValue.value ? tvlSeries.value : tvlSeries.value.slice(0, tvlSeries.value.length - 1),
+ () => (showTVLTooltip.value = true),
+ () => (showTVLTooltip.value = false),
+ "tvl",
+ )
+ } else {
+ buildBarChart(
+ sizeSeriesChartEl.value.wrapper,
+ loadLastValue.value ? sizeSeries.value : sizeSeries.value.slice(0, sizeSeries.value.length - 1),
+ () => (showSeriesTooltip.value = true),
+ () => (showSeriesTooltip.value = false),
+ "size",
+ )
+ buildBarChart(
+ pfbSeriesChartEl.value.wrapper,
+ loadLastValue.value ? pfbSeries.value : pfbSeries.value.slice(0, pfbSeries.value.length - 1),
+ () => (showPfbTooltip.value = true),
+ () => (showPfbTooltip.value = false),
+ "pfb",
+ )
+ buildBarChart(
+ feeSeriesChartEl.value.wrapper,
+ loadLastValue.value ? feeSeries.value : feeSeries.value.slice(0, feeSeries.value.length - 1),
+ () => (showFeeTooltip.value = true),
+ () => (showFeeTooltip.value = false),
+ "fee",
+ )
+ buildBarChart(
+ tvlSeriesChartEl.value.wrapper,
+ loadLastValue.value ? tvlSeries.value : tvlSeries.value.slice(0, tvlSeries.value.length - 1),
+ () => (showTVLTooltip.value = true),
+ () => (showTVLTooltip.value = false),
+ "tvl",
+ )
+ }
await prepareComparisonData()
@@ -410,6 +766,16 @@ watch(
},
)
+watch(
+ () => [chartView.value, loadLastValue.value],
+ () => {
+ updateUserSettings()
+ if (!isLoading.value) {
+ buildRollupCharts(false)
+ }
+ }
+)
+
watch(
() => selectedRollup.value,
() => {
@@ -424,6 +790,13 @@ const debouncedRedraw = useDebounceFn((e) => {
buildRollupCharts()
}, 500)
+onBeforeMount(() => {
+ isLoading.value = true
+ const settings = JSON.parse(localStorage.getItem("settings"))
+ chartView.value = settings?.chart?.view || "bar"
+ loadLastValue.value = settings?.chart?.view ? settings.chart.loadLastValue : true
+})
+
onMounted(async () => {
window.addEventListener("resize", debouncedRedraw)
@@ -443,21 +816,64 @@ onBeforeUnmount(() => {
Analytics
-
-
-
-
-
-
-
- {{ period.title }}
+
+
+
+
+
+
+
+
+ {{ period.title }}
+
+
+
+
+
+
+
+
+
+
+
+ Chart view
+
+
+
+
+
+
+
+
+
+ Show last value
+
+
-
-
-
+
+
+
@@ -500,44 +916,24 @@ onBeforeUnmount(() => {
-
+
- {{
- DateTime.now()
- .minus({ months: selectedPeriod.value - 1 })
- .toFormat("LLL y")
- }}
+ {{ getXAxisLabels(true) }}
- {{ DateTime.now().toFormat("LLL") }}
-
-
- {{
- DateTime.now()
- .minus({ days: selectedPeriod.value - 1 })
- .toFormat("LLL dd")
- }}
+ {{ getXAxisLabels(false) }}
-
- Today
-
-
-
- {{ DateTime.now().minus({ hours: selectedPeriod.value }).set({ minutes: 0 }).toFormat("hh:mm a") }}
-
-
- Now
-
-
+
{
-
+
- {{
- DateTime.now()
- .minus({ months: selectedPeriod.value - 1 })
- .toFormat("LLL y")
- }}
+ {{ getXAxisLabels(true) }}
- {{ DateTime.now().toFormat("LLL") }}
-
-
- {{
- DateTime.now()
- .minus({ days: selectedPeriod.value - 1 })
- .toFormat("LLL dd")
- }}
+ {{ getXAxisLabels(false) }}
-
- Today
-
-
-
- {{ DateTime.now().minus({ hours: selectedPeriod.value }).set({ minutes: 0 }).toFormat("hh:mm a") }}
-
-
- Now
-
-
+
{
-
+
Fee Spent
@@ -712,44 +1088,24 @@ onBeforeUnmount(() => {
-
+
- {{
- DateTime.now()
- .minus({ months: selectedPeriod.value - 1 })
- .toFormat("LLL y")
- }}
+ {{ getXAxisLabels(true) }}
- {{ DateTime.now().toFormat("LLL") }}
-
-
- {{
- DateTime.now()
- .minus({ days: selectedPeriod.value - 1 })
- .toFormat("LLL dd")
- }}
+ {{ getXAxisLabels(false) }}
-
- Today
-
-
-
- {{ DateTime.now().minus({ hours: selectedPeriod.value }).set({ minutes: 0 }).toFormat("hh:mm a") }}
-
-
- Now
-
-
+
{
-
+
+
+ TVL
+
+
+
+
+
+
+
+ Grouping by day or month is only available for this chart.
+
+
+
+
+
+
+
+
+
+ {{ Math.max(...tvlSeries.map((d) => d.value)) < 1_000_000
+ ? abbreviate(Math.max(...tvlSeries.map((d) => d.value)), 0)
+ : abbreviate(Math.max(...tvlSeries.map((d) => d.value))) }} $
+
+
+
+
+ {{ Math.round(Math.max(...tvlSeries.map((d) => d.value)) / 2) < 1_000_000
+ ? abbreviate(Math.round(Math.max(...tvlSeries.map((d) => d.value)) / 2), 0)
+ : abbreviate(Math.round(Math.max(...tvlSeries.map((d) => d.value)) / 2)) }} $
+
+
+
+ 0
+
+
+
+
+
+
+ {{ getXAxisLabels(true, true) }}
+
+
+
+ {{ getXAxisLabels(false, true) }}
+
+
+
+
+
+
+
+
+
+
+ {{ badgeText }}
+
+
+
+
+
+ {{ abbreviate(tooltipText) }} $
+
+
+
+
+
+
+
+
+
+
+
+
Rollups Comparison
@@ -847,7 +1306,7 @@ onBeforeUnmount(() => {
Size
-
+
Blobs
-
+
Fee
-
+
+
+
+
+
+
+ {{ `https://defillama.com/chain/${rollup.defi_lama}` }}
+
+
+
@@ -463,7 +473,7 @@ const handleCSVDownload = async (value) => {
- {{ DateTime.fromISO(rollup.first_message_time).setLocale("en").toFormat("LLL d, t") }}
+ {{ DateTime.fromISO(rollup.first_message_time).setLocale("en").toFormat("LLL d y, t") }}
@@ -476,7 +486,7 @@ const handleCSVDownload = async (value) => {
- {{ DateTime.fromISO(rollup.last_message_time).setLocale("en").toFormat("LLL d, t") }}
+ {{ DateTime.fromISO(rollup.last_message_time).setLocale("en").toFormat("LLL d y, t") }}
diff --git a/components/modules/rollup/tables/BlobsTable.vue b/components/modules/rollup/tables/BlobsTable.vue
index f4602399..63024058 100644
--- a/components/modules/rollup/tables/BlobsTable.vue
+++ b/components/modules/rollup/tables/BlobsTable.vue
@@ -53,15 +53,15 @@ const handleViewBlob = (blob) => {
|
-
+
-
+
-
+
- {{ blob.signer }}
+ {{ blob.signer.hash }}
diff --git a/components/modules/stats/BarChart.vue b/components/modules/stats/BarChart.vue
index 3a381a4f..289b41e2 100644
--- a/components/modules/stats/BarChart.vue
+++ b/components/modules/stats/BarChart.vue
@@ -38,9 +38,9 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
const marginTop = 12
const marginRight = 12
const marginBottom = 24
- const marginLeft = 36
- const marginAxisX = 20
- const barWidth = Math.round(Math.max((width - marginLeft - marginRight) / (cData.data.length) - (pData.data.length ? 2 : 5)), 4)
+ const marginLeft = 48
+ const marginAxisX = 24
+ const barWidth = Math.max(Math.round((width - marginLeft - marginRight) / (cData.data.length) - (pData.data.length ? 2 : 5)), 4)
const MIN_VALUE = d3.min([...cData.data.map(s => s.value), ...pData.data?.map(s => s.value)])
const MAX_VALUE = d3.max([...cData.data.map(s => s.value), ...pData.data?.map(s => s.value)])
@@ -53,7 +53,12 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
const x1 = d3.scaleBand(
['prev', 'current'],
- [0, barWidth],
+ [0, barWidth / 1.1],
+ )
+
+ const scaleX = d3.scaleUtc(
+ d3.extent(cData.data, (d) => new Date(d.date)),
+ [marginLeft - barWidth / 2, width - marginRight - barWidth / 2],
)
let data = cData.data.map((d, i) => ({
@@ -96,6 +101,8 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
return `${tia(value, 2)} TIA`
case 'seconds':
return `${truncateDecimalPart(value / 1_000, 3)}s`
+ case 'usd':
+ return `${abbreviate(value)} $`
default:
return comma(value)
}
@@ -127,11 +134,11 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
svg.append("g")
.attr("transform", `translate( ${barWidth / 2 - 3}, ${height - marginAxisX} )`)
.attr("color", "var(--op-20)")
- .call(d3.axisBottom(x0).ticks(6).tickFormat(d3.timeFormat(props.series.timeframe === 'hour' ? "%H:%M" : "%b %d")))
+ .call(d3.axisBottom(scaleX).ticks(Math.min(cData.data.length, 6)).tickFormat(d3.timeFormat(props.series.timeframe === 'hour' ? "%H:%M" : "%b %d")))
.selectAll(".tick line")
.filter(function(d) { return d === 0; })
.remove();
-
+
svg.append("g")
.attr("transform", `translate(0,0)`)
.attr("color", "var(--op-20)")
@@ -254,12 +261,16 @@ const drawChart = () => {
watch(
() => [currentData.value, prevData.value],
() => {
- drawChart()
+ if (chartEl?.value?.wrapper) {
+ drawChart()
+ }
},
)
onMounted(async () => {
- drawChart()
+ if (chartEl?.value?.wrapper) {
+ drawChart()
+ }
})
diff --git a/components/modules/stats/ChartCardPreview.vue b/components/modules/stats/ChartCardPreview.vue
index 2338a65e..2e83471d 100644
--- a/components/modules/stats/ChartCardPreview.vue
+++ b/components/modules/stats/ChartCardPreview.vue
@@ -10,7 +10,7 @@ import DiffChip from "@/components/modules/stats/DiffChip.vue"
import { abbreviate, comma, formatBytes, tia } from "@/services/utils"
/** API */
-import { fetchSeries, fetchSeriesCumulative } from "@/services/api/stats"
+import { fetchSeries, fetchSeriesCumulative, fetchTVS } from "@/services/api/stats"
const props = defineProps({
series: {
@@ -39,7 +39,19 @@ const chartElPrev = ref()
const getSeries = async () => {
let data = []
-
+ let from = parseInt(
+ DateTime.now().minus({
+ days: props.period.timeframe === "day" ? props.period.value * 2 + 1 : 0,
+ hours: props.period.timeframe === "hour" ? props.period.value * 2 + 1 : 0,
+ }).ts / 1_000
+ )
+ let to = parseInt(
+ DateTime.now().minus({
+ days: props.period.timeframe === "day" ? 1 : 0,
+ hours: props.period.timeframe === "hour" ? 1 : 0,
+ }).ts / 1_000
+ )
+
if (props.series.aggregate === 'cumulative') {
data = await fetchSeriesCumulative({
name: props.series.name,
@@ -49,24 +61,18 @@ const getSeries = async () => {
days: 48,
}).ts / 1_000)
})
- // data = (await fetchSeriesCumulative({
- // name: props.series.name,
- // period: props.period.timeframe,
- // from: parseInt(
- // DateTime.now().minus({
- // days: props.period.timeframe === "day" ? props.period.value * 2 : 0,
- // hours: props.period.timeframe === "hour" ? props.period.value * 2 : 0,
- // }).ts / 1_000)
- // })).reverse()
+ } else if (props.series.name === "tvs") {
+ data = (await fetchTVS({
+ period: props.period.timeframe,
+ from: from,
+ to: to,
+ })).map(v => { return { time: v.time, value: v.close } }).reverse()
} else {
data = (await fetchSeries({
table: props.series.name,
period: props.period.timeframe,
- from: parseInt(
- DateTime.now().minus({
- days: props.period.timeframe === "day" ? props.period.value * 2 : 0,
- hours: props.period.timeframe === "hour" ? props.period.value * 2 : 0,
- }).ts / 1_000)
+ from: from,
+ to: to,
})).reverse()
}
@@ -90,7 +96,10 @@ const getSeries = async () => {
})
}
- if (props.series.aggregate !== 'cumulative') {
+ if (props.series.name === 'tvs') {
+ currentTotal.value = currentData.value[currentData.value.length - 1].value // Math.max(...currentData.value.map(d => d.value))
+ prevTotal.value = prevData.value[prevData.value.length - 1].value // Math.max(...prevTotal.value.map(d => d.value))
+ } else if (props.series.aggregate !== 'cumulative') {
currentTotal.value = currentData.value.reduce((sum, el) => {
return sum + +el.value;
}, 0);
@@ -238,6 +247,10 @@ watch(
{{ series.name === 'gas_price' ? `${currentTotal.toFixed(4)} UTIA` : `${tia(currentTotal, 2)} TIA` }}
{{ series.name === 'gas_price' ? `${prevTotal.toFixed(4)} UTIA` : `${tia(prevTotal, 2)} TIA` }}
+
+ {{ `${abbreviate(currentTotal)} $` }}
+ {{ `${abbreviate(prevTotal)} $` }}
+
{{ series.units === 'bytes' ? formatBytes(currentTotal) : comma(currentTotal) }}
{{ `${series.units === 'bytes' ? formatBytes(prevTotal) : abbreviate(prevTotal)} previous ${period.title.replace('Last ', '')}` }}
@@ -258,7 +271,11 @@ watch(
- Today
+ {{ DateTime.now().minus({
+ days: period.timeframe === "day" ? 1 : 0,
+ hours: period.timeframe === "hour" ? 1 : 0,
+ }).toFormat("LLL dd")
+ }}
diff --git a/components/modules/stats/CircularChartCard.vue b/components/modules/stats/CircularChartCard.vue
deleted file mode 100644
index db276187..00000000
--- a/components/modules/stats/CircularChartCard.vue
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/components/modules/stats/LineChart.vue b/components/modules/stats/LineChart.vue
index 78242717..68d43e68 100644
--- a/components/modules/stats/LineChart.vue
+++ b/components/modules/stats/LineChart.vue
@@ -3,15 +3,9 @@
import * as d3 from "d3"
import { DateTime } from "luxon"
-/** Stats Components */
-import DiffChip from "@/components/modules/stats/DiffChip.vue"
-
/** Services */
import { abbreviate, comma, formatBytes, tia, truncateDecimalPart } from "@/services/utils"
-/** API */
-import { fetchSeries, fetchSeriesCumulative } from "@/services/api/stats"
-
const props = defineProps({
series: {
type: Object,
@@ -83,6 +77,8 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
return `${tia(value, 2)} TIA`
case 'seconds':
return `${truncateDecimalPart(value / 1_000, 3)}s`
+ case 'usd':
+ return `${abbreviate(value)} $`
default:
return comma(value)
}
@@ -252,7 +248,6 @@ const buildChart = (chart, cData, pData, onEnter, onLeave) => {
const drawChart = () => {
currentData.value.color = "var(--mint)"
prevData.value.color = "var(--txt-tertiary)"
-
buildChart(
chartEl.value.wrapper,
currentData.value,
@@ -265,12 +260,16 @@ const drawChart = () => {
watch(
() => [currentData.value, prevData.value],
() => {
- drawChart()
+ if (chartEl?.value?.wrapper) {
+ drawChart()
+ }
},
)
-onMounted(async () => {
- drawChart()
+onMounted(() => {
+ if (chartEl?.value?.wrapper) {
+ drawChart()
+ }
})
diff --git a/components/modules/stats/ParallelCoordinatesChart.vue b/components/modules/stats/ParallelCoordinatesChart.vue
index 6a11e15a..a0ebe42a 100644
--- a/components/modules/stats/ParallelCoordinatesChart.vue
+++ b/components/modules/stats/ParallelCoordinatesChart.vue
@@ -234,21 +234,23 @@ const buildChart = (chart, data) => {
.style("opacity", 0.5)
.style("filter", "brightness(0.6)")
.style("transition", "all 0.5s ease")
- // .attr("stroke-linecap", "round")
.attr("stroke-linejoin", "round")
.attr("d", path )
+ .each(function () {
+ const length = this.getTotalLength();
+ if (!isNaN(length) && length > 0) {
+ d3.select(this)
+ .attr("stroke-dasharray", length)
+ .attr("stroke-dashoffset", length)
+ .transition()
+ .duration(1000)
+ .ease(d3.easeCubic)
+ .attr("stroke-dashoffset", 0);
+ }
+ })
.on('mouseover', (event, d) => highlight(d.slug))
.on('mouseleave', (event, d) => unhighlight(d.slug))
.on('click', (event, d) => selectRollup(d.slug))
- .style("stroke-dasharray", function() { return this.getTotalLength(); })
- // .style("stroke-dashoffset", function() {
- // return Math.random() > 0.5 ? this.getTotalLength() : -this.getTotalLength();
- // })
- .style("stroke-dashoffset", function() { return this.getTotalLength(); })
- .transition()
- .duration(1000)
- .ease(d3.easeCubic)
- .style("stroke-dashoffset", 0)
svg.selectAll("first-last-axis")
.data(edgeAxis).enter()
diff --git a/components/modules/stats/SquareSizeCard.vue b/components/modules/stats/SquareSizeCard.vue
index 8930d48d..a50b3040 100644
--- a/components/modules/stats/SquareSizeCard.vue
+++ b/components/modules/stats/SquareSizeCard.vue
@@ -144,7 +144,7 @@ onMounted(async () => {
/>
-
+
/** Stats Components */
+import ChartCardPreview from "@/components/modules/stats/ChartCardPreview.vue"
import PieChartCard from "@/components/modules/stats/PieChartCard.vue"
import RollupsBubbleChart from "@/components/modules/stats/RollupsBubbleChart.vue"
import RollupsActivity from "~/components/modules/stats/RollupsActivity.vue"
+/** Stats Constants */
+import { STATS_PERIODS } from "@/services/constants/stats.js"
+
/** UI */
import Button from "@/components/ui/Button.vue"
import Checkbox from "@/components/ui/Checkbox.vue"
@@ -253,7 +257,7 @@ watch(
+
+
+
+ Economics
+
+
+
+
+
+
diff --git a/components/modules/tx/TxOverview.vue b/components/modules/tx/TxOverview.vue
index 48956da5..0c2acb2a 100644
--- a/components/modules/tx/TxOverview.vue
+++ b/components/modules/tx/TxOverview.vue
@@ -206,9 +206,9 @@ const handleViewRawTransaction = () => {
Signer
-
+
-
+
diff --git a/components/modules/validator/ValidatorOverview.vue b/components/modules/validator/ValidatorOverview.vue
index 5de93aaa..c4001db3 100644
--- a/components/modules/validator/ValidatorOverview.vue
+++ b/components/modules/validator/ValidatorOverview.vue
@@ -277,9 +277,9 @@ const handleDelegate = () => {
- {{ splitAddress(validator.address) }}
+ {{ splitAddress(validator.address.hash) }}
-
+
@@ -351,8 +351,8 @@ const handleDelegate = () => {
Delegator Address
-
-
+
+
diff --git a/components/modules/validator/tables/DelegatorsTable.vue b/components/modules/validator/tables/DelegatorsTable.vue
index 78c15eef..afa182a3 100644
--- a/components/modules/validator/tables/DelegatorsTable.vue
+++ b/components/modules/validator/tables/DelegatorsTable.vue
@@ -32,13 +32,13 @@ const props = defineProps({
|
|
-
+
- {{ $getDisplayName('addresses', d.delegator) }}
+ {{ $getDisplayName('addresses', d.delegator.hash) }}
-
+
@@ -51,12 +51,12 @@ const props = defineProps({
|
-
+
|
-
+
{{ shareOfTotalString(d.amount, validator.stake) }}
diff --git a/components/shared/tables/Events.vue b/components/shared/tables/Events.vue
index d54c1124..08e868fc 100644
--- a/components/shared/tables/Events.vue
+++ b/components/shared/tables/Events.vue
@@ -677,14 +677,14 @@ watch(
-
+
- {{ splitAddress(event.data.granter.replace(/"/g,'')) }}
+ {{ splitAddress(event.data.granter.hash.replace(/"/g,'')) }}
- {{ event.data.granter.replace(/"/g,'') }}
+ {{ event.data.granter.hash.replace(/"/g,'') }}
@@ -697,28 +697,28 @@ watch(
for
-
+
- {{ splitAddress(event.data.grantee.replace(/"/g,'')) }}
+ {{ splitAddress(event.data.grantee.hash.replace(/"/g,'')) }}
- {{ event.data.grantee.replace(/"/g,'') }}
+ {{ event.data.grantee.hash.replace(/"/g,'') }}
-
+
{{ splitAddress(event.data.granter.replace(/"/g,'')) }}
- {{ event.data.granter.replace(/"/g,'') }}
+ {{ event.data.granter.hash.replace(/"/g,'') }}
@@ -731,42 +731,42 @@ watch(
from
-
+
- {{ splitAddress(event.data.grantee.replace(/"/g,'')) }}
+ {{ splitAddress(event.data.grantee.hash.replace(/"/g,'')) }}
- {{ event.data.grantee.replace(/"/g,'') }}
+ {{ event.data.grantee.hash.replace(/"/g,'') }}
-
+
- {{ splitAddress(event.data.granter) }}
+ {{ splitAddress(event.data.granter.hash) }}
- {{ event.data.granter }}
+ {{ event.data.granter.hash }}
grants fee allowances to
-
+
- {{ splitAddress(event.data.grantee) }}
+ {{ splitAddress(event.data.grantee.hash) }}
- {{ event.data.grantee }}
+ {{ event.data.grantee.hash }}
diff --git a/components/widgets/BlobsWidget.vue b/components/widgets/BlobsWidget.vue
index 351f379e..1371d43e 100644
--- a/components/widgets/BlobsWidget.vue
+++ b/components/widgets/BlobsWidget.vue
@@ -112,7 +112,7 @@ const selectDay = (d) => {
@click="selectDay(day)"
:class="[$style.day, day?.value > 0 && $style.shadow]"
:style="{
- background: parseInt(day?.value) > 0 ? `rgb(10, 219, 111)` : 'var(--op-10)',
+ background: parseInt(day?.value) > 0 ? `var(--brand)` : 'var(--op-10)',
opacity: calculateOpacity(day?.value),
}"
/>
diff --git a/components/widgets/BlockWidget.vue b/components/widgets/BlockWidget.vue
index 5e467099..e0d8d424 100644
--- a/components/widgets/BlockWidget.vue
+++ b/components/widgets/BlockWidget.vue
@@ -110,7 +110,7 @@ onBeforeUnmount(() => {
Block
- {{ comma(lastBlock.height) }}
+ {{ comma(lastBlock.height) }}
@@ -253,7 +253,9 @@ onBeforeUnmount(() => {
width: 100%;
- background: var(--block-progress-fill-background);
+ /* background: var(--dark-mint); */
+ background: var(--neutral-mint);
+ /* background: var(--block-progress-fill-background); */
z-index: -1;
diff --git a/components/widgets/GasWidget.vue b/components/widgets/GasWidget.vue
index bf84b309..e92581ed 100644
--- a/components/widgets/GasWidget.vue
+++ b/components/widgets/GasWidget.vue
@@ -119,7 +119,8 @@ onMounted(async () => {
padding: 0 12px;
&.fast {
- background: linear-gradient(rgba(10, 219, 111, 25%), rgba(10, 219, 111, 10%));
+ /* background: linear-gradient(rgba(10, 219, 111, 25%), rgba(10, 219, 111, 10%)); */
+ background: linear-gradient(var(--dark-mint), rgba(10, 219, 111, 10%));
box-shadow: inset 0 0 0 1px rgba(10, 219, 111, 50%);
}
diff --git a/components/widgets/StakingWidget.vue b/components/widgets/StakingWidget.vue
index e0de18c5..76ce59e3 100644
--- a/components/widgets/StakingWidget.vue
+++ b/components/widgets/StakingWidget.vue
@@ -35,7 +35,7 @@ const validatorsGraph = ref([
title: "active",
count: 0,
width: 0,
- color: "var(--validator-active)",
+ color: "var(--brand)",
},
{
title: "inactive",
@@ -253,7 +253,7 @@ onMounted(() => {
border-radius: 2px;
- background: linear-gradient(90deg, var(--staking) var(--percentStaking), var(--supply) var(--percentStaking));
+ background: linear-gradient(90deg, var(--brand) var(--percentStaking), var(--supply) var(--percentStaking));
}
.validator_bar {
diff --git a/components/widgets/TransactionsWidget.vue b/components/widgets/TransactionsWidget.vue
index 3ceba6dd..45c13d57 100644
--- a/components/widgets/TransactionsWidget.vue
+++ b/components/widgets/TransactionsWidget.vue
@@ -223,7 +223,7 @@ const getSectorName = (item) => {
.hour.current {
.bar {
- background: var(--blue);
+ background: var(--supply);
animation: blink 1.5s ease infinite;
}
}
@@ -249,7 +249,7 @@ const getSectorName = (item) => {
background: var(--txt-tertiary);
&.green {
- background: var(--green);
+ background: var(--brand);
}
}
diff --git a/package.json b/package.json
index dc279b12..64853ccb 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"@keplr-wallet/cosmos": "^0.12.70",
"@openzeppelin/merkle-tree": "^1.0.6",
"@pinia/nuxt": "0.4.11",
+ "@sentry/vue": "^8.50.0",
"@vueuse/core": "^10.9.0",
"buffer": "^6.0.3",
"codemirror": "^6.0.1",
diff --git a/pages/addresses.vue b/pages/addresses.vue
index 165a2d0d..1c27779e 100644
--- a/pages/addresses.vue
+++ b/pages/addresses.vue
@@ -243,7 +243,7 @@ const handleLast = async () => {
-
+
diff --git a/pages/blob.vue b/pages/blob.vue
index 35f39738..5d1d0b9f 100644
--- a/pages/blob.vue
+++ b/pages/blob.vue
@@ -3,7 +3,7 @@
import { DateTime } from "luxon"
/** API */
-import { fetchBlobBlockscoutData, fetchBlobMetadata, fetchBlobByMetadata } from "@/services/api/namespace"
+import { fetchBlobBlockscoutData, fetchBlobByMetadata, fetchBlobMetadata, fetchBlobProof } from "@/services/api/namespace"
/** Components */
import HexViewer from "@/components/modules/blob/HexViewer.vue"
@@ -19,7 +19,6 @@ import { space, formatBytes, comma, strToHex } from "@/services/utils"
import { useCacheStore } from "@/store/cache"
import { useModalsStore } from "@/store/modals"
import { useNotificationsStore } from "@/store/notifications"
-import { blockscoutURL } from "~/services/config"
const cacheStore = useCacheStore()
const modalsStore = useModalsStore()
const notificationsStore = useNotificationsStore()
@@ -101,7 +100,7 @@ cacheStore.current.blob = {
}
onMounted(() => {
- if (!supportedContentTypeForPreview.includes(blob.content_type)) cards.value.preview = false
+ if (!supportedContentTypeForPreview.includes(blob.value?.content_type)) cards.value.preview = false
innerWidth.value = window.innerWidth
if (innerWidth.value <= 1020) {
@@ -178,17 +177,40 @@ const handleDownload = () => {
.map((e) => parseInt(e, 16)),
)
+ let extension = "bin"
+ if (supportedContentTypeForPreview.includes(blob.value?.content_type)) {
+ const ct = blob.value.content_type.split(";")[0].split("/")[1]
+ extension = ct === "plain" ? "txt" : ct
+ }
+
const a = window.document.createElement("a")
a.href = window.URL.createObjectURL(new Blob([byteArray], { type: "application/octet-stream" }))
a.download = `${metadata.value.namespace.namespace_id}_${blob.value.commitment.slice(
blob.value.commitment.length - 8,
blob.value.commitment.length,
- )}.bin`
+ )}.${extension}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
+const handleViewProof = async () => {
+ const { data } = await fetchBlobProof({
+ hash: hash.replaceAll(" ", "+"),
+ height: parseInt(height),
+ commitment: commitment.replaceAll(" ", "+"),
+ })
+
+ if (!data.value) {
+ cacheStore.current.proof = "Failed to load proof.."
+ } else {
+ cacheStore.current.proof = data.value
+ }
+
+ cacheStore.current._target = "proof"
+ modalsStore.open("rawData")
+}
+
const handleCopy = (text) => {
window.navigator.clipboard.writeText(text)
@@ -222,6 +244,10 @@ const handleCopy = (text) => {
View batch
+
-
+
Signer
- {{ metadata.signer }}
+ {{ $getDisplayName("addresses", "", metadata.signer) }}
diff --git a/pages/stats/[metric].vue b/pages/stats/[metric].vue
index ad1014f7..8b1c84b3 100644
--- a/pages/stats/[metric].vue
+++ b/pages/stats/[metric].vue
@@ -3,7 +3,7 @@
import { DateTime } from "luxon"
/** Stats Components/Constants */
-import { getSeriesByPage, STATS_PERIODS } from "@/services/constants/stats.js"
+import { getSeriesByPage, STATS_PERIODS, STATS_TIMEFRAMES } from "@/services/constants/stats.js"
import BarChart from "@/components/modules/stats/BarChart.vue"
import LineChart from "@/components/modules/stats/LineChart.vue"
import SquareSizeChart from "@/components/modules/stats/SquareSizeChart.vue"
@@ -14,7 +14,7 @@ import { exportSVGToPNG, exportToCSV } from "@/services/utils/export"
import { capitalizeAndReplaceUnderscore } from "@/services/utils"
/** API */
-import { fetchSeries, fetchSeriesCumulative } from "@/services/api/stats"
+import { fetchSeries, fetchSeriesCumulative, fetchTVS } from "@/services/api/stats"
/** UI */
import Button from "@/components/ui/Button.vue"
@@ -23,13 +23,14 @@ import Popover from "@/components/ui/Popover.vue"
import Toggle from "@/components/ui/Toggle.vue"
/** Store */
-/** Store */
+import { useCacheStore } from "@/store/cache"
import { useModalsStore } from "@/store/modals"
import { useNotificationsStore } from "@/store/notifications"
-import { useCacheStore } from "@/store/cache"
+import { useSettingsStore } from "@/store/settings"
+const cacheStore = useCacheStore()
const modalsStore = useModalsStore()
const notificationsStore = useNotificationsStore()
-const cacheStore = useCacheStore()
+const settingsStore = useSettingsStore()
const route = useRoute()
const router = useRouter()
@@ -40,7 +41,10 @@ if (!series.value.page) {
router.push("/stats")
}
-const metricName = computed(() => capitalizeAndReplaceUnderscore(series.value?.page))
+const metricName = computed(() => {
+ if (series.value.page === "tvs") return series.value.title
+ return capitalizeAndReplaceUnderscore(series.value?.page)
+})
// defineOgImage({
// title: "Rollup",
@@ -96,12 +100,50 @@ useHead({
const periods = ref(STATS_PERIODS)
const selectedPeriod = ref(periods.value[2])
+const selectedTimeframe = ref(STATS_TIMEFRAMES.find(tf => tf.timeframe === (series.value.name === "tvs" ? "day" : selectedPeriod.value.timeframe)))
+const timeframes = computed(() => {
+ let res = []
+
+ for (const tf of STATS_TIMEFRAMES) {
+ const pointCount = Math.floor(DateTime.fromSeconds(filters.to).diff(DateTime.fromSeconds(filters.from), `${tf.timeframe}s`)[`${tf.timeframe}s`]) + 1
+
+ if (pointCount > 1 && pointCount < 100) {
+ res.push(tf)
+ }
+ }
+
+ if (series.value.name === "tvs") {
+ res = res.filter(tf => tf.timeframe === "day" || tf.timeframe === "month")
+ }
+
+ return res
+})
+const timeframesStyles = computed(() => {
+ const len = timeframes.value.length
+ if (!len) return { background: "var(--op-5)" }
+
+ const segment = 100 / len
+ const index = timeframes.value.findIndex(tf => tf.timeframe === selectedTimeframe.value.timeframe)
+ const start = segment * index
+ const end = start + segment
+
+ return { background: `linear-gradient(to right, transparent ${start}%, var(--op-5) ${start}%, var(--op-5) ${end}%, transparent ${end}%)` }
+})
+
const currentData = ref([])
const prevData = ref([])
-const chartView = ref('line')
+const chartView = ref("line")
const loadPrevData = ref(true)
const loadLastValue = ref(true)
+const updateUserSettings = () => {
+ settingsStore.chart = {
+ ...settingsStore.chart,
+ view: chartView.value,
+ loadPrevData: loadPrevData.value,
+ loadLastValue: loadLastValue.value,
+ }
+}
const filters = reactive({})
@@ -109,9 +151,9 @@ const setDefaultFilters = () => {
filters.timeframe = selectedPeriod.value.timeframe
filters.periodValue = selectedPeriod.value.value
filters.from = parseInt(DateTime.now().startOf('day').minus({
- days: selectedPeriod.value.timeframe === "day" ? selectedPeriod.value.value - 1 : 0, // ??
- hours: selectedPeriod.value.timeframe === "hour" ? selectedPeriod.value.value : 0,
- }).ts / 1_000)
+ days: selectedPeriod.value.timeframe === "day" ? selectedPeriod.value.value - 1 : 0,
+ hours: selectedPeriod.value.timeframe === "hour" ? selectedPeriod.value.value : 0,
+ }).ts / 1_000)
filters.to = parseInt(DateTime.now().endOf('day').ts / 1_000)
}
@@ -126,42 +168,108 @@ const handleChangeChartView = () => {
}
const isLoading = ref(false)
-const getData = async () => {
- isLoading.value = true
-
+const fetchData = async (from, to) => {
let data = []
-
- if (series.value.aggregate !== 'cumulative') {
+ if (series.value.name === "tvs") {
+ data = (await fetchTVS({
+ period: selectedTimeframe.value.timeframe,
+ from: from
+ ? from
+ : loadPrevData.value
+ ? parseInt(DateTime.fromSeconds(filters.from).minus({
+ hours: filters.timeframe === "hour" ? filters.periodValue : 0,
+ days: filters.timeframe === "day" ? filters.periodValue : 0,
+ weeks: filters.timeframe === "week" ? filters.periodValue : 0,
+ months: filters.timeframe === "month" ? filters.periodValue : 0,
+ }).ts / 1_000)
+ : filters.from,
+ to: to ? to : filters.to
+ })).map(v => { return { time: v.time, value: v.close } })
+ } else if (series.value.aggregate !== 'cumulative') {
data = (await fetchSeries({
table: series.value.name,
- period: filters.timeframe,
- from: loadPrevData.value ? parseInt(DateTime.fromSeconds(filters.from).minus({
- hours: filters.timeframe === "hour" ? filters.periodValue : 0,
- days: filters.timeframe === "day" ? filters.periodValue : 0,
- weeks: filters.timeframe === "week" ? filters.periodValue : 0,
- }).ts / 1_000) : filters.from,
- to: filters.to
- })).reverse()
+ period: selectedTimeframe.value.timeframe,
+ from: from
+ ? from
+ : loadPrevData.value
+ ? parseInt(DateTime.fromSeconds(filters.from).minus({
+ hours: filters.timeframe === "hour" ? filters.periodValue : 0,
+ days: filters.timeframe === "day" ? filters.periodValue : 0,
+ weeks: filters.timeframe === "week" ? filters.periodValue : 0,
+ }).ts / 1_000)
+ : filters.from,
+ to: to ? to : filters.to
+ }))
} else {
- data = await fetchSeriesCumulative({
+ data = (await fetchSeriesCumulative({
name: series.value.name,
- period: filters.timeframe,
+ period: selectedTimeframe.value.timeframe,
from: loadPrevData.value ? parseInt(DateTime.fromSeconds(filters.from).minus({
hours: filters.timeframe === "hour" ? filters.periodValue : 0,
days: filters.timeframe === "day" ? filters.periodValue : 0,
weeks: filters.timeframe === "week" ? filters.periodValue : 0,
}).ts / 1_000) : filters.from,
to: filters.to
- })
+ })).reverse()
}
+ return data
+}
+const getData = async () => {
+ isLoading.value = true
+
+ let data = await fetchData()
if (data.length) {
if (loadPrevData.value) {
- prevData.value = data.slice(0, filters.periodValue).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) }))
- currentData.value = data.slice(filters.periodValue, data.length).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) }))
+ if (selectedTimeframe.value.timeframe !== filters.timeframe) {
+ if (data.length % 2 > 0) {
+ const from = parseInt(DateTime.fromISO(data[data.length - 1].time)
+ .minus({
+ hours: selectedTimeframe.value.timeframe === "hour" ? 1 : 0,
+ days: selectedTimeframe.value.timeframe === "day" ? 1 : 0,
+ weeks: selectedTimeframe.value.timeframe === "week" ? 1 : 0,
+ months: selectedTimeframe.value.timeframe === "month" ? 1 : 0
+ }).ts / 1_000
+ )
+ const to = parseInt(DateTime.fromISO(data[data.length - 1].time).ts / 1_000)
+ let addData = await fetchData(from, to)
+ if (!addData.length) {
+ addData = [{
+ date: DateTime.fromISO(data[data.length - 1].time)
+ .minus({
+ hours: filters.timeframe === "hour" ? 1 : 0,
+ days: filters.timeframe === "day" ? 1 : 0,
+ weeks: filters.timeframe === "week" ? 1 : 0,
+ })
+ .toJSDate(),
+ value: 0,
+ }]
+ }
+ data.push(addData[0])
+ }
+
+ currentData.value = data.slice(0, data.length / 2).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
+ prevData.value = data.slice(data.length / 2, data.length).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
+ } else {
+ currentData.value = data.slice(0, filters.periodValue).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
+ prevData.value = data.slice(filters.periodValue, data.length).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
+ while (prevData.value.length < currentData.value.length) {
+ prevData.value.unshift({
+ date: DateTime.fromJSDate(prevData.value[0]?.date)
+ .minus({
+ hours: filters.timeframe === "hour" ? 1 : 0,
+ days: filters.timeframe === "day" ? 1 : 0,
+ weeks: filters.timeframe === "week" ? 1 : 0,
+ })
+ .toJSDate(),
+ value: 0
+ })
+ }
+ }
} else {
+ // currentData.value = data.slice(0, filters.periodValue).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
+ currentData.value = data.map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) })).reverse()
prevData.value = []
- currentData.value = data.slice(0, filters.periodValue).map((s) => ({ date: DateTime.fromISO(s.time).toJSDate(), value: parseFloat(s.value) }))
}
}
@@ -185,21 +293,48 @@ const handleClose = () => {
}
const handleUpdateDate = async (event) => {
+ isLoading.value = true
+
if (event.from && event.to) {
- let daysDiff = Math.round(DateTime.fromSeconds(event.to).diff(DateTime.fromSeconds(event.from), 'days').days)
- if (daysDiff < 7) {
- filters.timeframe = 'hour'
- filters.periodValue = Math.round(DateTime.fromSeconds(event.to).diff(DateTime.fromSeconds(event.from), 'hours').hours)
- } else if (daysDiff < 50) {
- filters.timeframe = 'day'
- filters.periodValue = daysDiff
+ let from = event.from
+ let to = event.to
+
+ let daysDiff = Math.round(DateTime.fromSeconds(to).diff(DateTime.fromSeconds(from), 'days').days)
+ if (series.value.name === "tvs") {
+ if (daysDiff < 50) {
+ filters.timeframe = 'day'
+ filters.periodValue = daysDiff
+ } else {
+ filters.timeframe = 'month'
+ filters.periodValue = Math.ceil(daysDiff / 30)
+ }
} else {
- filters.timeframe = 'week'
- filters.periodValue = Math.round(daysDiff / 7)
+ if (daysDiff < 7) {
+ filters.timeframe = 'hour'
+ filters.periodValue = Math.round(DateTime.fromSeconds(to).diff(DateTime.fromSeconds(from), 'hours').hours)
+ } else if (daysDiff < 50) {
+ filters.timeframe = 'day'
+ filters.periodValue = daysDiff
+ } else {
+ filters.timeframe = 'week'
+ filters.periodValue = Math.ceil(daysDiff / 7)
+ }
+ }
+
+ if (filters.timeframe === 'hour') {
+ const hoursDiff = Math.round(DateTime.fromSeconds(Math.min(to, DateTime.now().ts / 1_000)).diff(DateTime.fromSeconds(from), 'hours').hours)
+ if (hoursDiff < filters.periodValue) {
+ from = parseInt(
+ DateTime.fromSeconds(Math.min(to, DateTime.now().ts / 1_000))
+ .minus({ hours: filters.periodValue })
+ .ts / 1_000
+ )
+ }
}
- filters.from = event.from
- filters.to = event.to
+ filters.from = from
+ filters.to = to
+ selectedTimeframe.value = timeframes.value.find(tf => tf.timeframe === filters.timeframe)
await getData()
} else if (event.clear) {
@@ -209,6 +344,10 @@ const handleUpdateDate = async (event) => {
}
}
+const handleTimeframeUpdate = (tf) => {
+ selectedTimeframe.value = tf
+}
+
const handleCSVDownload = async () => {
let data = [...series.value.currentData, ...series.value.prevData]
let csvHeaders = 'timestamp,value\n'
@@ -278,6 +417,29 @@ watch(
}
},
)
+
+watch(
+ () => selectedTimeframe.value,
+ async () => {
+ if (!isLoading.value) {
+ await getData()
+ }
+ }
+)
+
+watch(
+ () => [chartView.value, loadLastValue.value, loadPrevData.value],
+ () => {
+ updateUserSettings()
+ }
+)
+
+onBeforeMount(() => {
+ const settings = JSON.parse(localStorage.getItem("settings"))
+ chartView.value = settings?.chart?.view || "line"
+ loadPrevData.value = settings?.chart?.loadPrevData
+ loadLastValue.value = settings?.chart?.loadLastValue
+})
@@ -349,6 +511,28 @@ watch(
Show last value
+
+
+ Group by
+
+
+
+ {{ tf.shortTitle }}
+
+
+
@@ -401,6 +585,18 @@ watch(
transition: all 1s ease-in-out;
}
+.groupping_selector {
+ padding: 4px 6px 4px 6px;
+ box-shadow: inset 0 0 0 1px var(--op-10);
+ border-radius: 5px;
+ cursor: pointer;
+ transition: all 1s ease-in-out;
+
+ & .item {
+ padding: 2px;
+ }
+}
+
.disabled {
opacity: 0.3;
pointer-events: none;
diff --git a/pages/txs.vue b/pages/txs.vue
index dfb65072..bc95fa64 100644
--- a/pages/txs.vue
+++ b/pages/txs.vue
@@ -111,19 +111,22 @@ const handleClearAllFilters = () => {
const searchTerm = ref("")
/** Parse route query */
-Object.keys(route.query).forEach((key) => {
- if (key === "page") return
-
- if (key === "from" || key === "to") {
- filters[key] = route.query[key]
- } else if (route.query[key].split(",").length) {
- route.query[key].split(",").forEach((item) => {
- filters[key][item] = true
- })
- } else {
- filters[key][route.query[key]] = true
- }
-})
+const parseRouteQuery = () => {
+ Object.keys(route.query).forEach((key) => {
+ if (key === "page") return
+
+ if (key === "from" || key === "to") {
+ filters[key] = route.query[key]
+ } else if (route.query[key].split(",").length) {
+ route.query[key].split(",").forEach((item) => {
+ filters[key][item] = true
+ })
+ } else {
+ filters[key][route.query[key]] = true
+ }
+ })
+}
+parseRouteQuery()
const updateRouteQuery = () => {
router.replace({
@@ -140,6 +143,7 @@ const updateRouteQuery = () => {
.join(","),
...(filters.from ? { from: filters.from } : {}),
...(filters.to ? { to: filters.to } : {}),
+ page: page.value,
},
})
}
@@ -223,10 +227,15 @@ const handleUpdateDateFilter = (event) => {
const resetFilters = (target, refetch) => {
if (target === "from" || target === "to") {
filters[target] = ""
- } else {
+ } else if (target) {
Object.keys(filters[target]).forEach((f) => {
filters[target][f] = false
})
+ } else {
+ resetFilters("from")
+ resetFilters("to")
+ resetFilters("status")
+ resetFilters("message_type")
}
if (refetch) {
@@ -274,8 +283,9 @@ const sort = reactive({
dir: "desc",
})
-const page = ref(route.query.page ? parseInt(route.query.page) : 1)
-const pages = computed(() => Math.ceil(count.value / 20))
+const page = ref(route.query.page ? parseInt(route.query.page) < 1 ? 1 : parseInt(route.query.page) : 1)
+const limit = ref(20)
+const handleNextCondition = ref(false)
const findPFB = ref(false)
@@ -283,7 +293,7 @@ const getTransactions = async () => {
isRefetching.value = true
const { data } = await fetchTransactions({
- limit: 20,
+ limit: limit.value,
offset: (page.value - 1) * 20,
sort: sort.dir,
sort_by: sort.by,
@@ -302,11 +312,12 @@ const getTransactions = async () => {
})
transactions.value = data.value
+ handleNextCondition.value = transactions.value.length < limit.value
isLoaded.value = true
isRefetching.value = false
}
-getTransactions()
+await getTransactions()
onBeforeMount(() => {
if (localStorage.getItem("page:transactions:config:columns")) {
@@ -315,18 +326,33 @@ onBeforeMount(() => {
})
/** Refetch transactions */
+watch(
+ () => route.query,
+ async () => {
+ if (!isRefetching.value) {
+ if (Object.keys(route.query).length) {
+ parseRouteQuery()
+ } else {
+ resetFilters()
+ }
+
+ await getTransactions()
+ }
+ },
+)
+
watch(
() => page.value,
async () => {
- getTransactions()
- router.replace({ query: { page: page.value } })
+ await getTransactions()
+ updateRouteQuery()
},
)
watch(
() => findPFB.value,
- () => {
- getTransactions()
+ async () => {
+ await getTransactions()
},
)
@@ -337,7 +363,7 @@ watch(
}
)
-const handleSort = (by) => {
+const handleSort = async (by) => {
/** temp. only for time */
if (!["time"].includes(by)) return
@@ -358,7 +384,7 @@ const handleSort = (by) => {
page.value = 1
}
- getTransactions()
+ await getTransactions()
}
const handlePrev = () => {
@@ -401,7 +427,7 @@ const handleNext = () => {
Page {{ comma(page) }}
- | |