Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AI Assisted Translation to Engagement Column and Detail Page #1627

Merged
merged 7 commits into from
Jan 8, 2025
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
18 changes: 7 additions & 11 deletions src/components/BooleanProperty/BooleanProperty.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Chip, ChipProps, Skeleton } from '@mui/material';
import { styled } from '@mui/material/styles';
import { ReactElement } from 'react';
import { makeStyles } from 'tss-react/mui';
import { Except, SetRequired } from 'type-fest';
import { SecuredProp } from '~/common';
import { Redacted } from '../Redacted';
Expand All @@ -11,13 +11,11 @@ export interface BooleanPropertyProps extends SetRequired<ChipProps, 'label'> {
wrap?: (node: ReactElement) => ReactElement;
}

const useStyles = makeStyles()(({ palette, shape }) => ({
root: {
background: palette.info.main,
color: palette.info.contrastText,
borderRadius: shape.borderRadius,
height: 26,
},
const StyledChip = styled(Chip)(({ theme }) => ({
background: theme.palette.info.main,
color: theme.palette.info.contrastText,
borderRadius: theme.shape.borderRadius,
height: 26,
}));

export const BooleanProperty = ({
Expand All @@ -26,9 +24,7 @@ export const BooleanProperty = ({
wrap,
...rest
}: BooleanPropertyProps) => {
const { classes } = useStyles();

const chip = <Chip {...rest} className={classes.root} />;
const chip = <StyledChip {...rest} />;

const out = !data ? (
<Skeleton>{chip}</Skeleton>
Expand Down
11 changes: 11 additions & 0 deletions src/components/EngagementDataGrid/EngagementColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ export const EngagementColumns: Array<GridColDef<Engagement>> = [
: null,
filterable: false,
},
{
headerName: 'AI Assist',
description: 'Is using AI assistance in translation?',
field: 'usingAIAssistedTranslation',
...booleanColumn(),
valueGetter: (_, row) =>
row.__typename === 'LanguageEngagement'
? row.usingAIAssistedTranslation.value
: null,
filterable: false,
},
{
headerName: 'Type',
field: 'project.type',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ fragment engagementDataGridRow on Engagement {
milestoneReached {
value
}
...aiAssistedTranslation
language {
value {
id
Expand Down
7 changes: 7 additions & 0 deletions src/components/Grid/booleanColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Check as CheckIcon, Close as CloseIcon } from '@mui/icons-material';
import { GridColDef } from '@mui/x-data-grid';
import { GridFilterInputBoolean } from './GridFilterInputBoolean';

Expand All @@ -21,4 +22,10 @@ export const booleanColumn = () =>
InputComponent: GridFilterInputBoolean,
},
],
renderCell: ({ value }) =>
value ? (
<CheckIcon color="success" />
) : value === false ? (
<CloseIcon color="error" />
) : null,
} satisfies Partial<GridColDef>);
8 changes: 4 additions & 4 deletions src/components/form/EnumField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ export const EnumField = <
(): Set<T> | T | null =>
multiple
? new Set(input.value as readonly T[])
: ((input.value || defaultValue) as T | null),
: ((input.value ?? defaultValue) as T | null),
// eslint-disable-next-line react-hooks/exhaustive-deps,@typescript-eslint/no-unnecessary-condition
[input.value ? sortBy(many(input.value ?? '')).join('') : undefined]
[input.value != null ? sortBy(many(input.value ?? '')).join('') : undefined]
);

const isChecked = useCallback(
Expand All @@ -169,7 +169,7 @@ export const EnumField = <
const current = value as Set<T>;
return optionVal ? current.has(optionVal) : current.size === 0;
}
if (!optionVal || optionVal === (defaultValue as T | null)) {
if (optionVal == null || optionVal === (defaultValue as T | null)) {
return value === defaultValue;
}
return value === optionVal;
Expand All @@ -179,7 +179,7 @@ export const EnumField = <

const onOptionChange = useCallback(
(optionVal: T | undefined, checked: boolean) => {
if (!optionVal) {
if (optionVal == null) {
onChange(defaultValue);
return;
}
Expand Down
17 changes: 17 additions & 0 deletions src/components/form/TriStateBooleanField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { EnumField, EnumFieldProps } from './EnumField';

export type TriStateBooleanProps = Omit<
EnumFieldProps<string, false>,
'children' | 'options'
> & {
options?: Array<boolean | null>;
getLabel?: (v: boolean | null) => string;
};

export const TriStateBooleanField = (props: TriStateBooleanProps) => (
<EnumField
options={[true, false, null] as any}
getLabel={(v: any) => (v ? 'Yes' : v === false ? 'No' : 'Unknown')}
{...props}
/>
);
1 change: 1 addition & 0 deletions src/components/form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './DateField';
export * from './Dropzone';
export * from './EmailField';
export * from './EnumField';
export * from './TriStateBooleanField';
export * from './FieldGroup';
export * from './FormattedTextField';
export * from './NumberField';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
SecuredField,
SubmitError,
TextField,
TriStateBooleanField,
} from '../../../components/form';
import { AutocompleteField } from '../../../components/form/AutocompleteField';
import {
Expand Down Expand Up @@ -62,6 +63,7 @@ export type EditableEngagementField = ExtractStrict<
| 'lukePartnership'
| 'paratextRegistryId'
| 'openToInvestorVisit'
| 'usingAIAssistedTranslation'
>;

interface EngagementFieldProps {
Expand Down Expand Up @@ -153,6 +155,9 @@ const fieldMapping: Record<
paratextRegistryId: ({ props }) => (
<TextField {...props} label="Paratext Registry ID" />
),
usingAIAssistedTranslation: ({ props }) => (
<TriStateBooleanField {...props} label="AI Assisted Translation" />
),
};

interface EngagementFormValues {
Expand Down Expand Up @@ -222,6 +227,8 @@ export const EditEngagementDialog = ({
firstScripture: engagement.firstScripture.value,
paratextRegistryId: engagement.paratextRegistryId.value,
openToInvestorVisit: engagement.openToInvestorVisit.value,
usingAIAssistedTranslation:
engagement.usingAIAssistedTranslation.value,
}
: {
methodologies: engagement.methodologies.value,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fragment aiAssistedTranslation on LanguageEngagement {
...Id
usingAIAssistedTranslation {
canRead
canEdit
value
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const LanguageEngagementHeader = ({
'firstScripture',
'lukePartnership',
'openToInvestorVisit',
'usingAIAssistedTranslation',
])
}
>
Expand Down Expand Up @@ -162,6 +163,13 @@ export const LanguageEngagementHeader = ({
empty="Enter Paratext Registry ID"
/>
</Grid>
<BooleanProperty
label="AI Assisted Translation"
redacted="You do not have permission to view whether this engagement is using AI assistance"
data={engagement.usingAIAssistedTranslation}
wrap={(node) => <Grid item>{node}</Grid>}
sx={{ backgroundColor: 'warning.main' }}
/>
<BooleanProperty
label="First Scripture"
redacted="You do not have permission to view whether this engagement is the first scripture for this language"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ fragment LanguageEngagementDetail on LanguageEngagement {
...LanguageEngagementDatesForm
...EngagementDescription
...engagementMilestoneReached
...aiAssistedTranslation
ceremony {
...CeremonyCard
}
Expand Down
Loading