You've already forked AstralRinth
feat: improve analytics dashboard (#5897)
* feat: implement cancel/apply for custom timeframe range picker * feat: implement dot for showing todays date * feat: add max date to be today and show todays date * feat: if ratio mode, dont show total * feat: implement show more batching excess lines into "Other" bucket * refactor: pnpm prepr * feat: add pick and plop for date range start/end dates * feat: implement reset query button * feat: clear button to clear breakdown * feat: more aggressively trim allowed minimum group by option * fix: dont show project status filter when from project settings/analytics * fix: clear selected X above number when appropriate * feat: graph style updates and dont show year in x axis unless more than 2 year timeframe * fix: loading state to include legend in blur * feat: add project icon to project select * feat: filter out draft projects from analytics * feat: implement multiselect sections headers, project select org sections, and project options icons * feat: implement click and drag to select date range * feat: implement windows history for query builder * revert: no longer switch breakdown/filter option if same category * feat: implement showing project for project version breakdown/filter when there are multiple projects * feat: implement modrinth sided events * fix: border radius * feat: implement analytics range highlight * fix: loading state showing empty state text * refactor: pnpm prepr * feat: improve dropdown filter bar and multiselect performance * fix: multiselect keyboard use * fix: graph overflow issues * fix: loading state text on table * feat: implement tooltip scroll * fix: adjust charts event tooltip * feat: shorten time to not repeat am/pm * feat: implement query params for graph component settings * fix: qa * feat: add reset timeframe button * fix: legend colors moving between metric by determining color based on only downloads metric index * feat: implement auto switching temporarily to group by day for renvenue metric and disable revenue metric for time range < 2 days * fix: change to > 1 day * fix: custom timeframe picker * feat: implement big performance improvement for table * feat: implement hover on legend to highlight graph * fix: defer commit in query builder/filter and style fixes * feat: more performance optimization to analytics dashboard state, chart, and table * feat: add tooltip for other item * feat: improve custom time frame range select * feat: implement analytics events admin page * fix: switch column order * pnpm prepr * feat: implement mock analytics events * feat: improve analytics events admin page * feat: focus title input on analytics create event modal * fix: remove labels annoying * feat: hook up analytics events backend * fix: type error * feat: reduce combobox padding * feat: reduce padding on multiselect * feat: add overlay scrollbar for combobox * feat: a bunch of style fixes to combobox, multiselect and dropdown filter bar * feat: MORE PADDING fixes * feat: use user_agent for download source * Revert "feat: use user_agent for download source" This reverts commit d6dc8a99f11f94660872427796cdcf6fc93bb21d. * fix: query filter project version lag and borked virtualization * feat: rename breakdown "none" to "project" * feat: implement right side checkmark for multiselect * feat: keep crossed out legend items still shown in tooltip but also crossed out * fix: focus styles * fix: focus styles pt2 * feat: implement filter by top 8 * fix: preview is incorrect when selecting same date in range date picker * feat (playtest): cross out legend items in tooltip and allow hide/show in tooltip * feat (playtest): table component controls what graph shows * feat: change download source to use user_agent * feat: fix click to cross out in legend * feat: add hover legend item to highlight line in tooltip * fix: export csv to always be dropdown * feat: implement breakdown = none * performance: frontend memory reduction * performance: reduce memory usage from project versions query by keeping only whats necessary * fix: table checked items not in graph if 0 * feat: add shift click to select a range in table * performance: add caching for metric types so switching between them is snappy * performance: batch analytics requests by 15 project ids, with 150 ms delay between, so backend is happy * feat: add analytics table search * refactor: pnpm prepr * fix: query filter options not coming in from analytics fetch * feat: remove breakdown = none when there are multiple projects * feat: improve table sorting * feat: sort projects in project dropdown * fix: getting project name for project versions * fix: add loading state for filter and parallel fetch * performance: use precomputed map for project version options to remove first hover lag * feat: dropdown filter always open on one side and improve styles * fix: custom time range picker being weird * refactor: pnpm prepr * fix: add back in batch with 300ms interval for projects to prevent backend rate limiting * performance: only do queries to populate graph first before other analytics queries * fix: QA polish issues around style and copy * feat: dont show select all when its just one item in section * fix: bugs with ratio mode and hiding chart lines * fix: adjust padding in combobox and multiselect and fix not unfocusing when deselect * fix: small styles * fix: polish admin analytic events * fix: keep scroll position with selection action row appearing when selecting one * feat: add subheading in graph for showing N items from table * feat: add unmonetized explaination tooltip * performance: implement limit on how many lines can be shown in graph * feat: mobile pass * refactor: pnpm prepr * add clear button * feat: add time in analytics event and normalize date/time so its correct to timezones * fix: padding * feat: implement show prev period toggle * feat: extract TimeFramePicker to packages/ui * fix: adjust style * feat: keep table selected persisted in query parameter * fix: style on prev item value in legend * fix: when breakdown switches, reset selected series * fix: tooltip styles * feat: change project selection to reset to show top 8 only if reconciled down to 0 items * feat: implement show top 8 button in graph subheading * fix: rename download type to download reason * fix: formatting label for table * feat: persist table sort by and sort direction * fix: show top 8 button in graph not defaulting to top 8 for other metrics * feat: implement prev period analytics fetch into the same current period fetch by shifting start date * refactor: pnpm prepr * fix: remove number if its just top 1 * fix: brief select items empty state when switch breakdown * feat: implement format table playtime column * feat: update export csv filename * feat: change playtime column to display in hours * refactor: pnpm prepr * fix: still download type in filter * feat: update analytics tooltip * fix: wrong all projects icon * feat: force legend order and graph colour for monetization * refactor: pnpm prepr * fix: multiselect and combobox sizes * fix: chart icon add hover delay * feat: (to playtest) implement multiple breakdowns * fix: couple UX things for multiple breakdown * fix: cannot unpin on page click * fix: multiple breakdown legend and tooltip labels * feat: add right side checkmark for dropdown filtr bar * feat: enabling prev period will cross out prev for current ones already crossed out * feat-mobile: remove drag to select time frame in graph * feat-mobile: dropdown filter to replace dropdown for submenus on small screen * feat-mobile: time frame picker to use different start and end date pickers for mobile * fix-mobile: fix multiselect scroll on mobile * feat: consolidate is mobile ref into context * fix-mobile: combobox and multiselect scroll bug when mobile search bar open, fix timeframe picker mobile pick date, and dropdown filter bar click outside to close * fix-mobile: smaller metric card font * fix: dropdown filter bar scroll while search * feat: implement project side events * feat: implement better mobile view design for query builder * feat: handle events overflow * small: add select none * feat: remove clear project and breakdown * fix: event icon hover color * feat: default hide project events if there are multiple projects, and default show if only 1 project * feat: implement analytics performance updates, including facets, and v3 user projects * feat: grey out dimmed lined on legend item hover * feat-mobile: style fixes * add close on select prop * feat: add close on select for time frame picker mobile * feat: date picker default read only * refactor: pnpm prepr * feat: default to projects breakdown instead of no breakdown with multiple projects * fix-mobile: improve graph touch interactions * small: 2 sig figs on playtime * feat: deduplicate version uploads that have same version number and are uploaded on same day * fix: analytics events grouping causing overflow * feat: improve performance on analytics events grouping * fix: tooltip expanding page width briefly * fix: prevent double tap to zoom on inputs * feat: add click to show chart event for mobile * fix: toggle not having touch manipulation * fix: chart tooltip scroll in mobile * fix: remove project breakdownoption as it is default breakdown when none are selected * fix: dropdown filter bar briefly empty when switching pages in mobile * feat: keep tooltip open after drag in mobile * fix: using plural instead of single for project breakdown * fix: date picker scrolling page after picking date in mobile by suppressing focus * fix: callback to Organization instead of org id * feat: improve chart tooltip date range label formatter to be much more consistent * feat: tap to toggle event tooltip * fix: add user select none on graph and fix zoom into download threshold input * fix: frontend still filtering after backend already filters * feat: fix emptys state height content shift * fix: qa issues * fix: a number of qa issues - Hide project events based on visible project legend/table selection - Filter project status events by end status and add explicit copy for approved, private, and unlisted - Style Modrinth analytics events with blue icon, marker, guide, and range borders - Add scroll fade shadows to analytics chart and event tooltips - Show previous-period date range in the chart tooltip - Make project breakdown conditional on multiple selected projects and allow no breakdown when none are selected - Add breakdown selection actions and fix “Group by day” copy * feat: implement graph controls dropdown * fix date picker typing into time input * fix: styles in events table * small: style * feat: implement using new backend facets route * feat: implement user get all projects * performance: deter non-critical fetches to after analytics is in * fix: refreshing causes multiple projects to do breakdown=none * performance: cache project version options to fix lag on open sub menu * refactor: remove chart event height being controlled by parent * feat: update controls dropdown to have fainter border * fix: loading bar not fading away * fix: cannot click in graph * feat: dont conditionally show multiselect selection actions * fix: z-index and padding issues * fix: project events incorrectly toggling on for first page load * feat: remove show more and show less in legend, always show all * fix: playtime y axis labels * feat: improve y axis formatting for playtime and others * feat: use tabs for game version select, and remove prev period when change breakdown or project selection * refactor: pnpm prepr * feat: change hidden legend items to not contribute to ratio percentages * feat: event icon consume scroll for tooltip panel * feat: remove gap inside chart tooltip * feat: add gap for date picker 2 calendar view * feat: improve analytics events grouping logic for modrinth events to be close to target * pnpm prepr * fix: cant click in gap in toggle * fix: bugs around selected series from table not persisting with timeframe or filter changes * refactor: kabab case * refactor: split up large analytics chart and table component files into smaller components and ts modules * fix: legend is stale after resetting query * refactor: split up giant analytics provider with utils * i18n pass * revert: format number composable change * fix: playtime was choosing y axis ticks in seconds instead of hours * refactor: rename folder that with components to match main component name * refactor: same rename for analytics table for consistency * refactor: name main components to index.vue and keep folder name as component name * refactor: pnpm prepr * refactor: rename types * refactor: move query builder types into types file and move components into components/analytics-dashboard * refactor: colocate query builder url with analytics-dashboard component * refactor: pnpm prepr:frontend * fix: download threshold not width fit * fix: no option to see release/all game versions in selected filter dropdown * fix: game version dropdown width --------- Signed-off-by: Truman Gao <106889354+tdgao@users.noreply.github.com> Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
This commit is contained in:
@@ -14,6 +14,7 @@ import { KyrosLogsV1Module } from './kyros/logs/v1'
|
||||
import { KyrosUploadSessionsV1Module } from './kyros/upload-sessions/v1'
|
||||
import { LabrinthVersionsV2Module, LabrinthVersionsV3Module } from './labrinth'
|
||||
import { LabrinthAffiliateInternalModule } from './labrinth/affiliate/internal'
|
||||
import { LabrinthAnalyticsV3Module } from './labrinth/analytics/v3'
|
||||
import { LabrinthAuthInternalModule } from './labrinth/auth/internal'
|
||||
import { LabrinthAuthV2Module } from './labrinth/auth/v2'
|
||||
import { LabrinthBillingInternalModule } from './labrinth/billing/internal'
|
||||
@@ -40,6 +41,7 @@ import { LabrinthTeamsV3Module } from './labrinth/teams/v3'
|
||||
import { LabrinthTechReviewInternalModule } from './labrinth/tech-review/internal'
|
||||
import { LabrinthThreadsV3Module } from './labrinth/threads/v3'
|
||||
import { LabrinthUsersV2Module } from './labrinth/users/v2'
|
||||
import { LabrinthUsersV3Module } from './labrinth/users/v3'
|
||||
import { LauncherMetaManifestV0Module } from './launcher-meta/v0'
|
||||
import { MclogsInsightsV1Module } from './mclogs/insights/v1'
|
||||
import { MclogsLogsV1Module } from './mclogs/logs/v1'
|
||||
@@ -74,6 +76,7 @@ export const MODULE_REGISTRY = {
|
||||
kyros_logs_v1: KyrosLogsV1Module,
|
||||
kyros_upload_sessions_v1: KyrosUploadSessionsV1Module,
|
||||
labrinth_affiliate_internal: LabrinthAffiliateInternalModule,
|
||||
labrinth_analytics_v3: LabrinthAnalyticsV3Module,
|
||||
labrinth_auth_internal: LabrinthAuthInternalModule,
|
||||
labrinth_auth_v2: LabrinthAuthV2Module,
|
||||
labrinth_billing_internal: LabrinthBillingInternalModule,
|
||||
@@ -100,6 +103,7 @@ export const MODULE_REGISTRY = {
|
||||
labrinth_tech_review_internal: LabrinthTechReviewInternalModule,
|
||||
labrinth_threads_v3: LabrinthThreadsV3Module,
|
||||
labrinth_users_v2: LabrinthUsersV2Module,
|
||||
labrinth_users_v3: LabrinthUsersV3Module,
|
||||
labrinth_versions_v2: LabrinthVersionsV2Module,
|
||||
labrinth_versions_v3: LabrinthVersionsV3Module,
|
||||
paper_versions_v3: PaperVersionsV3Module,
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Labrinth } from '../types'
|
||||
|
||||
export class LabrinthAnalyticsV3Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'labrinth_analytics_v3'
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch analytics data for the authenticated user's accessible projects
|
||||
* and affiliate codes.
|
||||
*
|
||||
* @param data - Analytics request body defining time range and requested metrics
|
||||
* @returns Promise resolving to the analytics response, with time slices in `metrics`
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response = await client.labrinth.analytics_v3.fetch({
|
||||
* time_range: {
|
||||
* start: '2026-01-01T00:00:00Z',
|
||||
* end: '2026-02-01T00:00:00Z',
|
||||
* resolution: { slices: 31 },
|
||||
* },
|
||||
* project_ids: ['A1B2C3D4'],
|
||||
* return_metrics: {
|
||||
* project_views: { bucket_by: ['project_id'] },
|
||||
* },
|
||||
* })
|
||||
* const timeSlices = response.metrics
|
||||
* ```
|
||||
*/
|
||||
public async fetch(
|
||||
data: Labrinth.Analytics.v3.FetchRequest,
|
||||
): Promise<Labrinth.Analytics.v3.FetchResponse> {
|
||||
return this.client.request<Labrinth.Analytics.v3.FetchResponse>('/analytics', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'POST',
|
||||
body: data,
|
||||
timeout: 100 * 1000,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch available analytics filter facets for the authenticated user's
|
||||
* accessible projects.
|
||||
*
|
||||
* POST /v3/analytics/facets
|
||||
*/
|
||||
public async fetchFacets(
|
||||
data: Labrinth.Analytics.v3.FetchRequest,
|
||||
): Promise<Labrinth.Analytics.v3.FacetsResponse> {
|
||||
return this.client.request<Labrinth.Analytics.v3.FacetsResponse>('/analytics/facets', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'POST',
|
||||
body: data,
|
||||
timeout: 100 * 1000,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all analytics events.
|
||||
* GET /v3/analytics-event
|
||||
*/
|
||||
public async getEvents(): Promise<Labrinth.Analytics.v3.AnalyticsEvent[]> {
|
||||
return this.client.request<Labrinth.Analytics.v3.AnalyticsEvent[]>('/analytics-event', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an analytics event.
|
||||
* POST /v3/analytics-event
|
||||
*/
|
||||
public async createEvent(
|
||||
data: Labrinth.Analytics.v3.AnalyticsEventUpsert,
|
||||
): Promise<Labrinth.Analytics.v3.AnalyticsEvent> {
|
||||
return this.client.request<Labrinth.Analytics.v3.AnalyticsEvent>('/analytics-event', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'POST',
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an analytics event.
|
||||
* PATCH /v3/analytics-event/{id}
|
||||
*/
|
||||
public async editEvent(
|
||||
id: Labrinth.Analytics.v3.AnalyticsEventId,
|
||||
data: Labrinth.Analytics.v3.AnalyticsEventUpsert,
|
||||
): Promise<Labrinth.Analytics.v3.AnalyticsEvent> {
|
||||
return this.client.request<Labrinth.Analytics.v3.AnalyticsEvent>(`/analytics-event/${id}`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an analytics event.
|
||||
* DELETE /v3/analytics-event/{id}
|
||||
*/
|
||||
public async deleteEvent(id: Labrinth.Analytics.v3.AnalyticsEventId): Promise<void> {
|
||||
return this.client.request<void>(`/analytics-event/${id}`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './analytics/v3'
|
||||
export * from './auth/internal'
|
||||
export * from './auth/v2'
|
||||
export * from './billing/internal'
|
||||
@@ -21,5 +22,6 @@ export * from './state'
|
||||
export * from './tech-review/internal'
|
||||
export * from './threads/v3'
|
||||
export * from './users/v2'
|
||||
export * from './users/v3'
|
||||
export * from './versions/v2'
|
||||
export * from './versions/v3'
|
||||
|
||||
@@ -238,6 +238,267 @@ export namespace Labrinth {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Analytics {
|
||||
export namespace v3 {
|
||||
export type AnalyticsEventId = number
|
||||
export type AnalyticsEventMetricKind = 'views' | 'revenue' | 'downloads' | 'playtime'
|
||||
|
||||
export type AnalyticsEvent = {
|
||||
announcement_url: string | null
|
||||
for_metric_kind: AnalyticsEventMetricKind[] | null
|
||||
title: string
|
||||
ends: string
|
||||
id: AnalyticsEventId
|
||||
starts: string
|
||||
}
|
||||
|
||||
export type AnalyticsEventUpsert = {
|
||||
announcement_url: string | null
|
||||
for_metric_kind: AnalyticsEventMetricKind[] | null
|
||||
title: string
|
||||
ends: string
|
||||
starts: string
|
||||
}
|
||||
|
||||
export type FetchRequest = {
|
||||
time_range: TimeRange
|
||||
return_metrics: ReturnMetrics
|
||||
project_ids?: string[]
|
||||
}
|
||||
|
||||
export type TimeRange = {
|
||||
start: string
|
||||
end: string
|
||||
resolution: TimeRangeResolution
|
||||
}
|
||||
|
||||
export type TimeRangeResolution = { slices: number } | { minutes: number }
|
||||
|
||||
export type ReturnMetrics = {
|
||||
project_views?: Metrics<ProjectViewsField, ProjectViewsFilters>
|
||||
project_downloads?: Metrics<ProjectDownloadsField, ProjectDownloadsFilters>
|
||||
project_playtime?: Metrics<ProjectPlaytimeField, ProjectPlaytimeFilters>
|
||||
project_revenue?: Metrics<ProjectRevenueField, ProjectRevenueFilters>
|
||||
affiliate_code_clicks?: Metrics<AffiliateCodeClicksField, AffiliateCodeClicksFilters>
|
||||
affiliate_code_conversions?: Metrics<
|
||||
AffiliateCodeConversionsField,
|
||||
AffiliateCodeConversionsFilters
|
||||
>
|
||||
affiliate_code_revenue?: Metrics<AffiliateCodeRevenueField, AffiliateCodeRevenueFilters>
|
||||
}
|
||||
|
||||
export type Metrics<BucketBy, FilterBy> = {
|
||||
bucket_by?: BucketBy[]
|
||||
filter_by?: FilterBy
|
||||
}
|
||||
|
||||
export type ProjectViewsField =
|
||||
| 'project_id'
|
||||
| 'domain'
|
||||
| 'site_path'
|
||||
| 'monetized'
|
||||
| 'country'
|
||||
|
||||
export type ProjectDownloadsField =
|
||||
| 'project_id'
|
||||
| 'version_id'
|
||||
| 'user_agent'
|
||||
| 'domain'
|
||||
| 'country'
|
||||
| 'monetized'
|
||||
| 'reason'
|
||||
| 'game_version'
|
||||
| 'loader'
|
||||
|
||||
export type ProjectPlaytimeField =
|
||||
| 'project_id'
|
||||
| 'version_id'
|
||||
| 'loader'
|
||||
| 'game_version'
|
||||
| 'country'
|
||||
|
||||
export type ProjectRevenueField = 'project_id'
|
||||
|
||||
export type DownloadReason = 'standalone' | 'dependency' | 'modpack' | 'update'
|
||||
|
||||
export type AffiliateCodeClicksField = 'affiliate_code_id'
|
||||
|
||||
export type AffiliateCodeConversionsField = 'affiliate_code_id'
|
||||
|
||||
export type AffiliateCodeRevenueField = 'affiliate_code_id'
|
||||
|
||||
export type ProjectViewsFilters = {
|
||||
domain?: string[]
|
||||
site_path?: string[]
|
||||
monetized?: boolean[]
|
||||
country?: string[]
|
||||
}
|
||||
|
||||
export type ProjectDownloadsFilters = {
|
||||
version_id?: string[]
|
||||
domain?: string[]
|
||||
user_agent?: string[]
|
||||
monetized?: boolean[]
|
||||
country?: string[]
|
||||
reason?: DownloadReason[]
|
||||
game_version?: string[]
|
||||
loader?: string[]
|
||||
}
|
||||
|
||||
export type ProjectPlaytimeFilters = {
|
||||
version_id?: string[]
|
||||
loader?: string[]
|
||||
game_version?: string[]
|
||||
country?: string[]
|
||||
}
|
||||
|
||||
export type ProjectRevenueFilters = Record<string, never>
|
||||
|
||||
export type AffiliateCodeClicksFilters = {
|
||||
affiliate_code_id?: string[]
|
||||
}
|
||||
|
||||
export type AffiliateCodeConversionsFilters = {
|
||||
affiliate_code_id?: string[]
|
||||
}
|
||||
|
||||
export type AffiliateCodeRevenueFilters = {
|
||||
affiliate_code_id?: string[]
|
||||
}
|
||||
|
||||
export type FetchResponse = {
|
||||
metrics: TimeSlice[]
|
||||
project_events: ProjectAnalyticsEvent[]
|
||||
}
|
||||
|
||||
export type FacetsResponse = {
|
||||
facets: AnalyticsFacets
|
||||
}
|
||||
|
||||
export type AnalyticsFacet<T> = {
|
||||
value: T
|
||||
downloads: number
|
||||
}
|
||||
|
||||
export type AnalyticsFacets = {
|
||||
project_views: ProjectViewsFacets
|
||||
project_downloads: ProjectDownloadsFacets
|
||||
project_playtime: ProjectPlaytimeFacets
|
||||
}
|
||||
|
||||
export type ProjectViewsFacets = {
|
||||
domain: AnalyticsFacet<string>[]
|
||||
site_path: AnalyticsFacet<string>[]
|
||||
monetized: AnalyticsFacet<boolean>[]
|
||||
country: AnalyticsFacet<string>[]
|
||||
}
|
||||
|
||||
export type ProjectDownloadsFacets = {
|
||||
project_id: AnalyticsFacet<string>[]
|
||||
domain: AnalyticsFacet<string>[]
|
||||
user_agent: AnalyticsFacet<string>[]
|
||||
version_id: AnalyticsFacet<string>[]
|
||||
monetized: AnalyticsFacet<boolean>[]
|
||||
country: AnalyticsFacet<string>[]
|
||||
reason: AnalyticsFacet<DownloadReason>[]
|
||||
game_version: AnalyticsFacet<string>[]
|
||||
loader: AnalyticsFacet<string>[]
|
||||
}
|
||||
|
||||
export type ProjectPlaytimeFacets = {
|
||||
version_id: AnalyticsFacet<string>[]
|
||||
loader: AnalyticsFacet<string>[]
|
||||
game_version: AnalyticsFacet<string>[]
|
||||
country: AnalyticsFacet<string>[]
|
||||
}
|
||||
|
||||
export type TimeSlice = AnalyticsData[]
|
||||
|
||||
export type ProjectAnalyticsEvent = {
|
||||
project_id: string
|
||||
timestamp: string
|
||||
} & ProjectAnalyticsEventKind
|
||||
|
||||
export type ProjectAnalyticsEventKind =
|
||||
| {
|
||||
kind: 'version_uploaded'
|
||||
version_id: string
|
||||
version_name: string
|
||||
version_number: string
|
||||
}
|
||||
| {
|
||||
kind: 'status_changed'
|
||||
status_from: Projects.v2.ProjectStatus
|
||||
status_to: Projects.v2.ProjectStatus
|
||||
}
|
||||
|
||||
export type AnalyticsData = ProjectAnalytics | AffiliateCodeAnalytics
|
||||
|
||||
export type ProjectAnalytics = {
|
||||
source_project: string
|
||||
} & ProjectMetrics
|
||||
|
||||
export type ProjectMetrics =
|
||||
| ({ metric_kind: 'views' } & ProjectViews)
|
||||
| ({ metric_kind: 'downloads' } & ProjectDownloads)
|
||||
| ({ metric_kind: 'playtime' } & ProjectPlaytime)
|
||||
| ({ metric_kind: 'revenue' } & ProjectRevenue)
|
||||
|
||||
export type ProjectViews = {
|
||||
domain?: string
|
||||
site_path?: string
|
||||
monetized?: boolean
|
||||
country?: string
|
||||
views: number
|
||||
}
|
||||
|
||||
export type ProjectDownloads = {
|
||||
user_agent?: string
|
||||
domain?: string
|
||||
version_id?: string
|
||||
country?: string
|
||||
monetized?: boolean
|
||||
reason?: DownloadReason
|
||||
game_version?: string
|
||||
loader?: string
|
||||
downloads: number
|
||||
}
|
||||
|
||||
export type ProjectPlaytime = {
|
||||
version_id?: string
|
||||
loader?: string
|
||||
game_version?: string
|
||||
country?: string
|
||||
seconds: number
|
||||
}
|
||||
|
||||
export type ProjectRevenue = {
|
||||
revenue: string
|
||||
}
|
||||
|
||||
export type AffiliateCodeAnalytics = {
|
||||
source_affiliate_code: string
|
||||
} & AffiliateCodeMetrics
|
||||
|
||||
export type AffiliateCodeMetrics =
|
||||
| ({ metric_kind: 'clicks' } & AffiliateCodeClicks)
|
||||
| ({ metric_kind: 'conversions' } & AffiliateCodeConversions)
|
||||
| ({ metric_kind: 'revenue' } & AffiliateCodeRevenue)
|
||||
|
||||
export type AffiliateCodeClicks = {
|
||||
clicks: number
|
||||
}
|
||||
|
||||
export type AffiliateCodeConversions = {
|
||||
conversions: number
|
||||
}
|
||||
|
||||
export type AffiliateCodeRevenue = {
|
||||
revenue: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Auth {
|
||||
export namespace Internal {
|
||||
export type SubscriptionStatus = {
|
||||
@@ -1060,6 +1321,11 @@ export namespace Labrinth {
|
||||
allow_friend_requests?: boolean
|
||||
github_id?: number
|
||||
}
|
||||
|
||||
export type AllProjectsResponse = {
|
||||
projects: Projects.v3.Project[]
|
||||
organizations: Record<string, Organizations.v3.Organization>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Labrinth } from '../types'
|
||||
|
||||
export class LabrinthUsersV3Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'labrinth_users_v3'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all projects the authenticated user can access directly or through
|
||||
* their organizations.
|
||||
*
|
||||
* @param idOrUsername - User ID or username. Must be the authenticated user.
|
||||
*
|
||||
* GET /v3/user/{id}/all-projects
|
||||
*/
|
||||
public async getAllProjects(
|
||||
idOrUsername: string,
|
||||
): Promise<Labrinth.Users.v3.AllProjectsResponse> {
|
||||
return this.client.request<Labrinth.Users.v3.AllProjectsResponse>(
|
||||
`/user/${encodeURIComponent(idOrUsername)}/all-projects`,
|
||||
{
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user