mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
feat: dont show analytics incomplete current day revenue (#6933)
This commit is contained in:
+7
@@ -27,6 +27,7 @@ import {
|
|||||||
LineController,
|
LineController,
|
||||||
LineElement,
|
LineElement,
|
||||||
PointElement,
|
PointElement,
|
||||||
|
type ScriptableLineSegmentContext,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'chart.js'
|
} from 'chart.js'
|
||||||
|
|
||||||
@@ -446,6 +447,12 @@ function buildDatasets() {
|
|||||||
pointHoverBackgroundColor: colors.borderColor,
|
pointHoverBackgroundColor: colors.borderColor,
|
||||||
pointHoverBorderWidth: 0,
|
pointHoverBorderWidth: 0,
|
||||||
pointHitRadius: 16,
|
pointHitRadius: 16,
|
||||||
|
segment: dataset.lastDataPointUnavailable
|
||||||
|
? {
|
||||||
|
borderColor: (context: ScriptableLineSegmentContext) =>
|
||||||
|
context.p1DataIndex === dataset.data.length - 1 ? 'transparent' : undefined,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
stack: props.stacked ? 'analytics' : undefined,
|
stack: props.stacked ? 'analytics' : undefined,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+10
-2
@@ -59,7 +59,9 @@
|
|||||||
<span class="font-medium text-primary">
|
<span class="font-medium text-primary">
|
||||||
{{ formatMessage(analyticsChartMessages.total) }}
|
{{ formatMessage(analyticsChartMessages.total) }}
|
||||||
</span>
|
</span>
|
||||||
<span class="font-semibold text-contrast">{{ formattedTotal }}</span>
|
<span class="font-semibold" :class="totalHasData ? 'text-contrast' : 'text-primary'">
|
||||||
|
{{ formattedTotal }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="entry in entries"
|
v-for="entry in entries"
|
||||||
@@ -111,7 +113,11 @@
|
|||||||
:class="[
|
:class="[
|
||||||
'shrink-0',
|
'shrink-0',
|
||||||
entry.isPreviousPeriod ? 'font-medium text-secondary' : 'font-semibold',
|
entry.isPreviousPeriod ? 'font-medium text-secondary' : 'font-semibold',
|
||||||
entry.hidden ? 'text-primary line-through opacity-70' : 'text-contrast',
|
entry.hidden
|
||||||
|
? 'text-primary line-through opacity-70'
|
||||||
|
: entry.noData
|
||||||
|
? 'text-primary'
|
||||||
|
: 'text-contrast',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{ entry.formattedValue }}
|
{{ entry.formattedValue }}
|
||||||
@@ -148,6 +154,7 @@ export type AnalyticsChartTooltipEntry = {
|
|||||||
tooltip?: string
|
tooltip?: string
|
||||||
color: string
|
color: string
|
||||||
formattedValue: string
|
formattedValue: string
|
||||||
|
noData: boolean
|
||||||
hidden: boolean
|
hidden: boolean
|
||||||
toggleDisabled: boolean
|
toggleDisabled: boolean
|
||||||
isPreviousPeriod?: boolean
|
isPreviousPeriod?: boolean
|
||||||
@@ -164,6 +171,7 @@ const props = defineProps<{
|
|||||||
chartStart: Date | null
|
chartStart: Date | null
|
||||||
chartEnd: Date | null
|
chartEnd: Date | null
|
||||||
formattedTotal: string
|
formattedTotal: string
|
||||||
|
totalHasData: boolean
|
||||||
entries: AnalyticsChartTooltipEntry[]
|
entries: AnalyticsChartTooltipEntry[]
|
||||||
containerWidth: number
|
containerWidth: number
|
||||||
containerHeight: number
|
containerHeight: number
|
||||||
|
|||||||
+28
-3
@@ -64,6 +64,7 @@
|
|||||||
:chart-start="chartRangeBounds?.start ?? null"
|
:chart-start="chartRangeBounds?.start ?? null"
|
||||||
:chart-end="chartRangeBounds?.end ?? null"
|
:chart-end="chartRangeBounds?.end ?? null"
|
||||||
:formatted-total="hoverFormattedTotal"
|
:formatted-total="hoverFormattedTotal"
|
||||||
|
:total-has-data="hoverHasData"
|
||||||
:entries="hoverEntries"
|
:entries="hoverEntries"
|
||||||
:container-width="containerSize.width"
|
:container-width="containerSize.width"
|
||||||
:container-height="containerSize.height"
|
:container-height="containerSize.height"
|
||||||
@@ -89,6 +90,7 @@ import type {
|
|||||||
AnalyticsGroupByPreset,
|
AnalyticsGroupByPreset,
|
||||||
} from '~/providers/analytics/analytics'
|
} from '~/providers/analytics/analytics'
|
||||||
|
|
||||||
|
import { analyticsChartMessages } from '../../analytics-messages.ts'
|
||||||
import type {
|
import type {
|
||||||
AnalyticsChartLegendEntry,
|
AnalyticsChartLegendEntry,
|
||||||
AnalyticsChartRangeBounds,
|
AnalyticsChartRangeBounds,
|
||||||
@@ -188,7 +190,26 @@ const hoverTotalValue = computed(() => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function hasDatasetDataAtSlice(dataset: ChartDataset | undefined, sliceIndex: number) {
|
||||||
|
if (!dataset) return false
|
||||||
|
return !dataset.lastDataPointUnavailable || sliceIndex !== dataset.data.length - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const hoverHasData = computed(() => {
|
||||||
|
if (hoverState.sliceIndex === null) return false
|
||||||
|
const sliceIndex = hoverState.sliceIndex
|
||||||
|
|
||||||
|
return props.currentLegendEntries.some((legendEntry) => {
|
||||||
|
if (legendEntry.hidden) return false
|
||||||
|
const dataset = props.chartDatasetById.get(legendEntry.id)
|
||||||
|
return hasDatasetDataAtSlice(dataset, sliceIndex)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const hoverFormattedTotal = computed(() => {
|
const hoverFormattedTotal = computed(() => {
|
||||||
|
if (!hoverHasData.value) {
|
||||||
|
return formatMessage(analyticsChartMessages.noData)
|
||||||
|
}
|
||||||
if (props.isRatioMode) {
|
if (props.isRatioMode) {
|
||||||
return hoverTotalValue.value > 0 ? '100%' : '0%'
|
return hoverTotalValue.value > 0 ? '100%' : '0%'
|
||||||
}
|
}
|
||||||
@@ -203,6 +224,7 @@ const hoverEntries = computed(() => {
|
|||||||
return props.legendEntries.map((legendEntry) => {
|
return props.legendEntries.map((legendEntry) => {
|
||||||
const dataset = props.chartDatasetById.get(legendEntry.id)
|
const dataset = props.chartDatasetById.get(legendEntry.id)
|
||||||
const value = dataset?.data[sliceIndex] ?? 0
|
const value = dataset?.data[sliceIndex] ?? 0
|
||||||
|
const hasData = hasDatasetDataAtSlice(dataset, sliceIndex)
|
||||||
const ratioValue = legendEntry.hidden || totalValue === 0 ? 0 : (value / totalValue) * 100
|
const ratioValue = legendEntry.hidden || totalValue === 0 ? 0 : (value / totalValue) * 100
|
||||||
return {
|
return {
|
||||||
projectId: legendEntry.id,
|
projectId: legendEntry.id,
|
||||||
@@ -210,9 +232,12 @@ const hoverEntries = computed(() => {
|
|||||||
projectName: legendEntry.projectName,
|
projectName: legendEntry.projectName,
|
||||||
tooltip: legendEntry.tooltip,
|
tooltip: legendEntry.tooltip,
|
||||||
color: legendEntry.color,
|
color: legendEntry.color,
|
||||||
formattedValue: props.isRatioMode
|
formattedValue: hasData
|
||||||
? `${ratioValue.toFixed(1)}%`
|
? props.isRatioMode
|
||||||
: formatMetricValue(value, props.activeStat, formatNumber, formatMessage),
|
? `${ratioValue.toFixed(1)}%`
|
||||||
|
: formatMetricValue(value, props.activeStat, formatNumber, formatMessage)
|
||||||
|
: formatMessage(analyticsChartMessages.noData),
|
||||||
|
noData: !hasData,
|
||||||
hidden: legendEntry.hidden,
|
hidden: legendEntry.hidden,
|
||||||
toggleDisabled: !legendEntry.hidden && isLegendEntryToggleDisabled(legendEntry),
|
toggleDisabled: !legendEntry.hidden && isLegendEntryToggleDisabled(legendEntry),
|
||||||
isPreviousPeriod: legendEntry.isPreviousPeriod,
|
isPreviousPeriod: legendEntry.isPreviousPeriod,
|
||||||
|
|||||||
+1
@@ -38,6 +38,7 @@ export type ChartDataset = {
|
|||||||
projectName?: string
|
projectName?: string
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
data: number[]
|
data: number[]
|
||||||
|
lastDataPointUnavailable?: boolean
|
||||||
borderColor: string
|
borderColor: string
|
||||||
backgroundColor: string
|
backgroundColor: string
|
||||||
borderDash?: number[]
|
borderDash?: number[]
|
||||||
|
|||||||
+27
-4
@@ -32,6 +32,7 @@ import {
|
|||||||
type ChartDataset,
|
type ChartDataset,
|
||||||
getChartDatasetTotal,
|
getChartDatasetTotal,
|
||||||
getShortHourlyAxisTickLimit,
|
getShortHourlyAxisTickLimit,
|
||||||
|
getSliceBucketRange,
|
||||||
getSliceCount,
|
getSliceCount,
|
||||||
shouldCapitalizeBreakdownLabel,
|
shouldCapitalizeBreakdownLabel,
|
||||||
} from './analytics-chart-utils'
|
} from './analytics-chart-utils'
|
||||||
@@ -161,8 +162,8 @@ export function useAnalyticsChartDatasets(
|
|||||||
)
|
)
|
||||||
: undefined
|
: undefined
|
||||||
})
|
})
|
||||||
const chartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() =>
|
const chartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() => {
|
||||||
buildDatasetsByStat(
|
const datasets = buildDatasetsByStat(
|
||||||
context.displayedTimeSlices.value,
|
context.displayedTimeSlices.value,
|
||||||
selectedProjects.value,
|
selectedProjects.value,
|
||||||
legendPalette.value,
|
legendPalette.value,
|
||||||
@@ -175,8 +176,20 @@ export function useAnalyticsChartDatasets(
|
|||||||
showProjectVersionNames.value ? context.getVersionProjectName : undefined,
|
showProjectVersionNames.value ? context.getVersionProjectName : undefined,
|
||||||
formatMessage,
|
formatMessage,
|
||||||
sliceCount.value,
|
sliceCount.value,
|
||||||
),
|
)
|
||||||
)
|
const nextFetchRequest = context.displayedFetchRequest.value
|
||||||
|
if (
|
||||||
|
nextFetchRequest &&
|
||||||
|
context.displayedSelectedGroupBy.value === 'day' &&
|
||||||
|
isLastBucketCurrentDay(nextFetchRequest.time_range, sliceCount.value)
|
||||||
|
) {
|
||||||
|
datasets.revenue = datasets.revenue.map((dataset) => ({
|
||||||
|
...dataset,
|
||||||
|
lastDataPointUnavailable: true,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return datasets
|
||||||
|
})
|
||||||
const previousChartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() =>
|
const previousChartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() =>
|
||||||
buildDatasetsByStat(
|
buildDatasetsByStat(
|
||||||
context.displayedPreviousTimeSlices.value,
|
context.displayedPreviousTimeSlices.value,
|
||||||
@@ -406,6 +419,16 @@ function buildDatasetsByStat(
|
|||||||
return datasetsByStat
|
return datasetsByStat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLastBucketCurrentDay(timeRange: Labrinth.Analytics.v3.TimeRange, sliceCount: number) {
|
||||||
|
const lastBucket = getSliceBucketRange(timeRange, sliceCount, sliceCount - 1)
|
||||||
|
const todayStart = new Date()
|
||||||
|
todayStart.setHours(0, 0, 0, 0)
|
||||||
|
const tomorrowStart = new Date(todayStart)
|
||||||
|
tomorrowStart.setDate(tomorrowStart.getDate() + 1)
|
||||||
|
|
||||||
|
return lastBucket.start < tomorrowStart && lastBucket.end > todayStart
|
||||||
|
}
|
||||||
|
|
||||||
function sortDatasetsByTotal(datasets: ChartDataset[]) {
|
function sortDatasetsByTotal(datasets: ChartDataset[]) {
|
||||||
return [...datasets]
|
return [...datasets]
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
|
|||||||
@@ -688,6 +688,10 @@ export const analyticsChartMessages = defineMessages({
|
|||||||
id: 'analytics.chart.tooltip.hide-entry',
|
id: 'analytics.chart.tooltip.hide-entry',
|
||||||
defaultMessage: 'Hide {name} in graph',
|
defaultMessage: 'Hide {name} in graph',
|
||||||
},
|
},
|
||||||
|
noData: {
|
||||||
|
id: 'analytics.chart.tooltip.no-data',
|
||||||
|
defaultMessage: 'No data',
|
||||||
|
},
|
||||||
durationDays: {
|
durationDays: {
|
||||||
id: 'analytics.chart.tooltip.duration.days',
|
id: 'analytics.chart.tooltip.duration.days',
|
||||||
defaultMessage: '{count, plural, one {# day} other {# days}}',
|
defaultMessage: '{count, plural, one {# day} other {# days}}',
|
||||||
|
|||||||
@@ -191,6 +191,9 @@
|
|||||||
"analytics.chart.tooltip.hide-entry": {
|
"analytics.chart.tooltip.hide-entry": {
|
||||||
"message": "Hide {name} in graph"
|
"message": "Hide {name} in graph"
|
||||||
},
|
},
|
||||||
|
"analytics.chart.tooltip.no-data": {
|
||||||
|
"message": "No data"
|
||||||
|
},
|
||||||
"analytics.chart.tooltip.pinned": {
|
"analytics.chart.tooltip.pinned": {
|
||||||
"message": "Chart tooltip pinned"
|
"message": "Chart tooltip pinned"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user