Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Performance] Add Apollo retry and split myOrg calls for paginated queries (#184)

authored by

Juan Mrad and committed by
GitHub
9e09b29f b651709a

+223 -97
+166 -64
client/src/graphql/generated.ts
··· 10140 10140 | GQLManualReviewDecisionComponentFieldsTransformJobAndRecreateInQueueDecisionComponentFragment 10141 10141 | GQLManualReviewDecisionComponentFieldsUserOrRelatedActionDecisionComponentFragment; 10142 10142 10143 + export type GQLOrgLookupDataQueryVariables = Exact<{ [key: string]: never }>; 10144 + 10145 + export type GQLOrgLookupDataQuery = { 10146 + readonly __typename: 'Query'; 10147 + readonly myOrg?: { 10148 + readonly __typename: 'Org'; 10149 + readonly id: string; 10150 + readonly actions: ReadonlyArray< 10151 + | { 10152 + readonly __typename: 'CustomAction'; 10153 + readonly id: string; 10154 + readonly name: string; 10155 + } 10156 + | { 10157 + readonly __typename: 'EnqueueAuthorToMrtAction'; 10158 + readonly id: string; 10159 + readonly name: string; 10160 + } 10161 + | { 10162 + readonly __typename: 'EnqueueToMrtAction'; 10163 + readonly id: string; 10164 + readonly name: string; 10165 + } 10166 + | { 10167 + readonly __typename: 'EnqueueToNcmecAction'; 10168 + readonly id: string; 10169 + readonly name: string; 10170 + } 10171 + >; 10172 + readonly policies: ReadonlyArray<{ 10173 + readonly __typename: 'Policy'; 10174 + readonly id: string; 10175 + readonly name: string; 10176 + }>; 10177 + readonly users: ReadonlyArray<{ 10178 + readonly __typename: 'User'; 10179 + readonly id: string; 10180 + readonly firstName: string; 10181 + readonly lastName: string; 10182 + }>; 10183 + readonly mrtQueues: ReadonlyArray<{ 10184 + readonly __typename: 'ManualReviewQueue'; 10185 + readonly id: string; 10186 + readonly name: string; 10187 + }>; 10188 + } | null; 10189 + }; 10190 + 10143 10191 export type GQLGetRecentDecisionsQueryVariables = Exact<{ 10144 10192 input: GQLRecentDecisionsInput; 10145 10193 }>; ··· 10249 10297 } 10250 10298 >; 10251 10299 }>; 10252 - readonly myOrg?: { 10253 - readonly __typename: 'Org'; 10254 - readonly id: string; 10255 - readonly actions: ReadonlyArray< 10256 - | { 10257 - readonly __typename: 'CustomAction'; 10258 - readonly id: string; 10259 - readonly name: string; 10260 - } 10261 - | { 10262 - readonly __typename: 'EnqueueAuthorToMrtAction'; 10263 - readonly id: string; 10264 - readonly name: string; 10265 - } 10266 - | { 10267 - readonly __typename: 'EnqueueToMrtAction'; 10268 - readonly id: string; 10269 - readonly name: string; 10270 - } 10271 - | { 10272 - readonly __typename: 'EnqueueToNcmecAction'; 10273 - readonly id: string; 10274 - readonly name: string; 10275 - } 10276 - >; 10277 - readonly policies: ReadonlyArray<{ 10278 - readonly __typename: 'Policy'; 10279 - readonly id: string; 10280 - readonly name: string; 10281 - }>; 10282 - readonly users: ReadonlyArray<{ 10283 - readonly __typename: 'User'; 10284 - readonly id: string; 10285 - readonly firstName: string; 10286 - readonly lastName: string; 10287 - }>; 10288 - readonly mrtQueues: ReadonlyArray<{ 10289 - readonly __typename: 'ManualReviewQueue'; 10290 - readonly id: string; 10291 - readonly name: string; 10292 - }>; 10293 - } | null; 10294 10300 }; 10295 10301 10296 10302 export type GQLGetSkipsForRecentDecisionsQueryVariables = Exact<{ ··· 32696 32702 GQLRecentDecisionsSummaryDataQuery, 32697 32703 GQLRecentDecisionsSummaryDataQueryVariables 32698 32704 >; 32705 + export const GQLOrgLookupDataDocument = gql` 32706 + query OrgLookupData { 32707 + myOrg { 32708 + id 32709 + actions { 32710 + ... on ActionBase { 32711 + id 32712 + name 32713 + } 32714 + } 32715 + policies { 32716 + id 32717 + name 32718 + } 32719 + users { 32720 + id 32721 + firstName 32722 + lastName 32723 + } 32724 + mrtQueues { 32725 + id 32726 + name 32727 + } 32728 + } 32729 + } 32730 + `; 32731 + 32732 + /** 32733 + * __useGQLOrgLookupDataQuery__ 32734 + * 32735 + * To run a query within a React component, call `useGQLOrgLookupDataQuery` and pass it any options that fit your needs. 32736 + * When your component renders, `useGQLOrgLookupDataQuery` returns an object from Apollo Client that contains loading, error, and data properties 32737 + * you can use to render your UI. 32738 + * 32739 + * @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; 32740 + * 32741 + * @example 32742 + * const { data, loading, error } = useGQLOrgLookupDataQuery({ 32743 + * variables: { 32744 + * }, 32745 + * }); 32746 + */ 32747 + export function useGQLOrgLookupDataQuery( 32748 + baseOptions?: Apollo.QueryHookOptions< 32749 + GQLOrgLookupDataQuery, 32750 + GQLOrgLookupDataQueryVariables 32751 + >, 32752 + ) { 32753 + const options = { ...defaultOptions, ...baseOptions }; 32754 + return Apollo.useQuery<GQLOrgLookupDataQuery, GQLOrgLookupDataQueryVariables>( 32755 + GQLOrgLookupDataDocument, 32756 + options, 32757 + ); 32758 + } 32759 + export function useGQLOrgLookupDataLazyQuery( 32760 + baseOptions?: Apollo.LazyQueryHookOptions< 32761 + GQLOrgLookupDataQuery, 32762 + GQLOrgLookupDataQueryVariables 32763 + >, 32764 + ) { 32765 + const options = { ...defaultOptions, ...baseOptions }; 32766 + return Apollo.useLazyQuery< 32767 + GQLOrgLookupDataQuery, 32768 + GQLOrgLookupDataQueryVariables 32769 + >(GQLOrgLookupDataDocument, options); 32770 + } 32771 + // @ts-ignore 32772 + export function useGQLOrgLookupDataSuspenseQuery( 32773 + baseOptions?: Apollo.SuspenseQueryHookOptions< 32774 + GQLOrgLookupDataQuery, 32775 + GQLOrgLookupDataQueryVariables 32776 + >, 32777 + ): Apollo.UseSuspenseQueryResult< 32778 + GQLOrgLookupDataQuery, 32779 + GQLOrgLookupDataQueryVariables 32780 + >; 32781 + export function useGQLOrgLookupDataSuspenseQuery( 32782 + baseOptions?: 32783 + | Apollo.SkipToken 32784 + | Apollo.SuspenseQueryHookOptions< 32785 + GQLOrgLookupDataQuery, 32786 + GQLOrgLookupDataQueryVariables 32787 + >, 32788 + ): Apollo.UseSuspenseQueryResult< 32789 + GQLOrgLookupDataQuery | undefined, 32790 + GQLOrgLookupDataQueryVariables 32791 + >; 32792 + export function useGQLOrgLookupDataSuspenseQuery( 32793 + baseOptions?: 32794 + | Apollo.SkipToken 32795 + | Apollo.SuspenseQueryHookOptions< 32796 + GQLOrgLookupDataQuery, 32797 + GQLOrgLookupDataQueryVariables 32798 + >, 32799 + ) { 32800 + const options = 32801 + baseOptions === Apollo.skipToken 32802 + ? baseOptions 32803 + : { ...defaultOptions, ...baseOptions }; 32804 + return Apollo.useSuspenseQuery< 32805 + GQLOrgLookupDataQuery, 32806 + GQLOrgLookupDataQueryVariables 32807 + >(GQLOrgLookupDataDocument, options); 32808 + } 32809 + export type GQLOrgLookupDataQueryHookResult = ReturnType< 32810 + typeof useGQLOrgLookupDataQuery 32811 + >; 32812 + export type GQLOrgLookupDataLazyQueryHookResult = ReturnType< 32813 + typeof useGQLOrgLookupDataLazyQuery 32814 + >; 32815 + export type GQLOrgLookupDataSuspenseQueryHookResult = ReturnType< 32816 + typeof useGQLOrgLookupDataSuspenseQuery 32817 + >; 32818 + export type GQLOrgLookupDataQueryResult = Apollo.QueryResult< 32819 + GQLOrgLookupDataQuery, 32820 + GQLOrgLookupDataQueryVariables 32821 + >; 32699 32822 export const GQLGetRecentDecisionsDocument = gql` 32700 32823 query GetRecentDecisions($input: RecentDecisionsInput!) { 32701 32824 getRecentDecisions(input: $input) { ··· 32717 32840 } 32718 32841 createdAt 32719 32842 decisionReason 32720 - } 32721 - myOrg { 32722 - id 32723 - actions { 32724 - ... on ActionBase { 32725 - id 32726 - name 32727 - } 32728 - } 32729 - policies { 32730 - id 32731 - name 32732 - } 32733 - users { 32734 - id 32735 - firstName 32736 - lastName 32737 - } 32738 - mrtQueues { 32739 - id 32740 - name 32741 - } 32742 32843 } 32743 32844 } 32744 32845 ${GQLManualReviewDecisionComponentFieldsFragmentDoc} ··· 42992 43093 getResolvedJobsForUser: 'getResolvedJobsForUser', 42993 43094 getSkippedJobsForUser: 'getSkippedJobsForUser', 42994 43095 RecentDecisionsSummaryData: 'RecentDecisionsSummaryData', 43096 + OrgLookupData: 'OrgLookupData', 42995 43097 GetRecentDecisions: 'GetRecentDecisions', 42996 43098 getSkipsForRecentDecisions: 'getSkipsForRecentDecisions', 42997 43099 GetDecidedJob: 'GetDecidedJob',
+14 -2
client/src/index.tsx
··· 3 3 import { 4 4 ApolloClient, 5 5 ApolloProvider, 6 + from, 6 7 gql, 8 + HttpLink, 7 9 InMemoryCache, 8 10 StoreObject, 9 11 } from '@apollo/client'; 10 12 import { KeyFieldsContext } from '@apollo/client/cache/inmemory/policies'; 13 + import { RetryLink } from '@apollo/client/link/retry'; 11 14 import { createRoot } from 'react-dom/client'; 12 15 import { HelmetProvider } from 'react-helmet-async'; 13 16 import { QueryClient, QueryClientProvider } from 'react-query'; ··· 40 43 } 41 44 `; 42 45 43 - // Apollo Client 44 - const client = new ApolloClient({ 46 + const httpLink = new HttpLink({ 45 47 uri: 46 48 import.meta.env.MODE === 'production' 47 49 ? '/api/v1/graphql' 48 50 : 'http://localhost:3000/api/v1/graphql', 51 + }); 52 + 53 + const retryLink = new RetryLink({ 54 + delay: { initial: 300, max: 5000, jitter: true }, 55 + attempts: { max: 3, retryIf: (error) => Boolean(error) }, 56 + }); 57 + 58 + // Apollo Client 59 + const client = new ApolloClient({ 60 + link: from([retryLink, httpLink]), 49 61 cache: new InMemoryCache({ 50 62 typePolicies: { 51 63 ConditionInputField: {
+4 -1
client/src/webpages/dashboard/mrt/ManualReviewQueuesDashboard.tsx
··· 181 181 }; 182 182 183 183 export default function ManualReviewQueuesDashboard() { 184 - const { loading, data, refetch } = useGQLManualReviewQueuesQuery({ 184 + const { loading, error, data, refetch } = useGQLManualReviewQueuesQuery({ 185 185 fetchPolicy: 'no-cache', 186 186 pollInterval: 5000, 187 187 }); ··· 682 682 }), 683 683 [dataValues, onAddFavoriteQueue, onRemoveFavoriteQueue], 684 684 ); 685 + if (error) { 686 + throw error; 687 + } 685 688 if (loading) { 686 689 return <FullScreenLoading />; 687 690 }
+39 -30
client/src/webpages/dashboard/mrt/ManualReviewRecentDecisions.tsx
··· 23 23 useGQLGetDecidedJobLazyQuery, 24 24 useGQLGetRecentDecisionsLazyQuery, 25 25 useGQLGetSkipsForRecentDecisionsLazyQuery, 26 + useGQLOrgLookupDataQuery, 26 27 } from '../../../graphql/generated'; 27 28 import { assertUnreachable } from '../../../utils/misc'; 28 29 import { ··· 71 72 } 72 73 } 73 74 74 - query GetRecentDecisions($input: RecentDecisionsInput!) { 75 - getRecentDecisions(input: $input) { 76 - id 77 - jobId 78 - queueId 79 - reviewerId 80 - itemId 81 - itemTypeId 82 - decisions { 83 - ... on ManualReviewDecisionComponentBase { 84 - ...ManualReviewDecisionComponentFields 85 - } 86 - } 87 - relatedActions { 88 - ... on ManualReviewDecisionComponentBase { 89 - ...ManualReviewDecisionComponentFields 90 - } 91 - } 92 - createdAt 93 - decisionReason 94 - } 75 + query OrgLookupData { 95 76 myOrg { 96 77 id 97 78 actions { ··· 116 97 } 117 98 } 118 99 100 + query GetRecentDecisions($input: RecentDecisionsInput!) { 101 + getRecentDecisions(input: $input) { 102 + id 103 + jobId 104 + queueId 105 + reviewerId 106 + itemId 107 + itemTypeId 108 + decisions { 109 + ... on ManualReviewDecisionComponentBase { 110 + ...ManualReviewDecisionComponentFields 111 + } 112 + } 113 + relatedActions { 114 + ... on ManualReviewDecisionComponentBase { 115 + ...ManualReviewDecisionComponentFields 116 + } 117 + } 118 + createdAt 119 + decisionReason 120 + } 121 + } 122 + 119 123 query getSkipsForRecentDecisions($input: RecentDecisionsInput!) { 120 124 getSkipsForRecentDecisions(input: $input) { 121 125 jobId ··· 149 153 const [unsavedFilterValue, setUnsavedFilterValue] = useState< 150 154 RecentDecisionsFilterInput | undefined 151 155 >(undefined); 156 + 157 + const { data: orgLookupData } = useGQLOrgLookupDataQuery({ 158 + fetchPolicy: 'cache-and-network', 159 + }); 152 160 153 161 const { data: decidedJobFromJobIdData } = useGQLGetDecidedJobFromJobIdQuery({ 154 162 variables: { id: jobId! }, ··· 285 293 if (!reviewerId) { 286 294 return 'Automatic'; 287 295 } 288 - const reviewer = allDecisionsData?.myOrg?.users.find( 296 + const reviewer = orgLookupData?.myOrg?.users.find( 289 297 (user) => user.id === reviewerId, 290 298 ); 291 299 return reviewer 292 300 ? `${reviewer.firstName} ${reviewer.lastName}` 293 301 : 'Unknown'; 294 302 }, 295 - [allDecisionsData?.myOrg?.users], 303 + [orgLookupData?.myOrg?.users], 296 304 ); 297 305 298 306 const getQueueName = useCallback( 299 307 (queueId: string) => 300 - allDecisionsData?.myOrg?.mrtQueues.find((queue) => queue.id === queueId) 308 + orgLookupData?.myOrg?.mrtQueues.find((queue) => queue.id === queueId) 301 309 ?.name ?? 'Unknown', 302 - [allDecisionsData?.myOrg], 310 + [orgLookupData?.myOrg], 303 311 ); 304 312 305 313 const getActionName = useCallback( 306 314 (actionId: string) => 307 - allDecisionsData?.myOrg?.actions.find((action) => action.id === actionId) 315 + orgLookupData?.myOrg?.actions.find((action) => action.id === actionId) 308 316 ?.name ?? 'Unknown', 309 - [allDecisionsData?.myOrg], 317 + [orgLookupData?.myOrg], 310 318 ); 311 319 312 320 const getPolicyName = useCallback( 313 321 (policyId: string) => 314 - allDecisionsData?.myOrg?.policies.find((policy) => policy.id === policyId) 322 + orgLookupData?.myOrg?.policies.find((policy) => policy.id === policyId) 315 323 ?.name ?? 'Unknown', 316 - [allDecisionsData?.myOrg], 324 + [orgLookupData?.myOrg], 317 325 ); 318 326 319 327 const getDecisionColorNamePairs = useCallback( ··· 399 407 ); 400 408 401 409 const dataValues = useMemo(() => { 402 - if (!allDecisionsData || !allDecisionsData.myOrg) { 410 + if (!allDecisionsData || !orgLookupData?.myOrg) { 403 411 return undefined; 404 412 } 405 413 const allDecisions = [ ··· 435 443 }); 436 444 }, [ 437 445 allDecisionsData, 446 + orgLookupData?.myOrg, 438 447 decidedJobFromJobIdData?.getDecidedJobFromJobId?.decision, 439 448 getDecisionColorNamePairs, 440 449 getPoliciesFromDecision,