Compare commits

...

7 Commits

Author SHA1 Message Date
6d13dc3eb1 Merge remote-tracking branch 'origin/master' into colonelpanic/allow-transient-homography-ids 2026-07-12 00:19:46 -07:00
e3524cab97 Merge pull request 'Add weekly cohort funnel to getUsageStats' (#293) from dean/usage-stats-cohorts into master
Reviewed-on: #293
2026-07-12 04:07:43 +00:00
20a70fad2a Allow transient homography IDs 2026-07-11 20:55:53 -07:00
Dean Wenstrand
35c7c23ba9 Add disjoint activated segment to cohorts for stacking
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:45:01 -07:00
Dean Wenstrand
40c4b82a59 Add weekly cohort funnel to getUsageStats
All checks were successful
Tests / Tests (pull_request) Successful in 13s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:40:10 -07:00
9ebe2e61df Merge pull request 'dean/usage-stats' (#292) from dean/usage-stats into master
Reviewed-on: #292
2026-07-11 19:26:13 +00:00
dc02fd8387 Merge pull request 'Select detected ball colors for Shot Lab' (#291) from colonelpanic/shot-lab-image-colors into master
Reviewed-on: #291
2026-07-10 17:20:37 +00:00
3 changed files with 69 additions and 7 deletions

View File

@@ -260,6 +260,15 @@ export type ClusterAssignmentInput = {
userId?: InputMaybe<Scalars["Int"]["input"]>; userId?: InputMaybe<Scalars["Int"]["input"]>;
}; };
export type CohortStatsGql = {
__typename?: "CohortStatsGQL";
activated7d: Scalars["Int"]["output"];
activatedNotPaid7d: Scalars["Int"]["output"];
paid7d: Scalars["Int"]["output"];
signups: Scalars["Int"]["output"];
weekStart: Scalars["Date"]["output"];
};
export type CommentGql = { export type CommentGql = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: Scalars["Int"]["output"]; id: Scalars["Int"]["output"];
@@ -2400,7 +2409,7 @@ export type HomographyInfoGql = {
crop: BoundingBoxGql; crop: BoundingBoxGql;
destPoints: PocketPointsGql; destPoints: PocketPointsGql;
frameIndex: Scalars["Int"]["output"]; frameIndex: Scalars["Int"]["output"];
id: Scalars["Int"]["output"]; id?: Maybe<Scalars["Int"]["output"]>;
pockets: Array<BoundingBoxGql>; pockets: Array<BoundingBoxGql>;
sourcePoints: PocketPointsGql; sourcePoints: PocketPointsGql;
}; };
@@ -3080,6 +3089,7 @@ export type Query = {
getResolvedTier: ResolvedTierGql; getResolvedTier: ResolvedTierGql;
getRuns: GetRunsResult; getRuns: GetRunsResult;
getShotAnnotationTypes: Array<ShotAnnotationTypeGql>; getShotAnnotationTypes: Array<ShotAnnotationTypeGql>;
getShotTableState: ShotTableStateGql;
getShots: Array<ShotGql>; getShots: Array<ShotGql>;
getShotsByIds: Array<ShotGql>; getShotsByIds: Array<ShotGql>;
getShotsWithMetadata: GetShotsResult; getShotsWithMetadata: GetShotsResult;
@@ -3225,6 +3235,10 @@ export type QueryGetShotAnnotationTypesArgs = {
errorTypes?: InputMaybe<Scalars["Boolean"]["input"]>; errorTypes?: InputMaybe<Scalars["Boolean"]["input"]>;
}; };
export type QueryGetShotTableStateArgs = {
shotId: Scalars["Int"]["input"];
};
export type QueryGetShotsArgs = { export type QueryGetShotsArgs = {
countRespectsLimit?: Scalars["Boolean"]["input"]; countRespectsLimit?: Scalars["Boolean"]["input"];
filterInput: FilterInput; filterInput: FilterInput;
@@ -3604,6 +3618,14 @@ export type ShotProjectionGql = {
trajectories: Array<BallTrajectoryGql>; trajectories: Array<BallTrajectoryGql>;
}; };
export type ShotTableStateGql = {
__typename?: "ShotTableStateGQL";
frameIndex: Scalars["Int"]["output"];
shotId: Scalars["Int"]["output"];
tableState: TableStateGql;
videoId: Scalars["Int"]["output"];
};
export type ShotsOrderingComponent = export type ShotsOrderingComponent =
| { | {
difficulty: FloatOrdering; difficulty: FloatOrdering;
@@ -3980,6 +4002,7 @@ export type UsageStatsDailyGql = {
export type UsageStatsGql = { export type UsageStatsGql = {
__typename?: "UsageStatsGQL"; __typename?: "UsageStatsGQL";
cohorts: Array<CohortStatsGql>;
daily: Array<UsageStatsDailyGql>; daily: Array<UsageStatsDailyGql>;
funnel: FunnelStatsGql; funnel: FunnelStatsGql;
processingLast24h: Array<ProcessingStatusCountGql>; processingLast24h: Array<ProcessingStatusCountGql>;
@@ -6826,7 +6849,7 @@ export type GetLiveTableStateQuery = {
} | null>; } | null>;
homography?: { homography?: {
__typename?: "HomographyInfoGQL"; __typename?: "HomographyInfoGQL";
id: number; id?: number | null;
frameIndex: number; frameIndex: number;
crop: { crop: {
__typename?: "BoundingBoxGQL"; __typename?: "BoundingBoxGQL";
@@ -7475,6 +7498,14 @@ export type GetUsageStatsQuery = {
retentionPrevActive: number; retentionPrevActive: number;
retentionReturned: number; retentionReturned: number;
}; };
cohorts: Array<{
__typename?: "CohortStatsGQL";
weekStart: any;
signups: number;
activated7d: number;
paid7d: number;
activatedNotPaid7d: number;
}>;
windows: Array<{ windows: Array<{
__typename?: "UsageStatsWindowGQL"; __typename?: "UsageStatsWindowGQL";
label: string; label: string;
@@ -7855,7 +7886,7 @@ export type GetStreamMonitoringDetailsQuery = {
elapsedTime?: number | null; elapsedTime?: number | null;
currentHomography?: { currentHomography?: {
__typename?: "HomographyInfoGQL"; __typename?: "HomographyInfoGQL";
id: number; id?: number | null;
frameIndex: number; frameIndex: number;
crop: { crop: {
__typename?: "BoundingBoxGQL"; __typename?: "BoundingBoxGQL";
@@ -8269,7 +8300,7 @@ export type GetVideoQuery = {
} | null; } | null;
homographyHistory: Array<{ homographyHistory: Array<{
__typename?: "HomographyInfoGQL"; __typename?: "HomographyInfoGQL";
id: number; id?: number | null;
frameIndex: number; frameIndex: number;
crop: { crop: {
__typename?: "BoundingBoxGQL"; __typename?: "BoundingBoxGQL";
@@ -8517,7 +8548,7 @@ export type FindPrerecordTableLayoutMutation = {
__typename?: "Mutation"; __typename?: "Mutation";
findPrerecordTableLayout?: { findPrerecordTableLayout?: {
__typename?: "HomographyInfoGQL"; __typename?: "HomographyInfoGQL";
id: number; id?: number | null;
frameIndex: number; frameIndex: number;
crop: { crop: {
__typename?: "BoundingBoxGQL"; __typename?: "BoundingBoxGQL";
@@ -8547,7 +8578,7 @@ export type FindPrerecordTableLayoutMutation = {
export type HomographyInfoFragment = { export type HomographyInfoFragment = {
__typename?: "HomographyInfoGQL"; __typename?: "HomographyInfoGQL";
id: number; id?: number | null;
frameIndex: number; frameIndex: number;
crop: { crop: {
__typename?: "BoundingBoxGQL"; __typename?: "BoundingBoxGQL";
@@ -15788,6 +15819,13 @@ export const GetUsageStatsDocument = gql`
retentionPrevActive retentionPrevActive
retentionReturned retentionReturned
} }
cohorts {
weekStart
signups
activated7d
paid7d
activatedNotPaid7d
}
totalUsers totalUsers
totalVideos totalVideos
totalShots totalShots

View File

@@ -12,6 +12,13 @@ query getUsageStats($days: Int! = 30) {
retentionPrevActive retentionPrevActive
retentionReturned retentionReturned
} }
cohorts {
weekStart
signups
activated7d
paid7d
activatedNotPaid7d
}
totalUsers totalUsers
totalVideos totalVideos
totalShots totalShots

View File

@@ -73,6 +73,7 @@ type Query {
useHomography: HomographyInputGQL = null useHomography: HomographyInputGQL = null
): TableStateGQL! ): TableStateGQL!
getLiveTableState(videoId: Int!): LiveTableStateGQL! getLiveTableState(videoId: Int!): LiveTableStateGQL!
getShotTableState(shotId: Int!): ShotTableStateGQL!
simulateShot(simulationInput: SimulateShotInputGQL!): ShotProjectionGQL! simulateShot(simulationInput: SimulateShotInputGQL!): ShotProjectionGQL!
computePotAim( computePotAim(
simulationInput: SimulateShotInputGQL! simulationInput: SimulateShotInputGQL!
@@ -609,7 +610,7 @@ type VideoTagClass {
} }
type HomographyInfoGQL { type HomographyInfoGQL {
id: Int! id: Int
frameIndex: Int! frameIndex: Int!
crop: BoundingBoxGQL! crop: BoundingBoxGQL!
pockets: [BoundingBoxGQL!]! pockets: [BoundingBoxGQL!]!
@@ -1065,6 +1066,13 @@ type LiveTableStateGQL {
tableState: TableStateGQL! tableState: TableStateGQL!
} }
type ShotTableStateGQL {
shotId: Int!
videoId: Int!
frameIndex: Int!
tableState: TableStateGQL!
}
type ShotProjectionGQL { type ShotProjectionGQL {
trajectories: [BallTrajectoryGQL!]! trajectories: [BallTrajectoryGQL!]!
events: [SimulationEventGQL!]! events: [SimulationEventGQL!]!
@@ -1175,6 +1183,7 @@ type UsageStatsGQL {
totalVideos: Int! totalVideos: Int!
totalShots: Int! totalShots: Int!
totalRuns: Int! totalRuns: Int!
cohorts: [CohortStatsGQL!]!
windows: [UsageStatsWindowGQL!]! windows: [UsageStatsWindowGQL!]!
daily: [UsageStatsDailyGQL!]! daily: [UsageStatsDailyGQL!]!
processingLast24h: [ProcessingStatusCountGQL!]! processingLast24h: [ProcessingStatusCountGQL!]!
@@ -1193,6 +1202,14 @@ type FunnelStatsGQL {
retentionReturned: Int! retentionReturned: Int!
} }
type CohortStatsGQL {
weekStart: Date!
signups: Int!
activated7d: Int!
paid7d: Int!
activatedNotPaid7d: Int!
}
type UsageStatsWindowGQL { type UsageStatsWindowGQL {
label: String! label: String!
newUsers: Int! newUsers: Int!