Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/client/src/components/TagTraining.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useSnackbar } from '../context/Snackbar.context';
export interface TagTrainingComponentProps {
setTrainingSet: Dispatch<SetStateAction<string[]>>;
setTaggingSet: Dispatch<SetStateAction<string[]>>;
setCatchTrialSet: Dispatch<SetStateAction<string[]>>;
}

export const TagTrainingComponent: React.FC<TagTrainingComponentProps> = (props) => {
Expand All @@ -19,6 +20,7 @@ export const TagTrainingComponent: React.FC<TagTrainingComponentProps> = (props)
const [getDatasetsQuery, getDatasetsResults] = useGetDatasetsByProjectLazyQuery();
const [trainingSet, setTrainingSet] = useState<string[]>([]);
const [taggingSet, setTaggingSet] = useState<string[]>([]);
const [catchTrialSet, setCatchTrialSet] = useState<string[]>([]);
const { t } = useTranslation();
const { pushSnackbarMessage } = useSnackbar();

Expand Down Expand Up @@ -64,6 +66,24 @@ export const TagTrainingComponent: React.FC<TagTrainingComponentProps> = (props)
entry={params.row}
/>
)
},
{
field: 'catchTrial',
headerName: 'Catch Trial',
width: 200,
renderCell: (params) => (
<EditSetSwitch
startingValue={catchTrialSet.includes(params.row._id)}
onLoad={(_entry) => {}}
add={(entry) => {
setCatchTrialSet([...catchTrialSet, entry._id]);
}}
remove={(entry) => {
setCatchTrialSet(catchTrialSet.filter((entryID) => entryID !== entry._id));
}}
entry={params.row}
/>
)
}
];

Expand All @@ -77,6 +97,13 @@ export const TagTrainingComponent: React.FC<TagTrainingComponentProps> = (props)
props.setTrainingSet(entries);
}, [trainingSet]);

useEffect(() => {
const entries = Array.from(new Set(catchTrialSet));
if (props.setCatchTrialSet) {
props.setCatchTrialSet(entries);
}
}, [catchTrialSet]);

useEffect(() => {
if (getDatasetsResults.data) {
setDatasets(getDatasetsResults.data.getDatasetsByProject);
Expand Down
14 changes: 14 additions & 0 deletions packages/client/src/graphql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export type Mutation = {
changeStudyName: Study;
completeTag: Scalars['Boolean']['output'];
completeUploadSession: UploadResult;
createCatchTrials: Array<Tag>;
createDataset: Dataset;
createDatasetDownload: DatasetDownloadRequest;
createOrganization: Organization;
Expand Down Expand Up @@ -215,6 +216,12 @@ export type MutationCompleteUploadSessionArgs = {
};


export type MutationCreateCatchTrialsArgs = {
entries: Array<Scalars['ID']['input']>;
study: Scalars['ID']['input'];
};


export type MutationCreateDatasetArgs = {
dataset: DatasetCreate;
};
Expand Down Expand Up @@ -412,6 +419,7 @@ export type Query = {
findStudies: Array<Study>;
/** Get the presigned URL for where to upload the CSV against */
getCSVUploadURL: Scalars['String']['output'];
getCatchTrials: Array<Tag>;
getDatasetDownloads: Array<DatasetDownloadRequest>;
getDatasetProjectPermissions: Array<DatasetProjectPermission>;
getDatasets: Array<Dataset>;
Expand Down Expand Up @@ -465,6 +473,10 @@ export type QueryGetCsvUploadUrlArgs = {
};


export type QueryGetCatchTrialsArgs = {
study: Scalars['ID']['input'];
}

export type QueryGetDatasetDownloadsArgs = {
dataset: Scalars['ID']['input'];
};
Expand Down Expand Up @@ -613,6 +625,8 @@ export type Tag = {
/** If the tag is enabled as part of the study, way to disable certain tags */
enabled: Scalars['Boolean']['output'];
entry: Entry;
/** Indicates if the tag is a catch trial */
isCatchTrial: Scalars['Boolean']['output'];
/** Way to rank tags based on order to be tagged */
order: Scalars['Float']['output'];
study: Study;
Expand Down
26 changes: 26 additions & 0 deletions packages/client/src/graphql/tag/tag.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ mutation createTags($study: ID!, $entries: [ID!]!) {
}
}

mutation createCatchTrials($study: ID!, $entries: [ID!]!) {
createCatchTrials(study: $study, entries: $entries) {
_id
}
}

mutation createTrainingSet($study: ID!, $entries: [ID!]!) {
createTrainingSet(study: $study, entries: $entries)
}
Expand Down Expand Up @@ -185,3 +191,23 @@ query getTrainingTags($study: ID!, $user: String!) {
complete
}
}

query getCatchTrials($study: ID!) {
getCatchTrials(study: $study) {
_id
entry {
_id
organization
entryID
contentType
creator
dateCreated
meta
signedUrl
signedUrlExpiration
}
data
complete
isCatchTrial
}
}
100 changes: 99 additions & 1 deletion packages/client/src/graphql/tag/tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export type CreateTagsMutationVariables = Types.Exact<{

export type CreateTagsMutation = { __typename?: 'Mutation', createTags: Array<{ __typename?: 'Tag', _id: string }> };

export type CreateCatchTrialsMutationVariables = Types.Exact<{
study: Types.Scalars['ID']['input'];
entries: Array<Types.Scalars['ID']['input']> | Types.Scalars['ID']['input'];
}>;


export type CreateCatchTrialsMutation = { __typename?: 'Mutation', createCatchTrials: Array<{ __typename?: 'Tag', _id: string }> };

export type CreateTrainingSetMutationVariables = Types.Exact<{
study: Types.Scalars['ID']['input'];
entries: Array<Types.Scalars['ID']['input']> | Types.Scalars['ID']['input'];
Expand Down Expand Up @@ -84,6 +92,13 @@ export type GetTrainingTagsQueryVariables = Types.Exact<{

export type GetTrainingTagsQuery = { __typename?: 'Query', getTrainingTags: 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 }> };

export type GetCatchTrialsQueryVariables = Types.Exact<{
study: Types.Scalars['ID']['input'];
}>;


export type GetCatchTrialsQuery = { __typename?: 'Query', getCatchTrials: Array<{ __typename?: 'Tag', _id: string, data?: any | null, complete: boolean, isCatchTrial: boolean, entry: { __typename?: 'Entry', _id: string, organization: string, entryID: string, contentType: string, creator: string, dateCreated: any, meta?: any | null, signedUrl: string, signedUrlExpiration: number } }> };


export const CreateTagsDocument = gql`
mutation createTags($study: ID!, $entries: [ID!]!) {
Expand Down Expand Up @@ -119,6 +134,40 @@ export function useCreateTagsMutation(baseOptions?: Apollo.MutationHookOptions<C
export type CreateTagsMutationHookResult = ReturnType<typeof useCreateTagsMutation>;
export type CreateTagsMutationResult = Apollo.MutationResult<CreateTagsMutation>;
export type CreateTagsMutationOptions = Apollo.BaseMutationOptions<CreateTagsMutation, CreateTagsMutationVariables>;
export const CreateCatchTrialsDocument = gql`
mutation createCatchTrials($study: ID!, $entries: [ID!]!) {
createCatchTrials(study: $study, entries: $entries) {
_id
}
}
`;
export type CreateCatchTrialsMutationFn = Apollo.MutationFunction<CreateCatchTrialsMutation, CreateCatchTrialsMutationVariables>;

/**
* __useCreateCatchTrialsMutation__
*
* To run a mutation, you first call `useCreateCatchTrialsMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateCatchTrialsMutation` 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 [createCatchTrialsMutation, { data, loading, error }] = useCreateCatchTrialsMutation({
* variables: {
* study: // value for 'study'
* entries: // value for 'entries'
* },
* });
*/
export function useCreateCatchTrialsMutation(baseOptions?: Apollo.MutationHookOptions<CreateCatchTrialsMutation, CreateCatchTrialsMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<CreateCatchTrialsMutation, CreateCatchTrialsMutationVariables>(CreateCatchTrialsDocument, options);
}
export type CreateCatchTrialsMutationHookResult = ReturnType<typeof useCreateCatchTrialsMutation>;
export type CreateCatchTrialsMutationResult = Apollo.MutationResult<CreateCatchTrialsMutation>;
export type CreateCatchTrialsMutationOptions = Apollo.BaseMutationOptions<CreateCatchTrialsMutation, CreateCatchTrialsMutationVariables>;
export const CreateTrainingSetDocument = gql`
mutation createTrainingSet($study: ID!, $entries: [ID!]!) {
createTrainingSet(study: $study, entries: $entries)
Expand Down Expand Up @@ -545,4 +594,53 @@ export function useGetTrainingTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOp
}
export type GetTrainingTagsQueryHookResult = ReturnType<typeof useGetTrainingTagsQuery>;
export type GetTrainingTagsLazyQueryHookResult = ReturnType<typeof useGetTrainingTagsLazyQuery>;
export type GetTrainingTagsQueryResult = Apollo.QueryResult<GetTrainingTagsQuery, GetTrainingTagsQueryVariables>;
export type GetTrainingTagsQueryResult = Apollo.QueryResult<GetTrainingTagsQuery, GetTrainingTagsQueryVariables>;
export const GetCatchTrialsDocument = gql`
query getCatchTrials($study: ID!) {
getCatchTrials(study: $study) {
_id
entry {
_id
organization
entryID
contentType
creator
dateCreated
meta
signedUrl
signedUrlExpiration
}
data
complete
isCatchTrial
}
}
`;

/**
* __useGetCatchTrialsQuery__
*
* To run a query within a React component, call `useGetCatchTrialsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetCatchTrialsQuery` 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 } = useGetCatchTrialsQuery({
* variables: {
* study: // value for 'study'
* },
* });
*/
export function useGetCatchTrialsQuery(baseOptions: Apollo.QueryHookOptions<GetCatchTrialsQuery, GetCatchTrialsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetCatchTrialsQuery, GetCatchTrialsQueryVariables>(GetCatchTrialsDocument, options);
}
export function useGetCatchTrialsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetCatchTrialsQuery, GetCatchTrialsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetCatchTrialsQuery, GetCatchTrialsQueryVariables>(GetCatchTrialsDocument, options);
}
export type GetCatchTrialsQueryHookResult = ReturnType<typeof useGetCatchTrialsQuery>;
export type GetCatchTrialsLazyQueryHookResult = ReturnType<typeof useGetCatchTrialsLazyQuery>;
export type GetCatchTrialsQueryResult = Apollo.QueryResult<GetCatchTrialsQuery, GetCatchTrialsQueryVariables>;
25 changes: 22 additions & 3 deletions packages/client/src/pages/studies/NewStudy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import { useApolloClient } from '@apollo/client';
import {
CreateTagsDocument,
CreateTrainingSetDocument,
CreateCatchTrialsDocument,
CreateTagsMutationVariables,
CreateTagsMutation,
CreateTrainingSetMutation,
CreateTrainingSetMutationVariables
CreateTrainingSetMutationVariables,
CreateCatchTrialsMutation,
CreateCatchTrialsMutationVariables
} from '../../graphql/tag/tag';
import { useTranslation } from 'react-i18next';
import { TagFieldFragmentSchema, TagField } from '../../components/tagbuilder/TagProvider';
Expand All @@ -30,6 +33,7 @@ export const NewStudy: React.FC = () => {
const { updateStudies } = useStudy();
const [trainingSet, setTrainingSet] = useState<string[]>([]);
const [taggingSet, setTaggingSet] = useState<string[]>([]);
const [catchTrialSet, setCatchTrialSet] = useState<string[]>([]);
const apolloClient = useApolloClient();
// The different fields that make up the tag schema
const [tagFields, setTagFields] = useState<TagField[]>([]);
Expand Down Expand Up @@ -90,10 +94,19 @@ export const NewStudy: React.FC = () => {
return;
}

// Filter taggingSet to remove IDs that are also in catchTrialSet
const filteredTaggingSet = taggingSet.filter((id) => !catchTrialSet.includes(id));

// Create the corresponding tags
await apolloClient.mutate<CreateTagsMutation, CreateTagsMutationVariables>({
mutation: CreateTagsDocument,
variables: { study: result.data.createStudy._id, entries: taggingSet }
variables: { study: result.data.createStudy._id, entries: filteredTaggingSet }
});

// Create the corresponding Catch Trial tags
await apolloClient.mutate<CreateCatchTrialsMutation, CreateCatchTrialsMutationVariables>({
mutation: CreateCatchTrialsDocument,
variables: { study: result.data.createStudy._id, entries: catchTrialSet }
});

// Create the training set
Expand Down Expand Up @@ -138,7 +151,13 @@ export const NewStudy: React.FC = () => {
/>
);
case 2:
return <TagTrainingComponent setTaggingSet={setTaggingSet} setTrainingSet={setTrainingSet} />;
return (
<TagTrainingComponent
setTaggingSet={setTaggingSet}
setTrainingSet={setTrainingSet}
setCatchTrialSet={setCatchTrialSet}
/>
);
default:
return null;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/server/src/tag/models/tag.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export class Tag {
@Prop()
@Field({ description: 'If the tag is part of a training' })
training: boolean;

@Prop()
@Field({ description: 'Indicates if the tag is a catch trial' })
isCatchTrial: boolean;
}

export type TagDocument = Tag & Document;
Expand Down
17 changes: 17 additions & 0 deletions packages/server/src/tag/resolvers/tag.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ export class TagResolver {
return this.tagService.createTags(study, entries);
}

@Mutation(() => [Tag])
async createCatchTrials(
@Args('study', { type: () => ID }, StudyPipe) study: Study,
@Args('entries', { type: () => [ID] }, EntriesPipe) entries: Entry[],
@TokenContext() user: TokenPayload
) {
if (!(await this.enforcer.enforce(user.user_id, StudyPermissions.CREATE, study._id.toString()))) {
throw new UnauthorizedException('User cannot add tags to this study');
}
return this.tagService.createCatchTrials(study, entries);
}

@Mutation(() => Tag, { nullable: true })
async assignTag(
@Args('study', { type: () => ID }, StudyPipe) study: Study,
Expand Down Expand Up @@ -141,4 +153,9 @@ export class TagResolver {
async study(@Parent() tag: Tag): Promise<Study> {
return this.studyPipe.transform(tag.study);
}

@Query(() => [Tag])
async getCatchTrials(@Args('study', { type: () => ID }, StudyPipe) study: Study): Promise<Tag[]> {
return this.tagService.getCatchTrials(study);
}
}
Loading