Skip to content
Merged
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
76 changes: 74 additions & 2 deletions packages/client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,22 @@
"instruction": "Instruction",
"project": "Project",
"study": "Study",
"submit": "Submit"
"submit": "Submit",
"delete": "Delete",
"cancel": "Cancel",
"ok": "OK",
"email": "Email",
"back": "Back",
"finish": "Finish",
"next": "Next",
"continue": "Continue",
"required": "Required",
"preview": "Preview",
"enable": "Enable",
"view": "View",
"entryId": "Entry ID",
"login": "Login",
"clear": "clear"
},
"languages": {
"en": "English",
Expand All @@ -24,7 +39,7 @@
"studies": "Studies",
"newStudy": "New Study",
"studyControl": "Study Control",
"entryControls": "Entry Controls",
"entryControl": "Entry Control",
"downloadTags": "Download Tags",
"datasets": "Datasets",
"datasetControl": "Dataset Control",
Expand All @@ -44,7 +59,64 @@
"formLabel": "Create New Project",
"nameDescription": "Please enter project name",
"descriptionDescription": "Please enter project description",
"failMessage": " Failed to create project! Try again.",
"projectExists": "A project with this name already exists"
},
"projectControl": {
"deleteStudy": "Delete Study",
"deleteDescription": "Are you sure you want to delete this project? Doing so will delete all contained studies and tags"
},
"datasetControl": {
"deleteEntry": "Delete Entry",
"deleteDescription": "Are you sure you want to delete this project? Doing so will delete all associated tags",
"addDataset": " Add New Dataset",
"uploadEntries": " Upload Entries"
},
"projectAccess": {
"datasetName": "Dataset Name",
"projectHasAccess": "Project Has Access",
"accessFor": "Dataset Access for ",
"selectProject": "Select a Project to Continue"
},
"userPermissions": {
"studyAdmin": "Study Admin",
"contributor": "Contributor",
"trained": "Trained"
},
"projectUserPermissions": {
"projectAdmin": "Project Admin",
"contributor": "Contributor",
"trained": "Trained"
},
"newStudy": {
"createStudy": "Create New Study",
"steps": {
"Study Identification": "Study Identification",
"Construct Tagging Interface": "Construct Tagging Interface",
"Select Tag Training Items": "Select Tag Training Items"
},
"completed": "All steps completed - your new study is created",
"startOver": "Start Over",
"formTitle": "Study Information",
"tagsDescription": "Number of times each entry needs to be tagged (default 1)"
},
"studyControl": {
"deleteStudy": "Delete Study",
"deleteDescription": "Are you sure you want to delete this study? Doing so will delete all contained tags"
},
"contribute": {
"enterTagging": "Enter tagging",
"noTaggingLeft": "No tagging left",
"studyTraining": "Study Training",
"studyTagging": "Study Tagging",
"failMessage": " Failed to create project! Try again."
},
"successPage": {
"succefullyCreated": "Successfully created!"
},
"login": {
"selectOrg": "Select an Organization to Login",
"redirectToOrg": "Redirect to Organization Login"
}
}
}
8 changes: 5 additions & 3 deletions packages/client/src/components/DatasetAccess.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import useEnhancedEffect from '@mui/material/utils/useEnhancedEffect';
import { DataGrid, GridColDef, GridRenderCellParams, useGridApiContext } from '@mui/x-data-grid';
import { GridRowModesModel } from '@mui/x-data-grid-pro';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

interface Row {
id: number;
Expand Down Expand Up @@ -41,6 +42,7 @@ const renderSwitchEditInputCell: GridColDef['renderCell'] = (params) => {
export const DatasetAccess: React.FC<Table> = ({ tableRows }: Table) => {
const [rows] = useState(tableRows);
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
const { t } = useTranslation();

const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => {
setRowModesModel(newRowModesModel);
Expand All @@ -50,20 +52,20 @@ export const DatasetAccess: React.FC<Table> = ({ tableRows }: Table) => {
{ field: 'id', headerName: 'ID', width: 55 },
{
field: 'name',
headerName: 'Name',
headerName: t('common.name'),
width: 200,
editable: true
},
{
field: 'description',
headerName: 'Description',
headerName: t('common.description'),
width: 450,
editable: true
},
{
field: 'switch',
type: 'boolean',
headerName: 'Project Access',
headerName: t('menu.projectAccess'),
renderCell: (params) => <Switch value={params.value} />,
renderEditCell: renderSwitchEditInputCell,
editable: true,
Expand Down
7 changes: 5 additions & 2 deletions packages/client/src/components/DatasetTable.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,26 @@ import { useState, useEffect } from 'react';
import { Dataset, Entry } from '../graphql/graphql';
import { useEntryForDatasetLazyQuery } from '../graphql/entry/entry';
import { EntryView } from './EntryView.component';
import { useTranslation } from 'react-i18next';

export interface DatasetTableProps {
dataset: Dataset;
additionalColumns?: GridColDef[];
}

export const DatasetTable: React.FC<DatasetTableProps> = (props) => {
const { t } = useTranslation();

const defaultColumns: GridColDef[] = [
{
field: 'view',
headerName: 'View',
headerName: t('common.view'),
width: 300,
renderCell: (params) => <EntryView entry={params.row as Entry} width={300} />
},
{
field: 'entryID',
headerName: 'Entry ID',
headerName: t('common.entryId'),
width: 150,
editable: false
}
Expand Down
108 changes: 55 additions & 53 deletions packages/client/src/components/NewStudyJsonForm.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,75 @@ import { PartialStudyCreate } from '../types/study';
import { ErrorObject } from 'ajv';
import { useStudyExistsLazyQuery } from '../graphql/study/study';
import { useProject } from '../context/Project.context';
import { useTranslation } from 'react-i18next';

export interface NewStudyFormProps {
newStudy: PartialStudyCreate | null;
setNewStudy: Dispatch<SetStateAction<PartialStudyCreate | null>>;
}

export const NewStudyJsonForm: React.FC<NewStudyFormProps> = (props) => {
const initialData = {
tagsPerEntry: schema.properties.tagsPerEntry.default
};

const [data, setData] = useState<any>(initialData);
const [studyExistsQuery, studyExistsResults] = useStudyExistsLazyQuery();
const { project } = useProject();
const [additionalErrors, setAdditionalErrors] = useState<ErrorObject[]>([]);

// Keep track of the new study internally to check to make sure the name is
// unique before submitting
const [potentialNewStudy, setPotentialNewStudy] = useState<PartialStudyCreate | null>(null);
const { t } = useTranslation();

const schema = {
type: 'object',
properties: {
name: {
type: 'string',
pattern: '^[a-zA-Z 0-9]*$'
},
description: {
type: 'string'
},
instructions: {
type: 'string'
},
tagsPerEntry: {
type: 'number',
default: 1
}
},
required: ['name', 'description', 'instructions', 'tagsPerEntry']
};

const uischema = {
type: 'Group',
label: t('components.newStudy.formTitle'),
elements: [
{
type: 'Control',
label: t('common.name'),
scope: '#/properties/name'
},
{
type: 'Control',
label: t('common.description'),
scope: '#/properties/description'
},
{
type: 'Control',
label: t('common.instruction'),
scope: '#/properties/instructions'
},
{
type: 'Control',
label: t('components.newStudy.tagsDescription'),
scope: '#/properties/tagsPerEntry'
}
]
};

const initialData = {
tagsPerEntry: schema.properties.tagsPerEntry.default
};
const [data, setData] = useState<any>(initialData);

const handleChange = (data: any, errors: ErrorObject[] | undefined) => {
setData(data);
Expand Down Expand Up @@ -68,51 +118,3 @@ export const NewStudyJsonForm: React.FC<NewStudyFormProps> = (props) => {
/>
);
};

const schema = {
type: 'object',
properties: {
name: {
type: 'string',
pattern: '^[a-zA-Z 0-9]*$'
},
description: {
type: 'string'
},
instructions: {
type: 'string'
},
tagsPerEntry: {
type: 'number',
default: 1
}
},
required: ['name', 'description', 'instructions', 'tagsPerEntry']
};

const uischema = {
type: 'Group',
label: 'Study Information',
elements: [
{
type: 'Control',
label: 'Name',
scope: '#/properties/name'
},
{
type: 'Control',
label: 'Description',
scope: '#/properties/description'
},
{
type: 'Control',
label: 'Instructions',
scope: '#/properties/instructions'
},
{
type: 'Control',
label: 'Number of times each entry needs to be tagged (default 1)',
scope: '#/properties/tagsPerEntry'
}
]
};
2 changes: 1 addition & 1 deletion packages/client/src/components/SideBar.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const SideBar: FC<SideBarProps> = ({ open, drawerWidth }) => {
action: () => navigate('/study/permissions'),
visible: (p) => p!.studyAdmin
},
{ name: t('menu.entryControls'), action: () => navigate('/study/entries'), visible: (p) => p!.studyAdmin },
{ name: t('menu.entryControl'), action: () => navigate('/study/entries'), visible: (p) => p!.studyAdmin },
{ name: t('menu.downloadTags'), action: () => navigate('/study/tags'), visible: (p) => p!.studyAdmin }
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import AslLexSearchControl from '../tag/asllex/AslLexSearchControl';
import AslLexSearchControlTester from '../tag/asllex/aslLexSearchControlTester';
import VideoRecordField, { videoFieldTester } from '../tag/videorecord/VideoRecordField.component';
import { JsonFormsRendererRegistryEntry } from '@jsonforms/core';
import { useTranslation } from 'react-i18next';

export interface TagFormProps {
study: Study;
Expand All @@ -17,6 +18,7 @@ export interface TagFormProps {
export const TagForm: React.FC<TagFormProps> = (props) => {
const [data, setData] = useState<any>();
const [dataValid, setDataValid] = useState<boolean>(false);
const { t } = useTranslation();

const handleFormChange = (data: any, errors: ErrorObject[] | undefined) => {
setData(data);
Expand Down Expand Up @@ -62,10 +64,10 @@ export const TagForm: React.FC<TagFormProps> = (props) => {
/>
<Stack direction="row">
<Button variant="outlined" onClick={handleSubmit} disabled={!dataValid}>
Submit
{t('common.submit')}
</Button>
<Button variant="outlined" onClick={handleClear}>
Clear
{t('common.clear')}
</Button>
</Stack>
</Stack>
Expand Down
6 changes: 4 additions & 2 deletions packages/client/src/context/Confirmation.context.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createContext, useContext, useState } from 'react';
import { Dialog, DialogContent, DialogTitle, DialogActions, Button, Typography } from '@mui/material';
import { useTranslation } from 'react-i18next';

export interface ConfirmationRequest {
message: string;
Expand All @@ -21,6 +22,7 @@ export interface ConfirmationProviderProps {
export const ConfirmationProvider: React.FC<ConfirmationProviderProps> = ({ children }) => {
const [open, setOpen] = useState(false);
const [confirmationRequest, setConfirmationRequest] = useState<ConfirmationRequest | null>(null);
const { t } = useTranslation();

const pushConfirmationRequest = (confirmationRequest: ConfirmationRequest) => {
setConfirmationRequest(confirmationRequest);
Expand Down Expand Up @@ -50,9 +52,9 @@ export const ConfirmationProvider: React.FC<ConfirmationProviderProps> = ({ chil
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCancel}>
Cancel
{t('common.cancel')}
</Button>
<Button onClick={handleConfirm}>Ok</Button>
<Button onClick={handleConfirm}> {t('common.ok')}</Button>
</DialogActions>
</Dialog>
{children}
Expand Down
6 changes: 4 additions & 2 deletions packages/client/src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { useAuth } from '../context/Auth.context';
import { useNavigate } from 'react-router-dom';
import { Organization } from '../graphql/graphql';
import { useGetOrganizationsQuery } from '../graphql/organization/organization';
import { useTranslation } from 'react-i18next';

export const LoginPage: FC = () => {
// Construct the Auth URL
const { authenticated } = useAuth();
const navigate = useNavigate();
const { t } = useTranslation();

const [organization, setOrganization] = useState<Organization | null>(null);
const [authURL, setAuthURL] = useState<string | null>(null);
Expand Down Expand Up @@ -62,7 +64,7 @@ export const LoginPage: FC = () => {
alignItems: 'center'
}}
>
<Typography variant="h2">Login</Typography>
<Typography variant="h2">{t('common.login')}</Typography>
<FormControl sx={{ m: 1 }}>
<Select
sx={{ width: 300, m: 1 }}
Expand All @@ -77,7 +79,7 @@ export const LoginPage: FC = () => {
))}
</Select>
<Button disabled={organization == null} variant="contained" onClick={loginRedirect}>
{organization ? 'Redirect to Organization Login' : 'Select an Organization to Login'}
{organization ? t('components.login.redirectToOrg') : t('components.login.selectOrg')}
</Button>
</FormControl>
</Box>
Expand Down
Loading