Compare commits

..

8 Commits

Author SHA1 Message Date
5cd2dabeaa Generate Session Coach feedback operations 2026-07-29 17:26:28 -07:00
b034a2f1b8 Generate Session Coach feedback schema 2026-07-29 17:20:25 -07:00
d7b0b21430 Merge pull request 'Use BigInt for video export file sizes' (#310) from agent/video-export-bigint into master
Reviewed-on: #310
2026-07-27 19:35:17 +00:00
f173466b2f Merge pull request 'Add createShotShareLink for short share links' (#311) from dean/short-share-links-gql into master
Reviewed-on: #311
2026-07-27 19:35:11 +00:00
Dean Wenstrand
df69d154a5 Merge master into short-share-links-gql
All checks were successful
Tests / Tests (pull_request) Successful in 34s
gql master added Shot Lab video feed scopes and pagination
(operations-only: recorded_shots.gql + codegen output) while this branch
added createShotShareLink. The two touch disjoint parts of the generated
index.tsx, so the merge is textual only.

Verified rather than trusted: re-ran graphql-codegen after the merge and
src/index.tsx came back byte-identical (same md5), so the merged
generated file is exactly what codegen produces. Reverted prettier's
schema.gql reformat, which CI's own prettier undoes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 15:34:22 -04:00
0bceb5d300 Merge pull request 'Add Shot Lab video feed scopes and pagination' (#312) from t3code/shot-lab-video-sources into master
Reviewed-on: #312
2026-07-26 09:31:20 +00:00
179e8ed4e1 Add createShotShareLink for short share links
All checks were successful
Tests / Tests (pull_request) Successful in 11s
index.tsx is graphql-codegen output. schema.gql carries only the new
type, input and mutation field, deliberately left in the file's existing
formatting: package.json pins prettier as ^3.2.5, so a local install and
CI's yarn install can resolve different 3.x versions that disagree about
GraphQL union indentation. Committing a locally-reformatted schema.gql
makes CI's 'graphql-codegen causes no changes' check fail when its
prettier reformats it back.

The schema is verified semantically identical to the backend export via
lexicographic_sort_schema.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 15:02:17 -07:00
3e6dabe12a Use BigInt for video export file size
All checks were successful
Tests / Tests (pull_request) Successful in 6m3s
2026-07-24 20:09:19 -07:00
4 changed files with 279 additions and 19 deletions

View File

@@ -315,6 +315,11 @@ export type CreatePoolHallInput = {
timezone?: InputMaybe<Scalars["String"]["input"]>;
};
export type CreateShotShareLinkInput = {
paddingSeconds?: InputMaybe<Scalars["Float"]["input"]>;
shotIds: Array<Scalars["Int"]["input"]>;
};
export type CreateSubscriptionResultGql = {
__typename?: "CreateSubscriptionResultGQL";
checkoutUrl: Scalars["String"]["output"];
@@ -2530,6 +2535,7 @@ export type Mutation = {
createPoolHall: PoolHall;
createPoolHallCamera: PoolHallCameraStreamCredentials;
createRuleSet: RuleSet;
createShotShareLink: ShareLinkGql;
createSubscription: CreateSubscriptionResultGql;
createUploadStream: CreateUploadStreamReturn;
deleteComment: Scalars["Boolean"]["output"];
@@ -2573,6 +2579,7 @@ export type Mutation = {
startChallenge: ChallengeEntry;
submitCancellationFeedback: Scalars["Boolean"]["output"];
submitChallengeEntry: ChallengeEntry;
submitSessionCoachFeedback: SessionCoachFeedbackGql;
syncAppleSubscription: SyncAppleSubscriptionResultGql;
undismissChallenge: Scalars["Boolean"]["output"];
unfollowUser: UserGql;
@@ -2644,6 +2651,10 @@ export type MutationCreateRuleSetArgs = {
name: Scalars["String"]["input"];
};
export type MutationCreateShotShareLinkArgs = {
input: CreateShotShareLinkInput;
};
export type MutationCreateSubscriptionArgs = {
priceId: Scalars["String"]["input"];
};
@@ -2830,6 +2841,12 @@ export type MutationSubmitChallengeEntryArgs = {
videoId: Scalars["ID"]["input"];
};
export type MutationSubmitSessionCoachFeedbackArgs = {
generationId: Scalars["ID"]["input"];
response: SessionCoachFeedbackResponseEnum;
videoId: Scalars["Int"]["input"];
};
export type MutationSyncAppleSubscriptionArgs = {
input: SyncAppleSubscriptionInputGql;
};
@@ -3675,6 +3692,19 @@ export type SessionCoachEvidenceGql = {
score: Scalars["Float"]["output"];
};
export type SessionCoachFeedbackGql = {
__typename?: "SessionCoachFeedbackGQL";
response: SessionCoachFeedbackResponseEnum;
updatedAt: Scalars["DateTime"]["output"];
};
export enum SessionCoachFeedbackResponseEnum {
AlreadyWorkingOnThis = "ALREADY_WORKING_ON_THIS",
Helpful = "HELPFUL",
NotEnoughEvidence = "NOT_ENOUGH_EVIDENCE",
WrongFocus = "WRONG_FOCUS",
}
export type SessionCoachGql = {
__typename?: "SessionCoachGQL";
agentGeneration?: Maybe<SessionCoachGenerationGql>;
@@ -3727,6 +3757,7 @@ export type SessionCoachGenerationGql = {
createdAt: Scalars["DateTime"]["output"];
decision?: Maybe<SessionCoachDecisionGql>;
diagnostics?: Maybe<SessionCoachGenerationDiagnosticsGql>;
feedback?: Maybe<SessionCoachFeedbackGql>;
id: Scalars["ID"]["output"];
state: SessionCoachGenerationStateEnum;
};
@@ -3750,6 +3781,12 @@ export enum SessionCoachStateEnum {
Ready = "READY",
}
export type ShareLinkGql = {
__typename?: "ShareLinkGQL";
slug: Scalars["String"]["output"];
url: Scalars["String"]["output"];
};
export type ShotAnnotationGql = {
__typename?: "ShotAnnotationGQL";
createdAt?: Maybe<Scalars["DateTime"]["output"]>;
@@ -4302,7 +4339,7 @@ export type VideoExportJobGql = {
createdAt?: Maybe<Scalars["DateTime"]["output"]>;
downloadUrl?: Maybe<Scalars["String"]["output"]>;
expiresAt?: Maybe<Scalars["DateTime"]["output"]>;
fileSizeBytes?: Maybe<Scalars["Int"]["output"]>;
fileSizeBytes?: Maybe<Scalars["BigInt"]["output"]>;
id: Scalars["Int"]["output"];
mode: VideoExportModeEnum;
runId?: Maybe<Scalars["Int"]["output"]>;
@@ -7188,6 +7225,11 @@ export type GetSessionCoachQuery = {
abstentionReason?: string | null;
synthesisRationale?: string | null;
} | null;
feedback?: {
__typename?: "SessionCoachFeedbackGQL";
response: SessionCoachFeedbackResponseEnum;
updatedAt: any;
} | null;
} | null;
};
};
@@ -7245,10 +7287,30 @@ export type RequestSessionCoachGenerationMutation = {
abstentionReason?: string | null;
synthesisRationale?: string | null;
} | null;
feedback?: {
__typename?: "SessionCoachFeedbackGQL";
response: SessionCoachFeedbackResponseEnum;
updatedAt: any;
} | null;
} | null;
};
};
export type SubmitSessionCoachFeedbackMutationVariables = Exact<{
videoId: Scalars["Int"]["input"];
generationId: Scalars["ID"]["input"];
response: SessionCoachFeedbackResponseEnum;
}>;
export type SubmitSessionCoachFeedbackMutation = {
__typename?: "Mutation";
submitSessionCoachFeedback: {
__typename?: "SessionCoachFeedbackGQL";
response: SessionCoachFeedbackResponseEnum;
updatedAt: any;
};
};
export type SessionCoachCandidateFieldsFragment = {
__typename?: "SessionCoachCandidateGQL";
id: string;
@@ -7326,6 +7388,25 @@ export type SessionCoachGenerationFieldsFragment = {
abstentionReason?: string | null;
synthesisRationale?: string | null;
} | null;
feedback?: {
__typename?: "SessionCoachFeedbackGQL";
response: SessionCoachFeedbackResponseEnum;
updatedAt: any;
} | null;
};
export type CreateShotShareLinkMutationVariables = Exact<{
shotIds: Array<Scalars["Int"]["input"]> | Scalars["Int"]["input"];
paddingSeconds?: InputMaybe<Scalars["Float"]["input"]>;
}>;
export type CreateShotShareLinkMutation = {
__typename?: "Mutation";
createShotShareLink: {
__typename?: "ShareLinkGQL";
slug: string;
url: string;
};
};
export type PlayerSummaryFieldsFragment = {
@@ -9251,7 +9332,7 @@ export type VideoExportJobFieldsFragment = {
shotIds?: Array<number> | null;
runId?: number | null;
downloadUrl?: string | null;
fileSizeBytes?: number | null;
fileSizeBytes?: any | null;
expiresAt?: any | null;
createdAt?: any | null;
};
@@ -9273,7 +9354,7 @@ export type RequestVideoExportMutation = {
shotIds?: Array<number> | null;
runId?: number | null;
downloadUrl?: string | null;
fileSizeBytes?: number | null;
fileSizeBytes?: any | null;
expiresAt?: any | null;
createdAt?: any | null;
};
@@ -9305,7 +9386,7 @@ export type VideoExportJobQuery = {
shotIds?: Array<number> | null;
runId?: number | null;
downloadUrl?: string | null;
fileSizeBytes?: number | null;
fileSizeBytes?: any | null;
expiresAt?: any | null;
createdAt?: any | null;
} | null;
@@ -9329,7 +9410,7 @@ export type MyVideoExportsQuery = {
shotIds?: Array<number> | null;
runId?: number | null;
downloadUrl?: string | null;
fileSizeBytes?: number | null;
fileSizeBytes?: any | null;
expiresAt?: any | null;
createdAt?: any | null;
}>;
@@ -9919,6 +10000,10 @@ export const SessionCoachGenerationFieldsFragmentDoc = gql`
abstentionReason
synthesisRationale
}
feedback {
response
updatedAt
}
}
`;
export const PlayerClusterShotFieldsFragmentDoc = gql`
@@ -15707,6 +15792,125 @@ export type RequestSessionCoachGenerationMutationOptions =
RequestSessionCoachGenerationMutation,
RequestSessionCoachGenerationMutationVariables
>;
export const SubmitSessionCoachFeedbackDocument = gql`
mutation SubmitSessionCoachFeedback(
$videoId: Int!
$generationId: ID!
$response: SessionCoachFeedbackResponseEnum!
) {
submitSessionCoachFeedback(
videoId: $videoId
generationId: $generationId
response: $response
) {
response
updatedAt
}
}
`;
export type SubmitSessionCoachFeedbackMutationFn = Apollo.MutationFunction<
SubmitSessionCoachFeedbackMutation,
SubmitSessionCoachFeedbackMutationVariables
>;
/**
* __useSubmitSessionCoachFeedbackMutation__
*
* To run a mutation, you first call `useSubmitSessionCoachFeedbackMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useSubmitSessionCoachFeedbackMutation` 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 [submitSessionCoachFeedbackMutation, { data, loading, error }] = useSubmitSessionCoachFeedbackMutation({
* variables: {
* videoId: // value for 'videoId'
* generationId: // value for 'generationId'
* response: // value for 'response'
* },
* });
*/
export function useSubmitSessionCoachFeedbackMutation(
baseOptions?: Apollo.MutationHookOptions<
SubmitSessionCoachFeedbackMutation,
SubmitSessionCoachFeedbackMutationVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<
SubmitSessionCoachFeedbackMutation,
SubmitSessionCoachFeedbackMutationVariables
>(SubmitSessionCoachFeedbackDocument, options);
}
export type SubmitSessionCoachFeedbackMutationHookResult = ReturnType<
typeof useSubmitSessionCoachFeedbackMutation
>;
export type SubmitSessionCoachFeedbackMutationResult =
Apollo.MutationResult<SubmitSessionCoachFeedbackMutation>;
export type SubmitSessionCoachFeedbackMutationOptions =
Apollo.BaseMutationOptions<
SubmitSessionCoachFeedbackMutation,
SubmitSessionCoachFeedbackMutationVariables
>;
export const CreateShotShareLinkDocument = gql`
mutation CreateShotShareLink(
$shotIds: [Int!]!
$paddingSeconds: Float = null
) {
createShotShareLink(
input: { shotIds: $shotIds, paddingSeconds: $paddingSeconds }
) {
slug
url
}
}
`;
export type CreateShotShareLinkMutationFn = Apollo.MutationFunction<
CreateShotShareLinkMutation,
CreateShotShareLinkMutationVariables
>;
/**
* __useCreateShotShareLinkMutation__
*
* To run a mutation, you first call `useCreateShotShareLinkMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateShotShareLinkMutation` 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 [createShotShareLinkMutation, { data, loading, error }] = useCreateShotShareLinkMutation({
* variables: {
* shotIds: // value for 'shotIds'
* paddingSeconds: // value for 'paddingSeconds'
* },
* });
*/
export function useCreateShotShareLinkMutation(
baseOptions?: Apollo.MutationHookOptions<
CreateShotShareLinkMutation,
CreateShotShareLinkMutationVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useMutation<
CreateShotShareLinkMutation,
CreateShotShareLinkMutationVariables
>(CreateShotShareLinkDocument, options);
}
export type CreateShotShareLinkMutationHookResult = ReturnType<
typeof useCreateShotShareLinkMutation
>;
export type CreateShotShareLinkMutationResult =
Apollo.MutationResult<CreateShotShareLinkMutation>;
export type CreateShotShareLinkMutationOptions = Apollo.BaseMutationOptions<
CreateShotShareLinkMutation,
CreateShotShareLinkMutationVariables
>;
export const VideoPlayerClustersDocument = gql`
query VideoPlayerClusters($videoId: Int!) {
videoPlayerClusters(videoId: $videoId) {

View File

@@ -45,6 +45,21 @@ mutation RequestSessionCoachGeneration($videoId: Int!) {
}
}
mutation SubmitSessionCoachFeedback(
$videoId: Int!
$generationId: ID!
$response: SessionCoachFeedbackResponseEnum!
) {
submitSessionCoachFeedback(
videoId: $videoId
generationId: $generationId
response: $response
) {
response
updatedAt
}
}
fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
id
rank
@@ -117,4 +132,8 @@ fragment SessionCoachGenerationFields on SessionCoachGenerationGQL {
abstentionReason
synthesisRationale
}
feedback {
response
updatedAt
}
}

View File

@@ -0,0 +1,8 @@
mutation CreateShotShareLink($shotIds: [Int!]!, $paddingSeconds: Float = null) {
createShotShareLink(
input: { shotIds: $shotIds, paddingSeconds: $paddingSeconds }
) {
slug
url
}
}

View File

@@ -259,6 +259,11 @@ input CreatePoolHallInput {
timezone: String = null
}
input CreateShotShareLinkInput {
shotIds: [Int!]!
paddingSeconds: Float = null
}
type CreateSubscriptionResultGQL {
checkoutUrl: String!
sessionId: String!
@@ -531,19 +536,6 @@ type GetUploadLinksReturn {
stream: UploadStreamGQL
}
type SegmentUploadLink {
segmentIndex: Int!
uploadUrl: String!
headers: [Header]!
}
type UploadLinkBatch {
links: [SegmentUploadLink!]!
alreadyUploaded: [Int!]!
}
union UploadLinkBatchGetUploadLinkErrors = UploadLinkBatch | GetUploadLinkErrors
type HLSPlaylistGQL {
videoId: Int!
m3u8Text: String!
@@ -719,6 +711,7 @@ type Mutation {
cancelCameraClaimSession(claimSessionId: ID!): CameraClaimSession!
endCameraLease(leaseId: ID!): CameraLease!
extendCameraLease(leaseId: ID!, additionalMinutes: Int! = 60): CameraLease!
createShotShareLink(input: CreateShotShareLinkInput!): ShareLinkGQL!
finalizePlayerAssignments(
input: FinalizePlayerAssignmentsInput!
): [PlayerClusterGQL!]!
@@ -735,6 +728,11 @@ type Mutation {
shotId: Int!
fieldsToEdit: EditableShotFieldInputGQL!
): EditShotReturn!
submitSessionCoachFeedback(
videoId: Int!
generationId: ID!
response: SessionCoachFeedbackResponseEnum!
): SessionCoachFeedbackGQL!
requestSessionCoachGeneration(videoId: Int!): SessionCoachGQL!
getProfileImageUploadLink(
fileExt: String = ".png"
@@ -1308,6 +1306,12 @@ type SegmentAlreadyUploadedErr {
segmentId: Int!
}
type SegmentUploadLink {
segmentIndex: Int!
uploadUrl: String!
headers: [Header]!
}
type SerializedShotPathsGQL {
b64EncodedBuffer: String
}
@@ -1388,6 +1392,18 @@ type SessionCoachEvidenceGQL {
baselineMakePercentage: Float
}
type SessionCoachFeedbackGQL {
response: SessionCoachFeedbackResponseEnum!
updatedAt: DateTime!
}
enum SessionCoachFeedbackResponseEnum {
HELPFUL
WRONG_FOCUS
ALREADY_WORKING_ON_THIS
NOT_ENOUGH_EVIDENCE
}
type SessionCoachGQL {
videoId: Int!
processingId: Int
@@ -1439,6 +1455,7 @@ type SessionCoachGenerationGQL {
completedAt: DateTime
decision: SessionCoachDecisionGQL
diagnostics: SessionCoachGenerationDiagnosticsGQL
feedback: SessionCoachFeedbackGQL
}
enum SessionCoachGenerationStateEnum {
@@ -1460,6 +1477,11 @@ enum SessionCoachStateEnum {
FAILED
}
type ShareLinkGQL {
slug: String!
url: String!
}
type ShotAnnotationGQL {
shotId: Int!
type: ShotAnnotationTypeGQL!
@@ -1794,6 +1816,13 @@ type UploadLink {
headers: [Header]!
}
type UploadLinkBatch {
links: [SegmentUploadLink!]!
alreadyUploaded: [Int!]!
}
union UploadLinkBatchGetUploadLinkErrors = UploadLinkBatch | GetUploadLinkErrors
union UploadLinkGetProfileUploadLinkErrors =
UploadLink
| GetProfileUploadLinkErrors
@@ -1923,7 +1952,7 @@ type VideoExportJobGQL {
shotIds: [Int!]
runId: Int
downloadUrl: String
fileSizeBytes: Int
fileSizeBytes: BigInt
expiresAt: DateTime
createdAt: DateTime
}