Compare commits

..

5 Commits

Author SHA1 Message Date
1a95439ed2 Replace GetRecordedStreams/GetLiveStreams with video-first GetShotLabVideos
All checks were successful
Tests / Tests (pull_request) Successful in 44s
Shot Lab's source picker becomes video-first: one query for recent videos
regardless of stream completion (an in-progress recording with no shots
yet still appears), carrying stream recency fields so the client can hint
"actively updating" without gating on it. Operation-only change; schema
is untouched (the stream fields already exist).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 23:42:43 -07:00
5e14cd2201 Merge pull request 'Regenerate schema for leaderboard taxonomy filters' (#300) from dean/leaderboard-taxonomy into master
Reviewed-on: #300
2026-07-21 04:20:57 +00:00
Dean Wenstrand
9ec52d9d94 Regenerate schema for leaderboard taxonomy filters
All checks were successful
Tests / Tests (pull_request) Successful in 11s
Adds the optional taxonomy args to getLongestRunsLeaderboard and
getMakesLeaderboard (gameType, rankedOnly, excludeDrills, and
table/pocket size bounds) generated from the backend resolvers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:19:39 -07:00
4576b25dae Merge pull request 'Regenerate schema with upstream Strawberry' (#299) from codex/strawberry-upgrade into master 2026-07-20 22:08:35 +00:00
6d9cb4126e Merge pull request 'Add per-video HomographyBackendGQL selection to VideoMetadataInput' (#298) from colonelpanic/homography-backend-selection into master 2026-07-18 02:12:18 +00:00
4 changed files with 85 additions and 210 deletions

View File

@@ -3195,14 +3195,28 @@ export type QueryGetLiveTableStateArgs = {
}; };
export type QueryGetLongestRunsLeaderboardArgs = { export type QueryGetLongestRunsLeaderboardArgs = {
excludeDrills?: Scalars["Boolean"]["input"];
gameType?: InputMaybe<Scalars["String"]["input"]>;
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
limit?: Scalars["Int"]["input"]; limit?: Scalars["Int"]["input"];
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
rankedOnly?: Scalars["Boolean"]["input"];
requiredTags?: InputMaybe<Array<Scalars["String"]["input"]>>; requiredTags?: InputMaybe<Array<Scalars["String"]["input"]>>;
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
}; };
export type QueryGetMakesLeaderboardArgs = { export type QueryGetMakesLeaderboardArgs = {
excludeDrills?: Scalars["Boolean"]["input"];
gameType?: InputMaybe<Scalars["String"]["input"]>;
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
pocketSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
pocketSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
rankedOnly?: Scalars["Boolean"]["input"];
tableSizeMax?: InputMaybe<Scalars["Float"]["input"]>;
tableSizeMin?: InputMaybe<Scalars["Float"]["input"]>;
when?: InputMaybe<Scalars["DateTime"]["input"]>; when?: InputMaybe<Scalars["DateTime"]["input"]>;
}; };
@@ -5330,43 +5344,6 @@ export type GetMyDrillRunsQuery = {
}>; }>;
}; };
export type GetLiveStreamsQueryVariables = Exact<{
limit?: Scalars["Int"]["input"];
}>;
export type GetLiveStreamsQuery = {
__typename?: "Query";
getFeedVideos: {
__typename?: "VideoHistoryGQL";
videos: Array<{
__typename?: "VideoGQL";
id: number;
name?: string | null;
startTime?: any | null;
createdAt?: any | null;
screenshotUri?: string | null;
elapsedTime?: number | null;
owner?: {
__typename?: "UserGQL";
id: number;
username: string;
profileImageUri?: string | null;
} | null;
stream?: {
__typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean;
lastSegmentUploadedAt?: any | null;
} | null;
}>;
pageInfo: {
__typename?: "PageInfoGQL";
hasNextPage: boolean;
endCursor?: string | null;
};
};
};
export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{ export type GetVideoMakePercentageIntervalsQueryVariables = Exact<{
videoId: Scalars["ID"]["input"]; videoId: Scalars["ID"]["input"];
intervalDuration: Scalars["Int"]["input"]; intervalDuration: Scalars["Int"]["input"];
@@ -6708,11 +6685,11 @@ export type ReactToVideoMutation = {
reactToVideo: boolean; reactToVideo: boolean;
}; };
export type GetRecordedStreamsQueryVariables = Exact<{ export type GetShotLabVideosQueryVariables = Exact<{
limit?: Scalars["Int"]["input"]; limit?: Scalars["Int"]["input"];
}>; }>;
export type GetRecordedStreamsQuery = { export type GetShotLabVideosQuery = {
__typename?: "Query"; __typename?: "Query";
getFeedVideos: { getFeedVideos: {
__typename?: "VideoHistoryGQL"; __typename?: "VideoHistoryGQL";
@@ -6730,6 +6707,12 @@ export type GetRecordedStreamsQuery = {
username: string; username: string;
profileImageUri?: string | null; profileImageUri?: string | null;
} | null; } | null;
stream?: {
__typename?: "UploadStreamGQL";
id: string;
isCompleted: boolean;
lastSegmentUploadedAt?: any | null;
} | null;
}>; }>;
}; };
}; };
@@ -12134,105 +12117,6 @@ export type GetMyDrillRunsQueryResult = Apollo.QueryResult<
GetMyDrillRunsQuery, GetMyDrillRunsQuery,
GetMyDrillRunsQueryVariables GetMyDrillRunsQueryVariables
>; >;
export const GetLiveStreamsDocument = gql`
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`;
/**
* __useGetLiveStreamsQuery__
*
* To run a query within a React component, call `useGetLiveStreamsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetLiveStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetLiveStreamsQuery({
* variables: {
* limit: // value for 'limit'
* },
* });
*/
export function useGetLiveStreamsQuery(
baseOptions?: Apollo.QueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<GetLiveStreamsQuery, GetLiveStreamsQueryVariables>(
GetLiveStreamsDocument,
options,
);
}
export function useGetLiveStreamsSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>,
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>(GetLiveStreamsDocument, options);
}
export type GetLiveStreamsQueryHookResult = ReturnType<
typeof useGetLiveStreamsQuery
>;
export type GetLiveStreamsLazyQueryHookResult = ReturnType<
typeof useGetLiveStreamsLazyQuery
>;
export type GetLiveStreamsSuspenseQueryHookResult = ReturnType<
typeof useGetLiveStreamsSuspenseQuery
>;
export type GetLiveStreamsQueryResult = Apollo.QueryResult<
GetLiveStreamsQuery,
GetLiveStreamsQueryVariables
>;
export const GetVideoMakePercentageIntervalsDocument = gql` export const GetVideoMakePercentageIntervalsDocument = gql`
query GetVideoMakePercentageIntervals( query GetVideoMakePercentageIntervals(
$videoId: ID! $videoId: ID!
@@ -14531,11 +14415,10 @@ export type ReactToVideoMutationOptions = Apollo.BaseMutationOptions<
ReactToVideoMutation, ReactToVideoMutation,
ReactToVideoMutationVariables ReactToVideoMutationVariables
>; >;
export const GetRecordedStreamsDocument = gql` export const GetShotLabVideosDocument = gql`
query GetRecordedStreams($limit: Int! = 25) { query GetShotLabVideos($limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { allUsers: true }
) { ) {
@@ -14551,75 +14434,80 @@ export const GetRecordedStreamsDocument = gql`
username username
profileImageUri profileImageUri
} }
stream {
id
isCompleted
lastSegmentUploadedAt
}
} }
} }
} }
`; `;
/** /**
* __useGetRecordedStreamsQuery__ * __useGetShotLabVideosQuery__
* *
* To run a query within a React component, call `useGetRecordedStreamsQuery` and pass it any options that fit your needs. * To run a query within a React component, call `useGetShotLabVideosQuery` and pass it any options that fit your needs.
* When your component renders, `useGetRecordedStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties * When your component renders, `useGetShotLabVideosQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI. * you can use to render your UI.
* *
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
* *
* @example * @example
* const { data, loading, error } = useGetRecordedStreamsQuery({ * const { data, loading, error } = useGetShotLabVideosQuery({
* variables: { * variables: {
* limit: // value for 'limit' * limit: // value for 'limit'
* }, * },
* }); * });
*/ */
export function useGetRecordedStreamsQuery( export function useGetShotLabVideosQuery(
baseOptions?: Apollo.QueryHookOptions< baseOptions?: Apollo.QueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery< return Apollo.useQuery<GetShotLabVideosQuery, GetShotLabVideosQueryVariables>(
GetRecordedStreamsQuery, GetShotLabVideosDocument,
GetRecordedStreamsQueryVariables options,
>(GetRecordedStreamsDocument, options); );
} }
export function useGetRecordedStreamsLazyQuery( export function useGetShotLabVideosLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions< baseOptions?: Apollo.LazyQueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery< return Apollo.useLazyQuery<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>(GetRecordedStreamsDocument, options); >(GetShotLabVideosDocument, options);
} }
export function useGetRecordedStreamsSuspenseQuery( export function useGetShotLabVideosSuspenseQuery(
baseOptions?: Apollo.SuspenseQueryHookOptions< baseOptions?: Apollo.SuspenseQueryHookOptions<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>, >,
) { ) {
const options = { ...defaultOptions, ...baseOptions }; const options = { ...defaultOptions, ...baseOptions };
return Apollo.useSuspenseQuery< return Apollo.useSuspenseQuery<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>(GetRecordedStreamsDocument, options); >(GetShotLabVideosDocument, options);
} }
export type GetRecordedStreamsQueryHookResult = ReturnType< export type GetShotLabVideosQueryHookResult = ReturnType<
typeof useGetRecordedStreamsQuery typeof useGetShotLabVideosQuery
>; >;
export type GetRecordedStreamsLazyQueryHookResult = ReturnType< export type GetShotLabVideosLazyQueryHookResult = ReturnType<
typeof useGetRecordedStreamsLazyQuery typeof useGetShotLabVideosLazyQuery
>; >;
export type GetRecordedStreamsSuspenseQueryHookResult = ReturnType< export type GetShotLabVideosSuspenseQueryHookResult = ReturnType<
typeof useGetRecordedStreamsSuspenseQuery typeof useGetShotLabVideosSuspenseQuery
>; >;
export type GetRecordedStreamsQueryResult = Apollo.QueryResult< export type GetShotLabVideosQueryResult = Apollo.QueryResult<
GetRecordedStreamsQuery, GetShotLabVideosQuery,
GetRecordedStreamsQueryVariables GetShotLabVideosQueryVariables
>; >;
export const GetRecordedStreamShotsDocument = gql` export const GetRecordedStreamShotsDocument = gql`
query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) { query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {

View File

@@ -1,34 +0,0 @@
# Lightweight listing of live (in-progress) streams for pickers like the
# Shot Lab "follow a live stream" flow. Selects only what a picker card
# needs; intentionally avoids the heavy VideoCardFields fragment.
query GetLiveStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: false, requireCursorCompletion: false }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
startTime
createdAt
screenshotUri
elapsedTime
owner {
id
username
profileImageUri
}
stream {
id
isCompleted
lastSegmentUploadedAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

View File

@@ -1,8 +1,10 @@
# Lightweight two-step picker data for loading a recorded shot into Shot Lab. # Lightweight two-step picker data for Shot Lab's video-first source: recent
query GetRecordedStreams($limit: Int! = 25) { # videos (completed or still uploading — no completion gate, so an in-progress
# recording with no shots yet still appears), then that video's shots. The
# stream fields let the client hint at "actively updating" without gating.
query GetShotLabVideos($limit: Int! = 25) {
getFeedVideos( getFeedVideos(
limit: $limit limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE includePrivate: MINE
feedInput: { allUsers: true } feedInput: { allUsers: true }
) { ) {
@@ -18,6 +20,11 @@ query GetRecordedStreams($limit: Int! = 25) {
username username
profileImageUri profileImageUri
} }
stream {
id
isCompleted
lastSegmentUploadedAt
}
} }
} }
} }

View File

@@ -1005,6 +1005,13 @@ type Query {
when: DateTime = null when: DateTime = null
limit: Int! = 50 limit: Int! = 50
requiredTags: [String!] = null requiredTags: [String!] = null
gameType: String = null
rankedOnly: Boolean! = false
excludeDrills: Boolean! = true
tableSizeMin: Float = null
tableSizeMax: Float = null
pocketSizeMin: Float = null
pocketSizeMax: Float = null
): RunLeaderboardGQL! ): RunLeaderboardGQL!
getDrillRunLeaderboard( getDrillRunLeaderboard(
drillTag: String! drillTag: String!
@@ -1019,6 +1026,13 @@ type Query {
getMakesLeaderboard( getMakesLeaderboard(
interval: TimeInterval = null interval: TimeInterval = null
when: DateTime = null when: DateTime = null
gameType: String = null
rankedOnly: Boolean! = false
excludeDrills: Boolean! = true
tableSizeMin: Float = null
tableSizeMax: Float = null
pocketSizeMin: Float = null
pocketSizeMax: Float = null
): CountLeaderboardGQL! ): CountLeaderboardGQL!
getMedals(scope: MedalScope!, userId: Int = null): RequestedMedalsGQL! getMedals(scope: MedalScope!, userId: Int = null): RequestedMedalsGQL!
notifications( notifications(