Skip to content

Commit 8fd8814

Browse files
authored
feat: Tag View Pagination (#114)
* Server side pagination support for tags * Update view to leverage pagination
1 parent 57e1304 commit 8fd8814

File tree

8 files changed

+281
-32
lines changed

8 files changed

+281
-32
lines changed

packages/client/src/components/tag/view/TagGridView.component.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { GetGridColDefs, TagViewTest } from '../../../types/TagColumnView';
33
import { Entry, Study } from '../../../graphql/graphql';
44
import {
55
GridColDef,
6+
GridPaginationModel,
67
GridRenderCellParams,
78
GridToolbarColumnsButton,
89
GridToolbarContainer,
@@ -19,12 +20,15 @@ import { getSliderCols, sliderTest } from './SliderGridView.component';
1920
import { getBoolCols, booleanTest } from './BooleanGridView.component';
2021
import { aslLexTest, getAslLexCols } from './AslLexGridView.component';
2122
import { getVideoCols, videoViewTest } from './VideoGridView.component';
22-
import { useEffect, useState } from 'react';
23+
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
2324

2425
export interface TagGridViewProps {
2526
study: Study;
2627
tags: GetTagsQuery['getTags'];
2728
refetchTags: () => void;
29+
paginationModel: GridPaginationModel;
30+
setPaginationModel: Dispatch<SetStateAction<GridPaginationModel>>;
31+
totalTags: number;
2832
}
2933

3034
/**
@@ -55,7 +59,14 @@ interface GridData extends Omit<GetTagsQuery['getTags'][0], 'data'> {
5559
data: { [property: string]: any } | null;
5660
}
5761

58-
export const TagGridView: React.FC<TagGridViewProps> = ({ tags, study, refetchTags }) => {
62+
export const TagGridView: React.FC<TagGridViewProps> = ({
63+
tags,
64+
study,
65+
refetchTags,
66+
paginationModel,
67+
setPaginationModel,
68+
totalTags
69+
}) => {
5970
const { t } = useTranslation();
6071

6172
const [gridData, setGridData] = useState<(GridData | null)[]>([]);
@@ -163,6 +174,18 @@ export const TagGridView: React.FC<TagGridViewProps> = ({ tags, study, refetchTa
163174
columns={entryColumns.concat(tagMetaColumns).concat(dataColunms).concat(tagRedoColumns)}
164175
getRowId={(row) => row._id}
165176
slots={{ toolbar: TagToolbar }}
177+
paginationMode="server"
178+
paginationModel={paginationModel}
179+
initialState={{
180+
pagination: {
181+
paginationModel: {
182+
pageSize: 5
183+
}
184+
}
185+
}}
186+
pageSizeOptions={[5, 10, 15]}
187+
onPaginationModelChange={setPaginationModel}
188+
rowCount={totalTags}
166189
/>
167190
);
168191
};

packages/client/src/graphql/graphql.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ export type ProjectPermissionModel = {
469469
export type Query = {
470470
__typename?: 'Query';
471471
countEntryForDataset: Scalars['Int']['output'];
472+
countTagForStudy: Scalars['Int']['output'];
473+
countTrainingTagForStudy: Scalars['Int']['output'];
472474
datasetExists: Scalars['Boolean']['output'];
473475
entryForDataset: Array<Entry>;
474476
entryFromID: Entry;
@@ -506,6 +508,17 @@ export type QueryCountEntryForDatasetArgs = {
506508
};
507509

508510

511+
export type QueryCountTagForStudyArgs = {
512+
study: Scalars['ID']['input'];
513+
};
514+
515+
516+
export type QueryCountTrainingTagForStudyArgs = {
517+
study: Scalars['ID']['input'];
518+
user: Scalars['String']['input'];
519+
};
520+
521+
509522
export type QueryDatasetExistsArgs = {
510523
name: Scalars['String']['input'];
511524
};
@@ -582,11 +595,15 @@ export type QueryGetStudyPermissionsArgs = {
582595

583596

584597
export type QueryGetTagsArgs = {
598+
page?: InputMaybe<Scalars['Int']['input']>;
599+
pageSize?: InputMaybe<Scalars['Int']['input']>;
585600
study: Scalars['ID']['input'];
586601
};
587602

588603

589604
export type QueryGetTrainingTagsArgs = {
605+
page?: InputMaybe<Scalars['Int']['input']>;
606+
pageSize?: InputMaybe<Scalars['Int']['input']>;
590607
study: Scalars['ID']['input'];
591608
user: Scalars['String']['input'];
592609
};

packages/client/src/graphql/tag/tag.graphql

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ mutation saveVideoField($tag: ID!, $field: String!, $index: Int!) {
5050
}
5151
}
5252

53-
query getTags($study: ID!) {
54-
getTags(study: $study) {
53+
query getTags($study: ID!, $page: Int, $pageSize: Int) {
54+
getTags(study: $study, page: $page, pageSize: $pageSize) {
5555
_id
5656
entry {
5757
_id
@@ -118,8 +118,16 @@ query getTags($study: ID!) {
118118
}
119119
}
120120

121-
query getTrainingTags($study: ID!, $user: String!) {
122-
getTrainingTags(study: $study, user: $user) {
121+
query countTagForStudy($study: ID!) {
122+
countTagForStudy(study: $study)
123+
}
124+
125+
query countTrainingTagForStudy($study: ID!, $user: String!) {
126+
countTrainingTagForStudy(study: $study, user: $user)
127+
}
128+
129+
query getTrainingTags($study: ID!, $user: String!, $page: Int, $pageSize: Int) {
130+
getTrainingTags(study: $study, user: $user, page: $page, pageSize: $pageSize) {
123131
_id
124132
entry {
125133
_id

packages/client/src/graphql/tag/tag.ts

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,33 @@ export type SaveVideoFieldMutation = { __typename?: 'Mutation', saveVideoField:
7171

7272
export type GetTagsQueryVariables = Types.Exact<{
7373
study: Types.Scalars['ID']['input'];
74+
page?: Types.InputMaybe<Types.Scalars['Int']['input']>;
75+
pageSize?: Types.InputMaybe<Types.Scalars['Int']['input']>;
7476
}>;
7577

7678

7779
export type GetTagsQuery = { __typename?: 'Query', getTags: Array<{ __typename?: 'Tag', _id: string, complete: boolean, entry: { __typename?: 'Entry', _id: string, organization: string, entryID: string, contentType: string, creator: string, dateCreated: any, meta?: any | null, signedUrl: string, signedUrlExpiration: number, isTraining: boolean }, data?: Array<{ __typename?: 'TagField', type: Types.TagFieldType, name: string, field?: { __typename: 'AslLexField', lexiconEntry: { __typename?: 'LexiconEntry', key: string, primary: string, video: string, lexicon: string, associates: Array<string>, fields: any } } | { __typename: 'BooleanField', boolValue: boolean } | { __typename: 'FreeTextField', textValue: string } | { __typename: 'NumericField', numericValue: number } | { __typename: 'SliderField', sliderValue: number } | { __typename: 'VideoField', entries: Array<{ __typename?: 'Entry', _id: string, organization: string, entryID: string, contentType: string, creator: string, dateCreated: any, meta?: any | null, signedUrl: string, signedUrlExpiration: number, isTraining: boolean }> } | null }> | null }> };
7880

81+
export type CountTagForStudyQueryVariables = Types.Exact<{
82+
study: Types.Scalars['ID']['input'];
83+
}>;
84+
85+
86+
export type CountTagForStudyQuery = { __typename?: 'Query', countTagForStudy: number };
87+
88+
export type CountTrainingTagForStudyQueryVariables = Types.Exact<{
89+
study: Types.Scalars['ID']['input'];
90+
user: Types.Scalars['String']['input'];
91+
}>;
92+
93+
94+
export type CountTrainingTagForStudyQuery = { __typename?: 'Query', countTrainingTagForStudy: number };
95+
7996
export type GetTrainingTagsQueryVariables = Types.Exact<{
8097
study: Types.Scalars['ID']['input'];
8198
user: Types.Scalars['String']['input'];
99+
page?: Types.InputMaybe<Types.Scalars['Int']['input']>;
100+
pageSize?: Types.InputMaybe<Types.Scalars['Int']['input']>;
82101
}>;
83102

84103

@@ -364,8 +383,8 @@ export type SaveVideoFieldMutationHookResult = ReturnType<typeof useSaveVideoFie
364383
export type SaveVideoFieldMutationResult = Apollo.MutationResult<SaveVideoFieldMutation>;
365384
export type SaveVideoFieldMutationOptions = Apollo.BaseMutationOptions<SaveVideoFieldMutation, SaveVideoFieldMutationVariables>;
366385
export const GetTagsDocument = gql`
367-
query getTags($study: ID!) {
368-
getTags(study: $study) {
386+
query getTags($study: ID!, $page: Int, $pageSize: Int) {
387+
getTags(study: $study, page: $page, pageSize: $pageSize) {
369388
_id
370389
entry {
371390
_id
@@ -440,6 +459,8 @@ export const GetTagsDocument = gql`
440459
* const { data, loading, error } = useGetTagsQuery({
441460
* variables: {
442461
* study: // value for 'study'
462+
* page: // value for 'page'
463+
* pageSize: // value for 'pageSize'
443464
* },
444465
* });
445466
*/
@@ -454,9 +475,76 @@ export function useGetTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<Ge
454475
export type GetTagsQueryHookResult = ReturnType<typeof useGetTagsQuery>;
455476
export type GetTagsLazyQueryHookResult = ReturnType<typeof useGetTagsLazyQuery>;
456477
export type GetTagsQueryResult = Apollo.QueryResult<GetTagsQuery, GetTagsQueryVariables>;
478+
export const CountTagForStudyDocument = gql`
479+
query countTagForStudy($study: ID!) {
480+
countTagForStudy(study: $study)
481+
}
482+
`;
483+
484+
/**
485+
* __useCountTagForStudyQuery__
486+
*
487+
* To run a query within a React component, call `useCountTagForStudyQuery` and pass it any options that fit your needs.
488+
* When your component renders, `useCountTagForStudyQuery` returns an object from Apollo Client that contains loading, error, and data properties
489+
* you can use to render your UI.
490+
*
491+
* @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;
492+
*
493+
* @example
494+
* const { data, loading, error } = useCountTagForStudyQuery({
495+
* variables: {
496+
* study: // value for 'study'
497+
* },
498+
* });
499+
*/
500+
export function useCountTagForStudyQuery(baseOptions: Apollo.QueryHookOptions<CountTagForStudyQuery, CountTagForStudyQueryVariables>) {
501+
const options = {...defaultOptions, ...baseOptions}
502+
return Apollo.useQuery<CountTagForStudyQuery, CountTagForStudyQueryVariables>(CountTagForStudyDocument, options);
503+
}
504+
export function useCountTagForStudyLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<CountTagForStudyQuery, CountTagForStudyQueryVariables>) {
505+
const options = {...defaultOptions, ...baseOptions}
506+
return Apollo.useLazyQuery<CountTagForStudyQuery, CountTagForStudyQueryVariables>(CountTagForStudyDocument, options);
507+
}
508+
export type CountTagForStudyQueryHookResult = ReturnType<typeof useCountTagForStudyQuery>;
509+
export type CountTagForStudyLazyQueryHookResult = ReturnType<typeof useCountTagForStudyLazyQuery>;
510+
export type CountTagForStudyQueryResult = Apollo.QueryResult<CountTagForStudyQuery, CountTagForStudyQueryVariables>;
511+
export const CountTrainingTagForStudyDocument = gql`
512+
query countTrainingTagForStudy($study: ID!, $user: String!) {
513+
countTrainingTagForStudy(study: $study, user: $user)
514+
}
515+
`;
516+
517+
/**
518+
* __useCountTrainingTagForStudyQuery__
519+
*
520+
* To run a query within a React component, call `useCountTrainingTagForStudyQuery` and pass it any options that fit your needs.
521+
* When your component renders, `useCountTrainingTagForStudyQuery` returns an object from Apollo Client that contains loading, error, and data properties
522+
* you can use to render your UI.
523+
*
524+
* @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;
525+
*
526+
* @example
527+
* const { data, loading, error } = useCountTrainingTagForStudyQuery({
528+
* variables: {
529+
* study: // value for 'study'
530+
* user: // value for 'user'
531+
* },
532+
* });
533+
*/
534+
export function useCountTrainingTagForStudyQuery(baseOptions: Apollo.QueryHookOptions<CountTrainingTagForStudyQuery, CountTrainingTagForStudyQueryVariables>) {
535+
const options = {...defaultOptions, ...baseOptions}
536+
return Apollo.useQuery<CountTrainingTagForStudyQuery, CountTrainingTagForStudyQueryVariables>(CountTrainingTagForStudyDocument, options);
537+
}
538+
export function useCountTrainingTagForStudyLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<CountTrainingTagForStudyQuery, CountTrainingTagForStudyQueryVariables>) {
539+
const options = {...defaultOptions, ...baseOptions}
540+
return Apollo.useLazyQuery<CountTrainingTagForStudyQuery, CountTrainingTagForStudyQueryVariables>(CountTrainingTagForStudyDocument, options);
541+
}
542+
export type CountTrainingTagForStudyQueryHookResult = ReturnType<typeof useCountTrainingTagForStudyQuery>;
543+
export type CountTrainingTagForStudyLazyQueryHookResult = ReturnType<typeof useCountTrainingTagForStudyLazyQuery>;
544+
export type CountTrainingTagForStudyQueryResult = Apollo.QueryResult<CountTrainingTagForStudyQuery, CountTrainingTagForStudyQueryVariables>;
457545
export const GetTrainingTagsDocument = gql`
458-
query getTrainingTags($study: ID!, $user: String!) {
459-
getTrainingTags(study: $study, user: $user) {
546+
query getTrainingTags($study: ID!, $user: String!, $page: Int, $pageSize: Int) {
547+
getTrainingTags(study: $study, user: $user, page: $page, pageSize: $pageSize) {
460548
_id
461549
entry {
462550
_id
@@ -532,6 +620,8 @@ export const GetTrainingTagsDocument = gql`
532620
* variables: {
533621
* study: // value for 'study'
534622
* user: // value for 'user'
623+
* page: // value for 'page'
624+
* pageSize: // value for 'pageSize'
535625
* },
536626
* });
537627
*/

packages/client/src/pages/studies/TagTrainingView.tsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { useLocation } from 'react-router-dom';
22
import { User, Study } from '../../graphql/graphql';
3-
import { GetTagsQuery, useGetTrainingTagsQuery } from '../../graphql/tag/tag';
3+
import { GetTagsQuery, useCountTrainingTagForStudyLazyQuery, useGetTrainingTagsLazyQuery } from '../../graphql/tag/tag';
44
import { useEffect, useState } from 'react';
55
import { TagGridView } from '../../components/tag/view/TagGridView.component';
66
import { Typography } from '@mui/material';
77
import { useTranslation } from 'react-i18next';
88
import { useSnackbar } from '../../context/Snackbar.context';
9+
import { GridPaginationModel } from '@mui/x-data-grid';
910

1011
export const TagTrainingView: React.FC = () => {
1112
const state = useLocation().state;
@@ -14,28 +15,57 @@ export const TagTrainingView: React.FC = () => {
1415
const [tags, setTags] = useState<GetTagsQuery['getTags']>([]);
1516
const { t } = useTranslation();
1617
const { pushSnackbarMessage } = useSnackbar();
18+
const [paginationModel, setPaginationModel] = useState<GridPaginationModel>({ page: 0, pageSize: 10 });
19+
const [trainingTagsQuery, trainingTagsResult] = useGetTrainingTagsLazyQuery();
20+
const [totalTags, setTotalTags] = useState<number>(0);
21+
const [tagCount, tagCountResult] = useCountTrainingTagForStudyLazyQuery();
1722

18-
const trainingTags = useGetTrainingTagsQuery({ variables: { study: study._id, user: user.uid } });
23+
useEffect(() => {
24+
trainingTagsQuery({
25+
variables: {
26+
study: study._id,
27+
user: user.uid,
28+
page: paginationModel.page,
29+
pageSize: paginationModel.pageSize
30+
}
31+
});
32+
tagCount({ variables: { study: study._id, user: user.uid } });
33+
}, [paginationModel]);
1934

2035
useEffect(() => {
21-
if (trainingTags.data) {
22-
setTags(trainingTags.data.getTrainingTags);
23-
} else if (trainingTags.error) {
36+
if (trainingTagsResult.data) {
37+
setTags(trainingTagsResult.data.getTrainingTags);
38+
} else if (trainingTagsResult.error) {
2439
pushSnackbarMessage(t('errors.tagsQuery'), 'error');
25-
console.error(trainingTags.error);
40+
console.error(trainingTagsResult.error);
41+
}
42+
}, [trainingTagsResult]);
43+
44+
useEffect(() => {
45+
if (tagCountResult.data) {
46+
setTotalTags(tagCountResult.data.countTrainingTagForStudy);
47+
} else if (tagCountResult.error) {
48+
console.error(tagCountResult.error);
2649
}
27-
}, [trainingTags]);
50+
}, [tagCountResult]);
2851

2952
const refetchTags = () => {
30-
trainingTags.refetch();
53+
trainingTagsResult.refetch();
3154
};
3255

3356
return (
3457
<>
3558
{!tags || tags.length === 0 ? (
3659
<Typography variant="h3">{t('components.userPermissions.noTrainingTags')}</Typography>
3760
) : (
38-
<TagGridView tags={tags} study={study} refetchTags={refetchTags} />
61+
<TagGridView
62+
tags={tags}
63+
study={study}
64+
refetchTags={refetchTags}
65+
paginationModel={paginationModel}
66+
setPaginationModel={setPaginationModel}
67+
totalTags={totalTags}
68+
/>
3969
)}
4070
</>
4171
);

0 commit comments

Comments
 (0)