Compare commits

...

11 Commits

Author SHA1 Message Date
84d3a0252d Merge pull request 'Add player cluster + labeling mutation types' (#240) from dean/labeling-api-types into master
Reviewed-on: #240
2026-05-09 00:38:29 +00:00
Dean Wenstrand
1de4a97cb6 Add player cluster + labeling mutation types
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Schema additions for the per-video player labeling UI:
  * `PlayerClusterGQL` / `PlayerClusterShotGQL` — read shape.
  * `FinalizePlayerAssignmentsInput` + `ClusterAssignmentInput` +
    `ShotMoveInput` — write shape.
  * Query: `videoPlayerClusters(videoId)`.
  * Mutation: `finalizePlayerAssignments(input)`.

Generated by `just gql` from the backend type definitions in
`railbird/datatypes/gql/shooter.py` and resolvers in
`railbird/server/resolvers/shooter.py`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 15:04:41 -07:00
130314546c Merge pull request 'Add trial days to GetAvailableSubscriptions' (#239) from loewy/add-trial-period-days into master
Reviewed-on: #239
2026-05-04 21:46:45 +00:00
b88f172355 add trial days to return
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-05-04 14:07:16 -07:00
639fc88b0b Merge pull request 'Add createCustomerPortalSession' (#238) from loewy/create-customer-portal-session into master
Reviewed-on: #238
2026-05-01 22:45:40 +00:00
20f50368c9 remove return url
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-05-01 13:15:18 -07:00
8367c2d0cd add createCustomerPortalSession
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-04-30 11:44:34 -07:00
b0c62f6e80 Merge pull request 'Trim getFeed query fragment' (#237) from loewy/trim-get-feed-query-fragment into master
Reviewed-on: #237
2026-04-29 20:26:40 +00:00
bc1ff66467 trim uncessary requested fields
All checks were successful
Tests / Tests (pull_request) Successful in 38s
2026-04-28 12:53:25 -07:00
ae37a3d9d9 Merge pull request 'Default getLongestRunsLeaderboard limit to 50' (#236) from dean/leaderboard-default-top-50 into master
Reviewed-on: #236
2026-04-24 00:01:23 +00:00
Dean Wenstrand
114b21400e Default getLongestRunsLeaderboard limit to 50
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:56:56 -07:00
4 changed files with 178 additions and 82 deletions

View File

@@ -205,6 +205,11 @@ export enum ClientUploadStatusEnum {
UploadEnabled = "UPLOAD_ENABLED", UploadEnabled = "UPLOAD_ENABLED",
} }
export type ClusterAssignmentInput = {
clusterId: Scalars["Int"]["input"];
userId?: InputMaybe<Scalars["Int"]["input"]>;
};
export type CommentGql = { export type CommentGql = {
__typename?: "CommentGQL"; __typename?: "CommentGQL";
id: Scalars["Int"]["output"]; id: Scalars["Int"]["output"];
@@ -224,6 +229,11 @@ export type CreateBucketSetInput = {
keyName: Scalars["String"]["input"]; keyName: Scalars["String"]["input"];
}; };
export type CreateCustomerPortalSessionResultGql = {
__typename?: "CreateCustomerPortalSessionResultGQL";
portalUrl: Scalars["String"]["output"];
};
export type CreateSubscriptionResultGql = { export type CreateSubscriptionResultGql = {
__typename?: "CreateSubscriptionResultGQL"; __typename?: "CreateSubscriptionResultGQL";
checkoutUrl: Scalars["String"]["output"]; checkoutUrl: Scalars["String"]["output"];
@@ -2177,6 +2187,12 @@ export type FilterInput =
videoId: Array<Scalars["Int"]["input"]>; videoId: Array<Scalars["Int"]["input"]>;
}; };
export type FinalizePlayerAssignmentsInput = {
clusterAssignments?: Array<ClusterAssignmentInput>;
shotMoves?: Array<ShotMoveInput>;
videoId: Scalars["Int"]["input"];
};
export type FloatOrdering = { export type FloatOrdering = {
descending?: Scalars["Boolean"]["input"]; descending?: Scalars["Boolean"]["input"];
startingAt?: InputMaybe<Scalars["Float"]["input"]>; startingAt?: InputMaybe<Scalars["Float"]["input"]>;
@@ -2373,6 +2389,7 @@ export type Mutation = {
commentOnVideo: Scalars["Boolean"]["output"]; commentOnVideo: Scalars["Boolean"]["output"];
createBucketSet: BucketSetGql; createBucketSet: BucketSetGql;
createChallenge: Challenge; createChallenge: Challenge;
createCustomerPortalSession: CreateCustomerPortalSessionResultGql;
createRuleSet: RuleSet; createRuleSet: RuleSet;
createSubscription: CreateSubscriptionResultGql; createSubscription: CreateSubscriptionResultGql;
createUploadStream: CreateUploadStreamReturn; createUploadStream: CreateUploadStreamReturn;
@@ -2388,6 +2405,7 @@ export type Mutation = {
editUploadStream: Scalars["Boolean"]["output"]; editUploadStream: Scalars["Boolean"]["output"];
editUser: UserGql; editUser: UserGql;
ensureStripeCustomerExists: UserGql; ensureStripeCustomerExists: UserGql;
finalizePlayerAssignments: Array<PlayerClusterGql>;
findPrerecordTableLayout?: Maybe<HomographyInfoGql>; findPrerecordTableLayout?: Maybe<HomographyInfoGql>;
followUser: UserGql; followUser: UserGql;
getHlsInitUploadLink: GetUploadLinkReturn; getHlsInitUploadLink: GetUploadLinkReturn;
@@ -2511,6 +2529,10 @@ export type MutationEditUserArgs = {
input: EditUserInputGql; input: EditUserInputGql;
}; };
export type MutationFinalizePlayerAssignmentsArgs = {
input: FinalizePlayerAssignmentsInput;
};
export type MutationFindPrerecordTableLayoutArgs = { export type MutationFindPrerecordTableLayoutArgs = {
b64Image: Scalars["String"]["input"]; b64Image: Scalars["String"]["input"];
videoId: Scalars["Int"]["input"]; videoId: Scalars["Int"]["input"];
@@ -2673,6 +2695,29 @@ export type PageInfoGql = {
hasNextPage: Scalars["Boolean"]["output"]; hasNextPage: Scalars["Boolean"]["output"];
}; };
export type PlayerClusterGql = {
__typename?: "PlayerClusterGQL";
clusterId: Scalars["Int"]["output"];
confirmed: Scalars["Boolean"]["output"];
nShots: Scalars["Int"]["output"];
shots: Array<PlayerClusterShotGql>;
userId?: Maybe<Scalars["Int"]["output"]>;
videoId: Scalars["Int"]["output"];
};
export type PlayerClusterShotGql = {
__typename?: "PlayerClusterShotGQL";
bboxX1: Scalars["Int"]["output"];
bboxX2: Scalars["Int"]["output"];
bboxY1: Scalars["Int"]["output"];
bboxY2: Scalars["Int"]["output"];
confidence: Scalars["Float"]["output"];
cropUrl?: Maybe<Scalars["String"]["output"]>;
fullFrameUrl?: Maybe<Scalars["String"]["output"]>;
isConfirmed: Scalars["Boolean"]["output"];
shotId: Scalars["Int"]["output"];
};
export enum PocketEnum { export enum PocketEnum {
Corner = "CORNER", Corner = "CORNER",
Side = "SIDE", Side = "SIDE",
@@ -2783,6 +2828,7 @@ export type Query = {
notifications: NotificationConnection; notifications: NotificationConnection;
ruleSets: Array<RuleSet>; ruleSets: Array<RuleSet>;
unreadNotificationCount: Scalars["Int"]["output"]; unreadNotificationCount: Scalars["Int"]["output"];
videoPlayerClusters: Array<PlayerClusterGql>;
waitFor: Scalars["Float"]["output"]; waitFor: Scalars["Float"]["output"];
}; };
@@ -2949,6 +2995,10 @@ export type QueryNotificationsArgs = {
offset?: Scalars["Int"]["input"]; offset?: Scalars["Int"]["input"];
}; };
export type QueryVideoPlayerClustersArgs = {
videoId: Scalars["Int"]["input"];
};
export type QueryWaitForArgs = { export type QueryWaitForArgs = {
duration: Scalars["Float"]["input"]; duration: Scalars["Float"]["input"];
}; };
@@ -3166,6 +3216,11 @@ export type ShotGql = {
videoId: Scalars["Int"]["output"]; videoId: Scalars["Int"]["output"];
}; };
export type ShotMoveInput = {
newClusterId: Scalars["Int"]["input"];
shotId: Scalars["Int"]["input"];
};
export type ShotsOrderingComponent = export type ShotsOrderingComponent =
| { | {
difficulty: FloatOrdering; difficulty: FloatOrdering;
@@ -3264,6 +3319,7 @@ export type StripeProductGql = {
export type StripeSubscriptionOptionsGql = { export type StripeSubscriptionOptionsGql = {
__typename?: "StripeSubscriptionOptionsGQL"; __typename?: "StripeSubscriptionOptionsGQL";
products: Array<StripeProductGql>; products: Array<StripeProductGql>;
trialPeriodDays?: Maybe<Scalars["Int"]["output"]>;
}; };
export enum StripeSubscriptionStatusEnum { export enum StripeSubscriptionStatusEnum {
@@ -4097,15 +4153,11 @@ export type GetFeedQuery = {
id: number; id: number;
name?: string | null; name?: string | null;
screenshotUri?: string | null; screenshotUri?: string | null;
totalShotsMade: number;
totalShots: number; totalShots: number;
makePercentage: number; makePercentage: number;
averageTimeBetweenShots?: number | null; averageTimeBetweenShots?: number | null;
averageDifficulty?: number | null; averageDifficulty?: number | null;
createdAt?: any | null;
updatedAt?: any | null;
startTime?: any | null; startTime?: any | null;
endTime?: any | null;
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
@@ -4120,26 +4172,13 @@ export type GetFeedQuery = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
isCompleted: boolean;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ tags: Array<{ __typename?: "VideoTag"; name: string }>;
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
status: ProcessingStatusEnum; status: ProcessingStatusEnum;
errors: Array<{
__typename?: "VideoProcessingErrorGQL";
message: string;
}>;
statuses: Array<{
__typename?: "VideoProcessingStatusGQL";
status: ProcessingStatusEnum;
}>;
} | null; } | null;
reactions: Array<{ reactions: Array<{
__typename?: "ReactionGQL"; __typename?: "ReactionGQL";
@@ -4199,15 +4238,11 @@ export type VideoCardFieldsFragment = {
id: number; id: number;
name?: string | null; name?: string | null;
screenshotUri?: string | null; screenshotUri?: string | null;
totalShotsMade: number;
totalShots: number; totalShots: number;
makePercentage: number; makePercentage: number;
averageTimeBetweenShots?: number | null; averageTimeBetweenShots?: number | null;
averageDifficulty?: number | null; averageDifficulty?: number | null;
createdAt?: any | null;
updatedAt?: any | null;
startTime?: any | null; startTime?: any | null;
endTime?: any | null;
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
@@ -4222,23 +4257,13 @@ export type VideoCardFieldsFragment = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
isCompleted: boolean;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ tags: Array<{ __typename?: "VideoTag"; name: string }>;
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
status: ProcessingStatusEnum; status: ProcessingStatusEnum;
errors: Array<{ __typename?: "VideoProcessingErrorGQL"; message: string }>;
statuses: Array<{
__typename?: "VideoProcessingStatusGQL";
status: ProcessingStatusEnum;
}>;
} | null; } | null;
reactions: Array<{ reactions: Array<{
__typename?: "ReactionGQL"; __typename?: "ReactionGQL";
@@ -4312,15 +4337,11 @@ export type GetVideoFeedQuery = {
id: number; id: number;
name?: string | null; name?: string | null;
screenshotUri?: string | null; screenshotUri?: string | null;
totalShotsMade: number;
totalShots: number; totalShots: number;
makePercentage: number; makePercentage: number;
averageTimeBetweenShots?: number | null; averageTimeBetweenShots?: number | null;
averageDifficulty?: number | null; averageDifficulty?: number | null;
createdAt?: any | null;
updatedAt?: any | null;
startTime?: any | null; startTime?: any | null;
endTime?: any | null;
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
@@ -4335,26 +4356,13 @@ export type GetVideoFeedQuery = {
__typename?: "UploadStreamGQL"; __typename?: "UploadStreamGQL";
id: string; id: string;
lastIntendedSegmentBound?: number | null; lastIntendedSegmentBound?: number | null;
isCompleted: boolean;
streamSegmentType: StreamSegmentTypeEnum; streamSegmentType: StreamSegmentTypeEnum;
} | null; } | null;
tags: Array<{ tags: Array<{ __typename?: "VideoTag"; name: string }>;
__typename?: "VideoTag";
name: string;
tagClasses: Array<{ __typename?: "VideoTagClass"; name: string }>;
}>;
currentProcessing?: { currentProcessing?: {
__typename?: "VideoProcessingGQL"; __typename?: "VideoProcessingGQL";
id: number; id: number;
status: ProcessingStatusEnum; status: ProcessingStatusEnum;
errors: Array<{
__typename?: "VideoProcessingErrorGQL";
message: string;
}>;
statuses: Array<{
__typename?: "VideoProcessingStatusGQL";
status: ProcessingStatusEnum;
}>;
} | null; } | null;
reactions: Array<{ reactions: Array<{
__typename?: "ReactionGQL"; __typename?: "ReactionGQL";
@@ -4749,6 +4757,18 @@ export type CreateSubscriptionMutation = {
}; };
}; };
export type CreateCustomerPortalSessionMutationVariables = Exact<{
[key: string]: never;
}>;
export type CreateCustomerPortalSessionMutation = {
__typename?: "Mutation";
createCustomerPortalSession: {
__typename?: "CreateCustomerPortalSessionResultGQL";
portalUrl: string;
};
};
export type GetAvailableSubscriptionOptionsQueryVariables = Exact<{ export type GetAvailableSubscriptionOptionsQueryVariables = Exact<{
[key: string]: never; [key: string]: never;
}>; }>;
@@ -4757,6 +4777,7 @@ export type GetAvailableSubscriptionOptionsQuery = {
__typename?: "Query"; __typename?: "Query";
getAvailableSubscriptionOptions: { getAvailableSubscriptionOptions: {
__typename?: "StripeSubscriptionOptionsGQL"; __typename?: "StripeSubscriptionOptionsGQL";
trialPeriodDays?: number | null;
products: Array<{ products: Array<{
__typename?: "StripeProductGQL"; __typename?: "StripeProductGQL";
id: string; id: string;
@@ -6519,41 +6540,26 @@ export const VideoCardFieldsFragmentDoc = gql`
} }
name name
screenshotUri screenshotUri
totalShotsMade
totalShots totalShots
makePercentage makePercentage
averageTimeBetweenShots averageTimeBetweenShots
averageDifficulty averageDifficulty
createdAt
updatedAt
startTime startTime
endTime
private private
elapsedTime elapsedTime
screenshotUri
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
isCompleted
streamSegmentType streamSegmentType
} }
tableSize tableSize
pocketSize pocketSize
tags { tags {
tagClasses {
name
}
name name
} }
currentProcessing { currentProcessing {
id id
errors {
message
}
status status
statuses {
status
}
} }
reactions { reactions {
videoId videoId
@@ -9652,9 +9658,60 @@ export type CreateSubscriptionMutationOptions = Apollo.BaseMutationOptions<
CreateSubscriptionMutation, CreateSubscriptionMutation,
CreateSubscriptionMutationVariables CreateSubscriptionMutationVariables
>; >;
export const CreateCustomerPortalSessionDocument = gql`
mutation CreateCustomerPortalSession {
createCustomerPortalSession {
portalUrl
}
}
`;
export type CreateCustomerPortalSessionMutationFn = Apollo.MutationFunction<
CreateCustomerPortalSessionMutation,
CreateCustomerPortalSessionMutationVariables
>;
/**
* __useCreateCustomerPortalSessionMutation__
*
* To run a mutation, you first call `useCreateCustomerPortalSessionMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateCustomerPortalSessionMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createCustomerPortalSessionMutation, { data, loading, error }] = useCreateCustomerPortalSessionMutation({
* variables: {
* },
* });
*/
export function useCreateCustomerPortalSessionMutation(
baseOptions?: Apollo.MutationHookOptions<
CreateCustomerPortalSessionMutation,
CreateCustomerPortalSessionMutationVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<
CreateCustomerPortalSessionMutation,
CreateCustomerPortalSessionMutationVariables
>(CreateCustomerPortalSessionDocument, options);
}
export type CreateCustomerPortalSessionMutationHookResult = ReturnType<
typeof useCreateCustomerPortalSessionMutation
>;
export type CreateCustomerPortalSessionMutationResult =
Apollo.MutationResult<CreateCustomerPortalSessionMutation>;
export type CreateCustomerPortalSessionMutationOptions =
Apollo.BaseMutationOptions<
CreateCustomerPortalSessionMutation,
CreateCustomerPortalSessionMutationVariables
>;
export const GetAvailableSubscriptionOptionsDocument = gql` export const GetAvailableSubscriptionOptionsDocument = gql`
query GetAvailableSubscriptionOptions { query GetAvailableSubscriptionOptions {
getAvailableSubscriptionOptions { getAvailableSubscriptionOptions {
trialPeriodDays
products { products {
id id
name name

View File

@@ -31,41 +31,26 @@ fragment VideoCardFields on VideoGQL {
} }
name name
screenshotUri screenshotUri
totalShotsMade
totalShots totalShots
makePercentage makePercentage
averageTimeBetweenShots averageTimeBetweenShots
averageDifficulty averageDifficulty
createdAt
updatedAt
startTime startTime
endTime
private private
elapsedTime elapsedTime
screenshotUri
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
isCompleted
streamSegmentType streamSegmentType
} }
tableSize tableSize
pocketSize pocketSize
tags { tags {
tagClasses {
name
}
name name
} }
currentProcessing { currentProcessing {
id id
errors {
message
}
status status
statuses {
status
}
} }
reactions { reactions {
videoId videoId

View File

@@ -20,8 +20,15 @@ mutation CreateSubscription($priceId: String!) {
} }
} }
mutation CreateCustomerPortalSession {
createCustomerPortalSession {
portalUrl
}
}
query GetAvailableSubscriptionOptions { query GetAvailableSubscriptionOptions {
getAvailableSubscriptionOptions { getAvailableSubscriptionOptions {
trialPeriodDays
products { products {
id id
name name

View File

@@ -28,7 +28,7 @@ type Query {
getLongestRunsLeaderboard( getLongestRunsLeaderboard(
interval: TimeInterval = null interval: TimeInterval = null
when: DateTime = null when: DateTime = null
limit: Int! = 100 limit: Int! = 50
requiredTags: [String!] = null requiredTags: [String!] = null
): RunLeaderboardGQL! ): RunLeaderboardGQL!
getMakesLeaderboard( getMakesLeaderboard(
@@ -49,6 +49,7 @@ type Query {
limit: Int! = 500 limit: Int! = 500
countRespectsLimit: Boolean! = false countRespectsLimit: Boolean! = false
): GetRunsResult! ): GetRunsResult!
videoPlayerClusters(videoId: Int!): [PlayerClusterGQL!]!
getShotAnnotationTypes(errorTypes: Boolean = false): [ShotAnnotationTypeGQL!]! getShotAnnotationTypes(errorTypes: Boolean = false): [ShotAnnotationTypeGQL!]!
getTableState( getTableState(
b64Image: String! b64Image: String!
@@ -860,6 +861,27 @@ input DatetimeOrdering {
startingAt: DateTime = null startingAt: DateTime = null
} }
type PlayerClusterGQL {
videoId: Int!
clusterId: Int!
nShots: Int!
userId: Int
confirmed: Boolean!
shots: [PlayerClusterShotGQL!]!
}
type PlayerClusterShotGQL {
shotId: Int!
bboxX1: Int!
bboxY1: Int!
bboxX2: Int!
bboxY2: Int!
confidence: Float!
isConfirmed: Boolean!
cropUrl: String
fullFrameUrl: String
}
type TableStateGQL { type TableStateGQL {
identifierToPosition: [[Float!]!]! identifierToPosition: [[Float!]!]!
homography: HomographyInfoGQL homography: HomographyInfoGQL
@@ -940,6 +962,7 @@ type UserRelationship {
type StripeSubscriptionOptionsGQL { type StripeSubscriptionOptionsGQL {
products: [StripeProductGQL!]! products: [StripeProductGQL!]!
trialPeriodDays: Int
} }
type StripeProductGQL { type StripeProductGQL {
@@ -1093,6 +1116,9 @@ type Mutation {
markAllNotificationsAsRead: Boolean! markAllNotificationsAsRead: Boolean!
markNotificationsAsRead(notificationIds: [Int!]!): Boolean! markNotificationsAsRead(notificationIds: [Int!]!): Boolean!
deleteNotification(notificationId: Int!): Boolean! deleteNotification(notificationId: Int!): Boolean!
finalizePlayerAssignments(
input: FinalizePlayerAssignmentsInput!
): [PlayerClusterGQL!]!
addAnnotationToShot( addAnnotationToShot(
shotId: Int! shotId: Int!
annotationName: String! annotationName: String!
@@ -1117,6 +1143,7 @@ type Mutation {
ensureStripeCustomerExists: UserGQL! ensureStripeCustomerExists: UserGQL!
deleteUser: Boolean! deleteUser: Boolean!
createSubscription(priceId: String!): CreateSubscriptionResultGQL! createSubscription(priceId: String!): CreateSubscriptionResultGQL!
createCustomerPortalSession: CreateCustomerPortalSessionResultGQL!
cancelSubscription: UserSubscriptionStatusGQL! cancelSubscription: UserSubscriptionStatusGQL!
grantManualEntitlement( grantManualEntitlement(
userId: Int! userId: Int!
@@ -1163,6 +1190,22 @@ enum ReportReasonEnum {
OTHER OTHER
} }
input FinalizePlayerAssignmentsInput {
videoId: Int!
clusterAssignments: [ClusterAssignmentInput!]! = []
shotMoves: [ShotMoveInput!]! = []
}
input ClusterAssignmentInput {
clusterId: Int!
userId: Int = null
}
input ShotMoveInput {
shotId: Int!
newClusterId: Int!
}
type AddShotAnnotationReturn { type AddShotAnnotationReturn {
value: SuccessfulAddAddShotAnnotationErrors! value: SuccessfulAddAddShotAnnotationErrors!
} }
@@ -1256,6 +1299,10 @@ type CreateSubscriptionResultGQL {
sessionId: String! sessionId: String!
} }
type CreateCustomerPortalSessionResultGQL {
portalUrl: String!
}
enum CancellationReasonEnum { enum CancellationReasonEnum {
DONT_PLAY_ENOUGH DONT_PLAY_ENOUGH
TOO_EXPENSIVE TOO_EXPENSIVE