Compare commits

..

12 Commits

Author SHA1 Message Date
8111042936 Add pool hall camera claim schema
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2026-06-16 15:41:16 -07:00
d6fd68c1f6 add quotaEnforcementEnabled to deployed config
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-05-28 14:40:31 -07:00
deb724b430 Add quota bucket status fields
All checks were successful
Tests / Tests (pull_request) Successful in 9s
2026-05-25 16:26:57 -07:00
Dean Wenstrand
9250e4c639 Add username + profileImageUri to PlayerClusterGQL
All checks were successful
Tests / Tests (pull_request) Successful in 9s
The labeling UI was falling back to "user N" for any assigned cluster
whose user wasn't the video owner — e.g. an admin re-labels a video
they don't own. With the resolver now resolving usernames for every
confirmed cluster, the FE can render real names regardless of who's
viewing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:25:34 -07:00
Dean Wenstrand
5cf2dbaf01 Add averageDifficulty to PlayerSummaryFields
All checks were successful
Tests / Tests (pull_request) Successful in 9s
Regenerated via `just gql` after BE added average_difficulty to
PlayerSummaryGQL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:34:25 -07:00
239a143554 Merge pull request 'Regenerate schema + add longestRun to PlayerSummaryFields' (#244) from dean/player-summaries-longest-run-types into master
Reviewed-on: #244
2026-05-11 20:29:39 +00:00
Dean Wenstrand
296522afb8 Regenerate schema + add longestRun to PlayerSummaryFields
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Generated by `just gql` after BE added longest_run to PlayerSummaryGQL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:21:47 -07:00
f42579076e Merge pull request 'Add score to PlayerSummaryFields + PlayerClusterFields fragments' (#243) from dean/video-match-score-types into master
Reviewed-on: #243
2026-05-11 17:43:43 +00:00
Dean Wenstrand
0c9eb4945a Add score to PlayerSummaryFields + PlayerClusterFields fragments
All checks were successful
Tests / Tests (pull_request) Successful in 9s
Picks up the BE additions in railbird PR dean/video-match-score:
new `score` field on PlayerClusterGQL and PlayerSummaryGQL, and
a new `score` input field on ClusterAssignmentInput.

Generated by `just gql`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:22:58 -07:00
1182c15004 Merge pull request 'Add playerSummaries to schema + Video fragments' (#242) from dean/player-summaries-types into master
Reviewed-on: #242
2026-05-09 19:34:40 +00:00
Dean Wenstrand
755336b16a Add playerSummaries to schema + Video fragments
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Backs the multi-player vs UI: feed cards and the detail page both
read `video.playerSummaries`, a per-cluster rollup with username,
profile image, representative full-frame URL, makes/total/percentage.

  - PlayerSummaryFields fragment in shooter.gql
  - VideoCardFields (feed) and GetVideoDetails (detail) include
    playerSummaries via the new fragment
  - VideoCardFields tag selection extended to include tagClasses,
    needed for the FE's player_count detection

Generated by `just gql` from the BE additions in railbird PR
dean/video-player-summaries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:02:57 -07:00
c1efe9f5f2 Merge pull request 'Add VideoPlayerClusters query + FinalizePlayerAssignments mutation' (#241) from dean/player-labeling-ops into master
Reviewed-on: #241
2026-05-09 04:46:10 +00:00
6 changed files with 493 additions and 3 deletions

View File

@@ -140,6 +140,39 @@ export type BucketSetInputGql = {
feature: Scalars["String"]["input"]; feature: Scalars["String"]["input"];
}; };
export type CameraClaimSession = {
__typename?: "CameraClaimSession";
camera: PoolHallCamera;
cameraId: Scalars["ID"]["output"];
challengeCode: Scalars["String"]["output"];
createdAt: Scalars["DateTime"]["output"];
detectedAt?: Maybe<Scalars["DateTime"]["output"]>;
expiresAt: Scalars["DateTime"]["output"];
failedAt?: Maybe<Scalars["DateTime"]["output"]>;
failureReason?: Maybe<Scalars["String"]["output"]>;
id: Scalars["ID"]["output"];
status: Scalars["String"]["output"];
updatedAt: Scalars["DateTime"]["output"];
userId: Scalars["ID"]["output"];
};
export type CameraLease = {
__typename?: "CameraLease";
camera: PoolHallCamera;
cameraId: Scalars["ID"]["output"];
claimSessionId?: Maybe<Scalars["ID"]["output"]>;
createdAt: Scalars["DateTime"]["output"];
endReason?: Maybe<Scalars["String"]["output"]>;
endedAt?: Maybe<Scalars["DateTime"]["output"]>;
expiresAt?: Maybe<Scalars["DateTime"]["output"]>;
id: Scalars["ID"]["output"];
startedAt: Scalars["DateTime"]["output"];
status: Scalars["String"]["output"];
updatedAt: Scalars["DateTime"]["output"];
userId: Scalars["ID"]["output"];
videoId?: Maybe<Scalars["ID"]["output"]>;
};
export type CancellationFeedbackMetadataInput = { export type CancellationFeedbackMetadataInput = {
appVersion?: InputMaybe<Scalars["String"]["input"]>; appVersion?: InputMaybe<Scalars["String"]["input"]>;
gitRevision?: InputMaybe<Scalars["String"]["input"]>; gitRevision?: InputMaybe<Scalars["String"]["input"]>;
@@ -207,6 +240,7 @@ export enum ClientUploadStatusEnum {
export type ClusterAssignmentInput = { export type ClusterAssignmentInput = {
clusterId: Scalars["Int"]["input"]; clusterId: Scalars["Int"]["input"];
score?: InputMaybe<Scalars["Int"]["input"]>;
userId?: InputMaybe<Scalars["Int"]["input"]>; userId?: InputMaybe<Scalars["Int"]["input"]>;
}; };
@@ -234,6 +268,21 @@ export type CreateCustomerPortalSessionResultGql = {
portalUrl: Scalars["String"]["output"]; portalUrl: Scalars["String"]["output"];
}; };
export type CreatePoolHallCameraInput = {
name: Scalars["String"]["input"];
poolHallId: Scalars["ID"]["input"];
streamPath?: InputMaybe<Scalars["String"]["input"]>;
tableLabel?: InputMaybe<Scalars["String"]["input"]>;
};
export type CreatePoolHallInput = {
address?: InputMaybe<Scalars["String"]["input"]>;
latitude?: InputMaybe<Scalars["Float"]["input"]>;
longitude?: InputMaybe<Scalars["Float"]["input"]>;
name: Scalars["String"]["input"];
timezone?: InputMaybe<Scalars["String"]["input"]>;
};
export type CreateSubscriptionResultGql = { export type CreateSubscriptionResultGql = {
__typename?: "CreateSubscriptionResultGQL"; __typename?: "CreateSubscriptionResultGQL";
checkoutUrl: Scalars["String"]["output"]; checkoutUrl: Scalars["String"]["output"];
@@ -289,6 +338,7 @@ export type DeployedConfigGql = {
environment: Scalars["String"]["output"]; environment: Scalars["String"]["output"];
firebase: Scalars["Boolean"]["output"]; firebase: Scalars["Boolean"]["output"];
minimumAllowedAppVersion: Scalars["String"]["output"]; minimumAllowedAppVersion: Scalars["String"]["output"];
quotaEnforcementEnabled: Scalars["Boolean"]["output"];
subscriptionGatingEnabled: Scalars["Boolean"]["output"]; subscriptionGatingEnabled: Scalars["Boolean"]["output"];
}; };
@@ -2385,11 +2435,15 @@ export type Mutation = {
addAnnotationToShot: AddShotAnnotationReturn; addAnnotationToShot: AddShotAnnotationReturn;
blockContent: Scalars["Boolean"]["output"]; blockContent: Scalars["Boolean"]["output"];
blockUser: Scalars["Boolean"]["output"]; blockUser: Scalars["Boolean"]["output"];
cancelCameraClaimSession: CameraClaimSession;
cancelSubscription: UserSubscriptionStatusGql; cancelSubscription: UserSubscriptionStatusGql;
commentOnVideo: Scalars["Boolean"]["output"]; commentOnVideo: Scalars["Boolean"]["output"];
createBucketSet: BucketSetGql; createBucketSet: BucketSetGql;
createCameraClaimSession: CameraClaimSession;
createChallenge: Challenge; createChallenge: Challenge;
createCustomerPortalSession: CreateCustomerPortalSessionResultGql; createCustomerPortalSession: CreateCustomerPortalSessionResultGql;
createPoolHall: PoolHall;
createPoolHallCamera: PoolHallCameraStreamCredentials;
createRuleSet: RuleSet; createRuleSet: RuleSet;
createSubscription: CreateSubscriptionResultGql; createSubscription: CreateSubscriptionResultGql;
createUploadStream: CreateUploadStreamReturn; createUploadStream: CreateUploadStreamReturn;
@@ -2422,6 +2476,7 @@ export type Mutation = {
respondToChallengeInvitation: ChallengeInvitation; respondToChallengeInvitation: ChallengeInvitation;
retireTags: Scalars["Boolean"]["output"]; retireTags: Scalars["Boolean"]["output"];
revokeManualEntitlement: UserSubscriptionStatusGql; revokeManualEntitlement: UserSubscriptionStatusGql;
rotatePoolHallCameraStreamKey: PoolHallCameraStreamCredentials;
setLoggerLevel: Scalars["Boolean"]["output"]; setLoggerLevel: Scalars["Boolean"]["output"];
setSegmentDuration: Scalars["Boolean"]["output"]; setSegmentDuration: Scalars["Boolean"]["output"];
startChallenge: ChallengeEntry; startChallenge: ChallengeEntry;
@@ -2429,6 +2484,8 @@ export type Mutation = {
submitChallengeEntry: ChallengeEntry; submitChallengeEntry: ChallengeEntry;
undismissChallenge: Scalars["Boolean"]["output"]; undismissChallenge: Scalars["Boolean"]["output"];
unfollowUser: UserGql; unfollowUser: UserGql;
updatePoolHall: PoolHall;
updatePoolHallCamera: PoolHallCamera;
updateShotAnnotations: UpdateShotAnnotationReturn; updateShotAnnotations: UpdateShotAnnotationReturn;
}; };
@@ -2446,6 +2503,10 @@ export type MutationBlockUserArgs = {
userId: Scalars["Int"]["input"]; userId: Scalars["Int"]["input"];
}; };
export type MutationCancelCameraClaimSessionArgs = {
claimSessionId: Scalars["ID"]["input"];
};
export type MutationCommentOnVideoArgs = { export type MutationCommentOnVideoArgs = {
message: Scalars["String"]["input"]; message: Scalars["String"]["input"];
parentCommentId?: InputMaybe<Scalars["Int"]["input"]>; parentCommentId?: InputMaybe<Scalars["Int"]["input"]>;
@@ -2456,6 +2517,10 @@ export type MutationCreateBucketSetArgs = {
params: CreateBucketSetInput; params: CreateBucketSetInput;
}; };
export type MutationCreateCameraClaimSessionArgs = {
cameraId: Scalars["ID"]["input"];
};
export type MutationCreateChallengeArgs = { export type MutationCreateChallengeArgs = {
description?: InputMaybe<Scalars["String"]["input"]>; description?: InputMaybe<Scalars["String"]["input"]>;
endDate: Scalars["DateTime"]["input"]; endDate: Scalars["DateTime"]["input"];
@@ -2469,6 +2534,14 @@ export type MutationCreateChallengeArgs = {
startDate: Scalars["DateTime"]["input"]; startDate: Scalars["DateTime"]["input"];
}; };
export type MutationCreatePoolHallArgs = {
input: CreatePoolHallInput;
};
export type MutationCreatePoolHallCameraArgs = {
input: CreatePoolHallCameraInput;
};
export type MutationCreateRuleSetArgs = { export type MutationCreateRuleSetArgs = {
description?: InputMaybe<Scalars["String"]["input"]>; description?: InputMaybe<Scalars["String"]["input"]>;
name: Scalars["String"]["input"]; name: Scalars["String"]["input"];
@@ -2604,6 +2677,10 @@ export type MutationRevokeManualEntitlementArgs = {
userId: Scalars["Int"]["input"]; userId: Scalars["Int"]["input"];
}; };
export type MutationRotatePoolHallCameraStreamKeyArgs = {
cameraId: Scalars["ID"]["input"];
};
export type MutationSetLoggerLevelArgs = { export type MutationSetLoggerLevelArgs = {
level: Scalars["String"]["input"]; level: Scalars["String"]["input"];
path: Scalars["String"]["input"]; path: Scalars["String"]["input"];
@@ -2638,6 +2715,14 @@ export type MutationUnfollowUserArgs = {
followedUserId: Scalars["Int"]["input"]; followedUserId: Scalars["Int"]["input"];
}; };
export type MutationUpdatePoolHallArgs = {
input: UpdatePoolHallInput;
};
export type MutationUpdatePoolHallCameraArgs = {
input: UpdatePoolHallCameraInput;
};
export type MutationUpdateShotAnnotationsArgs = { export type MutationUpdateShotAnnotationsArgs = {
annotations: Array<UpdateAnnotationInputGql>; annotations: Array<UpdateAnnotationInputGql>;
shotId: Scalars["Int"]["input"]; shotId: Scalars["Int"]["input"];
@@ -2700,8 +2785,11 @@ export type PlayerClusterGql = {
clusterId: Scalars["Int"]["output"]; clusterId: Scalars["Int"]["output"];
confirmed: Scalars["Boolean"]["output"]; confirmed: Scalars["Boolean"]["output"];
nShots: Scalars["Int"]["output"]; nShots: Scalars["Int"]["output"];
profileImageUri?: Maybe<Scalars["String"]["output"]>;
score?: Maybe<Scalars["Int"]["output"]>;
shots: Array<PlayerClusterShotGql>; shots: Array<PlayerClusterShotGql>;
userId?: Maybe<Scalars["Int"]["output"]>; userId?: Maybe<Scalars["Int"]["output"]>;
username?: Maybe<Scalars["String"]["output"]>;
videoId: Scalars["Int"]["output"]; videoId: Scalars["Int"]["output"];
}; };
@@ -2718,6 +2806,22 @@ export type PlayerClusterShotGql = {
shotId: Scalars["Int"]["output"]; shotId: Scalars["Int"]["output"];
}; };
export type PlayerSummaryGql = {
__typename?: "PlayerSummaryGQL";
averageDifficulty?: Maybe<Scalars["Float"]["output"]>;
averageTimeBetweenShots?: Maybe<Scalars["Float"]["output"]>;
clusterId: Scalars["Int"]["output"];
longestRun: Scalars["Int"]["output"];
makePercentage: Scalars["Float"]["output"];
profileImageUri?: Maybe<Scalars["String"]["output"]>;
representativeFullFrameUrl?: Maybe<Scalars["String"]["output"]>;
score?: Maybe<Scalars["Int"]["output"]>;
totalShots: Scalars["Int"]["output"];
totalShotsMade: Scalars["Int"]["output"];
userId?: Maybe<Scalars["Int"]["output"]>;
username?: Maybe<Scalars["String"]["output"]>;
};
export enum PocketEnum { export enum PocketEnum {
Corner = "CORNER", Corner = "CORNER",
Side = "SIDE", Side = "SIDE",
@@ -2770,6 +2874,41 @@ export type PocketingIntentionInfoGql = {
pocketId: PocketIdentifier; pocketId: PocketIdentifier;
}; };
export type PoolHall = {
__typename?: "PoolHall";
address?: Maybe<Scalars["String"]["output"]>;
createdAt: Scalars["DateTime"]["output"];
id: Scalars["ID"]["output"];
latitude?: Maybe<Scalars["Float"]["output"]>;
longitude?: Maybe<Scalars["Float"]["output"]>;
name: Scalars["String"]["output"];
status: Scalars["String"]["output"];
timezone?: Maybe<Scalars["String"]["output"]>;
updatedAt: Scalars["DateTime"]["output"];
};
export type PoolHallCamera = {
__typename?: "PoolHallCamera";
createdAt: Scalars["DateTime"]["output"];
id: Scalars["ID"]["output"];
lastPublishedAt?: Maybe<Scalars["DateTime"]["output"]>;
lastUnpublishedAt?: Maybe<Scalars["DateTime"]["output"]>;
name: Scalars["String"]["output"];
poolHall: PoolHall;
poolHallId: Scalars["ID"]["output"];
status: Scalars["String"]["output"];
streamPath: Scalars["String"]["output"];
tableLabel?: Maybe<Scalars["String"]["output"]>;
updatedAt: Scalars["DateTime"]["output"];
};
export type PoolHallCameraStreamCredentials = {
__typename?: "PoolHallCameraStreamCredentials";
camera: PoolHallCamera;
rtmpPath: Scalars["String"]["output"];
streamKey: Scalars["String"]["output"];
};
export type ProcessingFailedErr = { export type ProcessingFailedErr = {
__typename?: "ProcessingFailedErr"; __typename?: "ProcessingFailedErr";
processing: VideoProcessingGql; processing: VideoProcessingGql;
@@ -2788,9 +2927,13 @@ export enum ProcessingStatusEnum {
export type Query = { export type Query = {
__typename?: "Query"; __typename?: "Query";
activeCameraLease?: Maybe<CameraLease>;
cameraClaimSession?: Maybe<CameraClaimSession>;
challenge?: Maybe<Challenge>; challenge?: Maybe<Challenge>;
challengeLeaderboard: Array<ChallengeEntry>; challengeLeaderboard: Array<ChallengeEntry>;
challenges: Array<Challenge>; challenges: Array<Challenge>;
claimableCameras: Array<PoolHallCamera>;
claimablePoolHalls: Array<PoolHall>;
doesUsernameExist: Scalars["Boolean"]["output"]; doesUsernameExist: Scalars["Boolean"]["output"];
getAggregatedShotMetrics: Array<AggregateResultGql>; getAggregatedShotMetrics: Array<AggregateResultGql>;
getAvailableSubscriptionOptions: StripeSubscriptionOptionsGql; getAvailableSubscriptionOptions: StripeSubscriptionOptionsGql;
@@ -2826,12 +2969,18 @@ export type Query = {
myChallengeInvitations: Array<ChallengeInvitation>; myChallengeInvitations: Array<ChallengeInvitation>;
myDismissedChallenges: Array<Challenge>; myDismissedChallenges: Array<Challenge>;
notifications: NotificationConnection; notifications: NotificationConnection;
poolHallCameras: Array<PoolHallCamera>;
poolHalls: Array<PoolHall>;
ruleSets: Array<RuleSet>; ruleSets: Array<RuleSet>;
unreadNotificationCount: Scalars["Int"]["output"]; unreadNotificationCount: Scalars["Int"]["output"];
videoPlayerClusters: Array<PlayerClusterGql>; videoPlayerClusters: Array<PlayerClusterGql>;
waitFor: Scalars["Float"]["output"]; waitFor: Scalars["Float"]["output"];
}; };
export type QueryCameraClaimSessionArgs = {
id: Scalars["ID"]["input"];
};
export type QueryChallengeArgs = { export type QueryChallengeArgs = {
id: Scalars["ID"]["input"]; id: Scalars["ID"]["input"];
}; };
@@ -2845,6 +2994,10 @@ export type QueryChallengesArgs = {
includeDismissed?: Scalars["Boolean"]["input"]; includeDismissed?: Scalars["Boolean"]["input"];
}; };
export type QueryClaimableCamerasArgs = {
poolHallId: Scalars["ID"]["input"];
};
export type QueryDoesUsernameExistArgs = { export type QueryDoesUsernameExistArgs = {
candidateUsername: Scalars["String"]["input"]; candidateUsername: Scalars["String"]["input"];
}; };
@@ -2995,6 +3148,10 @@ export type QueryNotificationsArgs = {
offset?: Scalars["Int"]["input"]; offset?: Scalars["Int"]["input"];
}; };
export type QueryPoolHallCamerasArgs = {
poolHallId: Scalars["ID"]["input"];
};
export type QueryVideoPlayerClustersArgs = { export type QueryVideoPlayerClustersArgs = {
videoId: Scalars["Int"]["input"]; videoId: Scalars["Int"]["input"];
}; };
@@ -3003,15 +3160,29 @@ export type QueryWaitForArgs = {
duration: Scalars["Float"]["input"]; duration: Scalars["Float"]["input"];
}; };
export type QuotaBucketStatusGql = {
__typename?: "QuotaBucketStatusGQL";
appliesToUploadKind: Scalars["String"]["output"];
canUpload: Scalars["Boolean"]["output"];
durationLimitSeconds?: Maybe<Scalars["Int"]["output"]>;
durationRemainingSeconds?: Maybe<Scalars["Float"]["output"]>;
durationUsedSeconds: Scalars["Float"]["output"];
periodEnd: Scalars["DateTime"]["output"];
periodStart: Scalars["DateTime"]["output"];
quotaKey: Scalars["String"]["output"];
};
export type QuotaStatusGql = { export type QuotaStatusGql = {
__typename?: "QuotaStatusGQL"; __typename?: "QuotaStatusGQL";
canUpload: Scalars["Boolean"]["output"]; canUpload: Scalars["Boolean"]["output"];
durationLimitSeconds?: Maybe<Scalars["Int"]["output"]>; durationLimitSeconds?: Maybe<Scalars["Int"]["output"]>;
durationRemainingSeconds?: Maybe<Scalars["Float"]["output"]>; durationRemainingSeconds?: Maybe<Scalars["Float"]["output"]>;
durationUsedSeconds: Scalars["Float"]["output"]; durationUsedSeconds: Scalars["Float"]["output"];
importQuotaBuckets: Array<QuotaBucketStatusGql>;
maxVideoDurationSeconds?: Maybe<Scalars["Int"]["output"]>; maxVideoDurationSeconds?: Maybe<Scalars["Int"]["output"]>;
periodEnd: Scalars["DateTime"]["output"]; periodEnd: Scalars["DateTime"]["output"];
periodStart: Scalars["DateTime"]["output"]; periodStart: Scalars["DateTime"]["output"];
recordingQuotaBuckets: Array<QuotaBucketStatusGql>;
tierName: Scalars["String"]["output"]; tierName: Scalars["String"]["output"];
}; };
@@ -3397,6 +3568,23 @@ export type UpdateAnnotationInputGql = {
notes?: InputMaybe<Scalars["String"]["input"]>; notes?: InputMaybe<Scalars["String"]["input"]>;
}; };
export type UpdatePoolHallCameraInput = {
id: Scalars["ID"]["input"];
name?: InputMaybe<Scalars["String"]["input"]>;
status?: InputMaybe<Scalars["String"]["input"]>;
tableLabel?: InputMaybe<Scalars["String"]["input"]>;
};
export type UpdatePoolHallInput = {
address?: InputMaybe<Scalars["String"]["input"]>;
id: Scalars["ID"]["input"];
latitude?: InputMaybe<Scalars["Float"]["input"]>;
longitude?: InputMaybe<Scalars["Float"]["input"]>;
name?: InputMaybe<Scalars["String"]["input"]>;
status?: InputMaybe<Scalars["String"]["input"]>;
timezone?: InputMaybe<Scalars["String"]["input"]>;
};
export type UpdateShotAnnotationReturn = { export type UpdateShotAnnotationReturn = {
__typename?: "UpdateShotAnnotationReturn"; __typename?: "UpdateShotAnnotationReturn";
error?: Maybe<DoesNotOwnShotErr>; error?: Maybe<DoesNotOwnShotErr>;
@@ -3557,6 +3745,7 @@ export type VideoGql = {
medianRun?: Maybe<Scalars["Float"]["output"]>; medianRun?: Maybe<Scalars["Float"]["output"]>;
name?: Maybe<Scalars["String"]["output"]>; name?: Maybe<Scalars["String"]["output"]>;
owner?: Maybe<UserGql>; owner?: Maybe<UserGql>;
playerSummaries: Array<PlayerSummaryGql>;
playlist?: Maybe<HlsPlaylistGql>; playlist?: Maybe<HlsPlaylistGql>;
pocketSize?: Maybe<Scalars["Float"]["output"]>; pocketSize?: Maybe<Scalars["Float"]["output"]>;
private: Scalars["Boolean"]["output"]; private: Scalars["Boolean"]["output"];
@@ -4098,6 +4287,7 @@ export type GetDeployedConfigQuery = {
firebase: boolean; firebase: boolean;
minimumAllowedAppVersion: string; minimumAllowedAppVersion: string;
subscriptionGatingEnabled: boolean; subscriptionGatingEnabled: boolean;
quotaEnforcementEnabled: boolean;
defaultAndroidRecordingFormat: StreamSegmentTypeEnum; defaultAndroidRecordingFormat: StreamSegmentTypeEnum;
bucketUrl: string; bucketUrl: string;
bannerMessages: Array<{ bannerMessages: Array<{
@@ -4174,7 +4364,26 @@ export type GetFeedQuery = {
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ __typename?: "VideoTag"; name: string }>; tags: Array<{
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
playerSummaries: Array<{
__typename?: "PlayerSummaryGQL";
clusterId: number;
userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
representativeFullFrameUrl?: string | null;
totalShots: number;
totalShotsMade: number;
makePercentage: number;
score?: number | null;
longestRun: number;
averageDifficulty?: number | null;
averageTimeBetweenShots?: number | null;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
@@ -4259,7 +4468,26 @@ export type VideoCardFieldsFragment = {
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ __typename?: "VideoTag"; name: string }>; tags: Array<{
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
playerSummaries: Array<{
__typename?: "PlayerSummaryGQL";
clusterId: number;
userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
representativeFullFrameUrl?: string | null;
totalShots: number;
totalShotsMade: number;
makePercentage: number;
score?: number | null;
longestRun: number;
averageDifficulty?: number | null;
averageTimeBetweenShots?: number | null;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
@@ -4358,7 +4586,26 @@ export type GetVideoFeedQuery = {
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ __typename?: "VideoTag"; name: string }>; tags: Array<{
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
playerSummaries: Array<{
__typename?: "PlayerSummaryGQL";
clusterId: number;
userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
representativeFullFrameUrl?: string | null;
totalShots: number;
totalShotsMade: number;
makePercentage: number;
score?: number | null;
longestRun: number;
averageDifficulty?: number | null;
averageTimeBetweenShots?: number | null;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
@@ -4929,6 +5176,22 @@ export type GetRunsWithTimestampsQuery = {
}; };
}; };
export type PlayerSummaryFieldsFragment = {
__typename?: "PlayerSummaryGQL";
clusterId: number;
userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
representativeFullFrameUrl?: string | null;
totalShots: number;
totalShotsMade: number;
makePercentage: number;
score?: number | null;
longestRun: number;
averageDifficulty?: number | null;
averageTimeBetweenShots?: number | null;
};
export type PlayerClusterShotFieldsFragment = { export type PlayerClusterShotFieldsFragment = {
__typename?: "PlayerClusterShotGQL"; __typename?: "PlayerClusterShotGQL";
shotId: number; shotId: number;
@@ -4948,7 +5211,10 @@ export type PlayerClusterFieldsFragment = {
clusterId: number; clusterId: number;
nShots: number; nShots: number;
userId?: number | null; userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
confirmed: boolean; confirmed: boolean;
score?: number | null;
shots: Array<{ shots: Array<{
__typename?: "PlayerClusterShotGQL"; __typename?: "PlayerClusterShotGQL";
shotId: number; shotId: number;
@@ -4975,7 +5241,10 @@ export type VideoPlayerClustersQuery = {
clusterId: number; clusterId: number;
nShots: number; nShots: number;
userId?: number | null; userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
confirmed: boolean; confirmed: boolean;
score?: number | null;
shots: Array<{ shots: Array<{
__typename?: "PlayerClusterShotGQL"; __typename?: "PlayerClusterShotGQL";
shotId: number; shotId: number;
@@ -5003,7 +5272,10 @@ export type FinalizePlayerAssignmentsMutation = {
clusterId: number; clusterId: number;
nShots: number; nShots: number;
userId?: number | null; userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
confirmed: boolean; confirmed: boolean;
score?: number | null;
shots: Array<{ shots: Array<{
__typename?: "PlayerClusterShotGQL"; __typename?: "PlayerClusterShotGQL";
shotId: number; shotId: number;
@@ -5955,6 +6227,21 @@ export type GetVideoDetailsQuery = {
name: string; name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>; tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>; }>;
playerSummaries: Array<{
__typename?: "PlayerSummaryGQL";
clusterId: number;
userId?: number | null;
username?: string | null;
profileImageUri?: string | null;
representativeFullFrameUrl?: string | null;
totalShots: number;
totalShotsMade: number;
makePercentage: number;
score?: number | null;
longestRun: number;
averageDifficulty?: number | null;
averageTimeBetweenShots?: number | null;
}>;
}; };
}; };
@@ -6612,6 +6899,22 @@ export type GetUploadStreamsWithDetailsQuery = {
}; };
}; };
export const PlayerSummaryFieldsFragmentDoc = gql`
fragment PlayerSummaryFields on PlayerSummaryGQL {
clusterId
userId
username
profileImageUri
representativeFullFrameUrl
totalShots
totalShotsMade
makePercentage
score
longestRun
averageDifficulty
averageTimeBetweenShots
}
`;
export const UserSocialsFieldsFragmentDoc = gql` export const UserSocialsFieldsFragmentDoc = gql`
fragment UserSocialsFields on UserGQL { fragment UserSocialsFields on UserGQL {
id id
@@ -6646,6 +6949,12 @@ export const VideoCardFieldsFragmentDoc = gql`
pocketSize pocketSize
tags { tags {
name name
tagClasses {
name
}
}
playerSummaries {
...PlayerSummaryFields
} }
currentProcessing { currentProcessing {
id id
@@ -6673,6 +6982,7 @@ export const VideoCardFieldsFragmentDoc = gql`
} }
} }
} }
${PlayerSummaryFieldsFragmentDoc}
${UserSocialsFieldsFragmentDoc} ${UserSocialsFieldsFragmentDoc}
`; `;
export const MedalFieldsFragmentDoc = gql` export const MedalFieldsFragmentDoc = gql`
@@ -6741,7 +7051,10 @@ export const PlayerClusterFieldsFragmentDoc = gql`
clusterId clusterId
nShots nShots
userId userId
username
profileImageUri
confirmed confirmed
score
shots { shots {
...PlayerClusterShotFields ...PlayerClusterShotFields
} }
@@ -8433,6 +8746,7 @@ export const GetDeployedConfigDocument = gql`
firebase firebase
minimumAllowedAppVersion minimumAllowedAppVersion
subscriptionGatingEnabled subscriptionGatingEnabled
quotaEnforcementEnabled
bannerMessages { bannerMessages {
color color
dismissible dismissible
@@ -12666,8 +12980,12 @@ export const GetVideoDetailsDocument = gql`
} }
name name
} }
playerSummaries {
...PlayerSummaryFields
} }
} }
}
${PlayerSummaryFieldsFragmentDoc}
`; `;
/** /**

View File

@@ -6,6 +6,7 @@ query getDeployedConfig {
firebase firebase
minimumAllowedAppVersion minimumAllowedAppVersion
subscriptionGatingEnabled subscriptionGatingEnabled
quotaEnforcementEnabled
bannerMessages { bannerMessages {
color color
dismissible dismissible

View File

@@ -47,6 +47,12 @@ fragment VideoCardFields on VideoGQL {
pocketSize pocketSize
tags { tags {
name name
tagClasses {
name
}
}
playerSummaries {
...PlayerSummaryFields
} }
currentProcessing { currentProcessing {
id id

View File

@@ -1,3 +1,18 @@
fragment PlayerSummaryFields on PlayerSummaryGQL {
clusterId
userId
username
profileImageUri
representativeFullFrameUrl
totalShots
totalShotsMade
makePercentage
score
longestRun
averageDifficulty
averageTimeBetweenShots
}
fragment PlayerClusterShotFields on PlayerClusterShotGQL { fragment PlayerClusterShotFields on PlayerClusterShotGQL {
shotId shotId
bboxX1 bboxX1
@@ -15,7 +30,10 @@ fragment PlayerClusterFields on PlayerClusterGQL {
clusterId clusterId
nShots nShots
userId userId
username
profileImageUri
confirmed confirmed
score
shots { shots {
...PlayerClusterShotFields ...PlayerClusterShotFields
} }

View File

@@ -83,6 +83,9 @@ query GetVideoDetails($videoId: Int!) {
} }
name name
} }
playerSummaries {
...PlayerSummaryFields
}
} }
} }

View File

@@ -42,6 +42,12 @@ type Query {
filters: NotificationFilters = null filters: NotificationFilters = null
): NotificationConnection! ): NotificationConnection!
unreadNotificationCount: Int! unreadNotificationCount: Int!
poolHalls: [PoolHall!]!
claimablePoolHalls: [PoolHall!]!
poolHallCameras(poolHallId: ID!): [PoolHallCamera!]!
claimableCameras(poolHallId: ID!): [PoolHallCamera!]!
cameraClaimSession(id: ID!): CameraClaimSession
activeCameraLease: CameraLease
getRuns( getRuns(
filterInput: RunFilterInput! filterInput: RunFilterInput!
runIds: [Int!] = null runIds: [Int!] = null
@@ -406,6 +412,7 @@ type VideoGQL {
currentProcessing: VideoProcessingGQL currentProcessing: VideoProcessingGQL
reactions: [ReactionGQL!]! reactions: [ReactionGQL!]!
comments: [CommentGQL!]! comments: [CommentGQL!]!
playerSummaries: [PlayerSummaryGQL!]!
} }
type ShotGQL { type ShotGQL {
@@ -665,6 +672,21 @@ type CommentGQL {
replies: [CommentGQL!]! replies: [CommentGQL!]!
} }
type PlayerSummaryGQL {
clusterId: Int!
userId: Int
username: String
profileImageUri: String
representativeFullFrameUrl: String
totalShots: Int!
totalShotsMade: Int!
makePercentage: Float!
score: Int
longestRun: Int!
averageDifficulty: Float
averageTimeBetweenShots: Float
}
type DeployedConfigGQL { type DeployedConfigGQL {
allowNewUsers: Boolean! allowNewUsers: Boolean!
firebase: Boolean! firebase: Boolean!
@@ -672,6 +694,7 @@ type DeployedConfigGQL {
environment: String! environment: String!
minimumAllowedAppVersion: String! minimumAllowedAppVersion: String!
subscriptionGatingEnabled: Boolean! subscriptionGatingEnabled: Boolean!
quotaEnforcementEnabled: Boolean!
bannerMessages: [BannerGQL!]! bannerMessages: [BannerGQL!]!
defaultAndroidRecordingFormat: StreamSegmentTypeEnum! defaultAndroidRecordingFormat: StreamSegmentTypeEnum!
bucketUrl: String! bucketUrl: String!
@@ -823,6 +846,63 @@ input NotificationFilters {
notificationTypes: [NotificationTypeEnum!] = null notificationTypes: [NotificationTypeEnum!] = null
} }
type PoolHall {
id: ID!
name: String!
address: String
latitude: Float
longitude: Float
timezone: String
status: String!
createdAt: DateTime!
updatedAt: DateTime!
}
type PoolHallCamera {
id: ID!
poolHallId: ID!
name: String!
tableLabel: String
streamPath: String!
status: String!
lastPublishedAt: DateTime
lastUnpublishedAt: DateTime
createdAt: DateTime!
updatedAt: DateTime!
poolHall: PoolHall!
}
type CameraClaimSession {
id: ID!
cameraId: ID!
userId: ID!
challengeCode: String!
status: String!
expiresAt: DateTime!
detectedAt: DateTime
failedAt: DateTime
failureReason: String
createdAt: DateTime!
updatedAt: DateTime!
camera: PoolHallCamera!
}
type CameraLease {
id: ID!
cameraId: ID!
claimSessionId: ID
userId: ID!
videoId: ID
status: String!
startedAt: DateTime!
endedAt: DateTime
expiresAt: DateTime
endReason: String
createdAt: DateTime!
updatedAt: DateTime!
camera: PoolHallCamera!
}
type GetRunsResult { type GetRunsResult {
runs: [RunGQL!]! runs: [RunGQL!]!
count: Int count: Int
@@ -866,7 +946,10 @@ type PlayerClusterGQL {
clusterId: Int! clusterId: Int!
nShots: Int! nShots: Int!
userId: Int userId: Int
username: String
profileImageUri: String
confirmed: Boolean! confirmed: Boolean!
score: Int
shots: [PlayerClusterShotGQL!]! shots: [PlayerClusterShotGQL!]!
} }
@@ -1021,6 +1104,19 @@ type QuotaStatusGQL {
durationUsedSeconds: Float! durationUsedSeconds: Float!
durationLimitSeconds: Int durationLimitSeconds: Int
maxVideoDurationSeconds: Int maxVideoDurationSeconds: Int
importQuotaBuckets: [QuotaBucketStatusGQL!]!
recordingQuotaBuckets: [QuotaBucketStatusGQL!]!
durationRemainingSeconds: Float
canUpload: Boolean!
}
type QuotaBucketStatusGQL {
quotaKey: String!
appliesToUploadKind: String!
periodStart: DateTime!
periodEnd: DateTime!
durationUsedSeconds: Float!
durationLimitSeconds: Int
durationRemainingSeconds: Float durationRemainingSeconds: Float
canUpload: Boolean! canUpload: Boolean!
} }
@@ -1116,6 +1212,15 @@ type Mutation {
markAllNotificationsAsRead: Boolean! markAllNotificationsAsRead: Boolean!
markNotificationsAsRead(notificationIds: [Int!]!): Boolean! markNotificationsAsRead(notificationIds: [Int!]!): Boolean!
deleteNotification(notificationId: Int!): Boolean! deleteNotification(notificationId: Int!): Boolean!
createPoolHall(input: CreatePoolHallInput!): PoolHall!
updatePoolHall(input: UpdatePoolHallInput!): PoolHall!
createPoolHallCamera(
input: CreatePoolHallCameraInput!
): PoolHallCameraStreamCredentials!
updatePoolHallCamera(input: UpdatePoolHallCameraInput!): PoolHallCamera!
rotatePoolHallCameraStreamKey(cameraId: ID!): PoolHallCameraStreamCredentials!
createCameraClaimSession(cameraId: ID!): CameraClaimSession!
cancelCameraClaimSession(claimSessionId: ID!): CameraClaimSession!
finalizePlayerAssignments( finalizePlayerAssignments(
input: FinalizePlayerAssignmentsInput! input: FinalizePlayerAssignmentsInput!
): [PlayerClusterGQL!]! ): [PlayerClusterGQL!]!
@@ -1190,6 +1295,44 @@ enum ReportReasonEnum {
OTHER OTHER
} }
input CreatePoolHallInput {
name: String!
address: String = null
latitude: Float = null
longitude: Float = null
timezone: String = null
}
input UpdatePoolHallInput {
id: ID!
name: String = null
address: String = null
latitude: Float = null
longitude: Float = null
timezone: String = null
status: String = null
}
type PoolHallCameraStreamCredentials {
camera: PoolHallCamera!
streamKey: String!
rtmpPath: String!
}
input CreatePoolHallCameraInput {
poolHallId: ID!
name: String!
tableLabel: String = null
streamPath: String = null
}
input UpdatePoolHallCameraInput {
id: ID!
name: String = null
tableLabel: String = null
status: String = null
}
input FinalizePlayerAssignmentsInput { input FinalizePlayerAssignmentsInput {
videoId: Int! videoId: Int!
clusterAssignments: [ClusterAssignmentInput!]! = [] clusterAssignments: [ClusterAssignmentInput!]! = []
@@ -1199,6 +1342,7 @@ input FinalizePlayerAssignmentsInput {
input ClusterAssignmentInput { input ClusterAssignmentInput {
clusterId: Int! clusterId: Int!
userId: Int = null userId: Int = null
score: Int = null
} }
input ShotMoveInput { input ShotMoveInput {