You've already forked AstralRinth
8371ff641a
* fix: previous period data was included in the table * fix: revenue displaying stale data when viewing it from different metric and grouped by 6 hour or 1 hour * fix: remove staletime on analytics query so switching tabs does not refersh query * feat: add monetization alert * fix-small: missing space in tooltip * fix: incorrect y-axis formatting for trailing decimal 0s * fix: switching tabs resets table series selection due to other refetches * fix: always show month first in chart tooltip * fix: change all time start date to be project published date * fix: increase length on project name column * fix: unknown download source data points not showing for download source breakdown * fix: double unknown for loader * fix: no data on country labeling incorrectly as "Unknown" instead of "Other" * fix: date picker number inputs showing arrows * fix: stat card showing enormous percentage for prev period by switching it to absolute value difference after 1000% * fix: decimal values for playtime being rounded badly, resulting in 0.04 becoming 0.0 * fix: chips having stroke * refactor: pnpm prepr * fix: spacing in annoucement link * fix: legend scroll shadow on top of event tooltip
111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
import type { Labrinth } from '@modrinth/api-client'
|
|
|
|
import type { AnalyticsBreakdownPreset } from '~/providers/analytics/analytics'
|
|
|
|
import { formatAnalyticsDownloadSourceLabel, type FormatMessage } from './analytics-messages'
|
|
|
|
export const ALL_BREAKDOWN_VALUE = '__all__'
|
|
export const UNKNOWN_BREAKDOWN_VALUE = '__unknown__'
|
|
export const COMBINED_BREAKDOWN_LABEL_SEPARATOR = ' + '
|
|
export const COMBINED_BREAKDOWN_DATASET_ID_PREFIX = 'breakdowns:'
|
|
|
|
export function getAnalyticsBreakdownValue(
|
|
point: Labrinth.Analytics.v3.ProjectAnalytics,
|
|
selectedBreakdown: AnalyticsBreakdownPreset,
|
|
formatMessage: FormatMessage,
|
|
): string {
|
|
switch (selectedBreakdown) {
|
|
case 'none':
|
|
return ALL_BREAKDOWN_VALUE
|
|
case 'project':
|
|
return normalizeBreakdownValue('source_project' in point ? point.source_project : undefined)
|
|
case 'country':
|
|
return normalizeBreakdownValue('country' in point ? point.country?.toUpperCase() : undefined)
|
|
case 'monetization': {
|
|
if ('monetized' in point && typeof point.monetized === 'boolean') {
|
|
return point.monetized ? 'monetized' : 'unmonetized'
|
|
}
|
|
return ALL_BREAKDOWN_VALUE
|
|
}
|
|
case 'user_agent': {
|
|
const downloadSource = normalizeBreakdownValue(
|
|
'user_agent' in point ? point.user_agent : undefined,
|
|
UNKNOWN_BREAKDOWN_VALUE,
|
|
)
|
|
return downloadSource === UNKNOWN_BREAKDOWN_VALUE
|
|
? UNKNOWN_BREAKDOWN_VALUE
|
|
: getDownloadSourceLabel(downloadSource, formatMessage)
|
|
}
|
|
case 'download_reason':
|
|
return normalizeBreakdownValue(
|
|
'reason' in point ? point.reason : undefined,
|
|
UNKNOWN_BREAKDOWN_VALUE,
|
|
)
|
|
case 'version_id':
|
|
return normalizeBreakdownValue('version_id' in point ? point.version_id : undefined)
|
|
case 'loader':
|
|
return normalizeBreakdownValue(
|
|
'loader' in point ? point.loader : undefined,
|
|
UNKNOWN_BREAKDOWN_VALUE,
|
|
)
|
|
case 'game_version':
|
|
return normalizeBreakdownValue(
|
|
'game_version' in point ? point.game_version : undefined,
|
|
UNKNOWN_BREAKDOWN_VALUE,
|
|
)
|
|
default:
|
|
return ALL_BREAKDOWN_VALUE
|
|
}
|
|
}
|
|
|
|
export function getAnalyticsBreakdownValues(
|
|
point: Labrinth.Analytics.v3.ProjectAnalytics,
|
|
selectedBreakdowns: readonly AnalyticsBreakdownPreset[],
|
|
formatMessage: FormatMessage,
|
|
): string[] {
|
|
return selectedBreakdowns
|
|
.filter((breakdown) => breakdown !== 'none')
|
|
.map((breakdown) => getAnalyticsBreakdownValue(point, breakdown, formatMessage))
|
|
}
|
|
|
|
export function getAnalyticsBreakdownKey(values: readonly string[]): string {
|
|
return values.map((value) => encodeURIComponent(value)).join('+')
|
|
}
|
|
|
|
export function getAnalyticsBreakdownDatasetId(
|
|
values: readonly string[],
|
|
selectedBreakdowns: readonly AnalyticsBreakdownPreset[],
|
|
): string {
|
|
const normalizedBreakdowns = selectedBreakdowns.filter((breakdown) => breakdown !== 'none')
|
|
if (normalizedBreakdowns.length === 0) {
|
|
return 'all'
|
|
}
|
|
if (normalizedBreakdowns.length === 1) {
|
|
if (normalizedBreakdowns[0] === 'project') {
|
|
return values[0] ?? 'all'
|
|
}
|
|
return `breakdown:${values[0] ?? 'all'}`
|
|
}
|
|
|
|
return `${COMBINED_BREAKDOWN_DATASET_ID_PREFIX}${getAnalyticsBreakdownKey(values)}`
|
|
}
|
|
|
|
export function getDownloadSourceLabel(value: string, formatMessage: FormatMessage): string {
|
|
return formatAnalyticsDownloadSourceLabel(value, formatMessage)
|
|
}
|
|
|
|
function normalizeBreakdownValue(
|
|
value: string | undefined,
|
|
fallback = ALL_BREAKDOWN_VALUE,
|
|
): string {
|
|
const normalized = value?.trim()
|
|
const normalizedLowercase = normalized?.toLowerCase()
|
|
if (
|
|
fallback === UNKNOWN_BREAKDOWN_VALUE &&
|
|
(normalizedLowercase === 'unknown' || normalizedLowercase === 'other')
|
|
) {
|
|
return fallback
|
|
}
|
|
return normalized && normalized.length > 0 ? normalized : fallback
|
|
}
|