Skip to content

Commit

Permalink
Merge pull request #232 from tnc-ca-geo/freeze-project-label-names
Browse files Browse the repository at this point in the history
Make `ProjectLabel.names` read-only for ML-generated labels
  • Loading branch information
nathanielrindlaub authored Aug 16, 2024
2 parents 5189331 + 977cab4 commit d4b2542
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/api/buildQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ const projectLabelFields = `
name
color
reviewerEnabled
ml
`;

const projectFields = `
Expand Down
1 change: 1 addition & 0 deletions src/components/Modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const ModalBody = styled('div', {
minHeight: '$7',
maxHeight: 'calc(95vh - $7)',
overflowY: 'scroll',
overflowX: 'hidden',
position: 'relative',
});

Expand Down
51 changes: 29 additions & 22 deletions src/features/projects/AddAutomationRuleForm.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { styled } from '../../theme/stitches.config.js';
import _ from 'lodash';
import { Formik, Form, Field, FieldArray, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { updateAutomationRules, selectMLModels, fetchModels } from './projectsSlice.js';
import SelectField from '../../components/SelectField.jsx';
import Button from '../../components/Button.jsx';
import { FormWrapper, FieldRow, ButtonRow, FormFieldWrapper, FormError } from '../../components/Form.jsx';
import {
FormWrapper,
FieldRow,
ButtonRow,
FormFieldWrapper,
FormError,
} from '../../components/Form.jsx';
import CategoryConfigForm from './CategoryConfigForm.jsx';

const CategoryConfigSection = styled('div', {
maxHeight: '220px',
overflowY: 'scroll',
});

const emptyRule = {
name: '',
event: {
Expand Down Expand Up @@ -145,7 +145,11 @@ const AddAutomationRuleForm = ({ project, availableModels, hideAddRuleForm, rule
{values.event.type.value === 'label-added' && (
<FormFieldWrapper css={{ flexGrow: '0' }}>
<label htmlFor="event-label">Label</label>
<Field id="event-label" name="event.label" value={values.event.label ? values.event.label : ''} />
<Field
id="event-label"
name="event.label"
value={values.event.label ? values.event.label : ''}
/>
<ErrorMessage component={FormError} name="event.label" />
</FormFieldWrapper>
)}
Expand All @@ -157,6 +161,7 @@ const AddAutomationRuleForm = ({ project, availableModels, hideAddRuleForm, rule
<SelectField
name="action.type"
label="Action"
menuPlacement="top"
value={values.action.type}
onChange={(name, value) => {
setFieldValue(name, value);
Expand All @@ -181,6 +186,7 @@ const AddAutomationRuleForm = ({ project, availableModels, hideAddRuleForm, rule
<SelectField
name="action.model"
label="Model"
menuPlacement="top"
value={values.action.model}
onChange={(name, value) => {
setFieldValue(name, value);
Expand Down Expand Up @@ -220,20 +226,21 @@ const AddAutomationRuleForm = ({ project, availableModels, hideAddRuleForm, rule
</FieldRow>

{/* category configurations */}
{values.action.categoryConfig && Object.entries(values.action.categoryConfig).length > 0 && (
<CategoryConfigSection>
<label>Confidence thresholds</label>
<FieldArray name="categoryConfigs">
<>
{Object.entries(values.action.categoryConfig)
.filter(([k]) => k !== 'empty') // NOTE: manually hiding "empty" categories b/c it isn't a real category returned by MDv5
.map(([k, v]) => (
<CategoryConfigForm key={k} catName={k} config={v} />
))}
</>
</FieldArray>
</CategoryConfigSection>
)}
{values.action.categoryConfig &&
Object.entries(values.action.categoryConfig).length > 0 && (
<div>
<label>Confidence thresholds</label>
<FieldArray name="categoryConfigs">
<>
{Object.entries(values.action.categoryConfig)
.filter(([k]) => k !== 'empty') // NOTE: manually hiding "empty" categories b/c it isn't a real category returned by MDv5
.map(([k, v]) => (
<CategoryConfigForm key={k} catName={k} config={v} />
))}
</>
</FieldArray>
</div>
)}

<ButtonRow>
<Button type="button" size="large" onClick={handleDiscardRuleClick}>
Expand Down
7 changes: 4 additions & 3 deletions src/features/projects/ManageLabelsModal/EditLabelForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ const DisabledIndicator = styled('span', {
});

const EditLabelForm = ({ label, labels, setLabelToDelete, setAlertOpen }) => {
const { _id, name, color, reviewerEnabled } = label;
const { _id, name, color, reviewerEnabled, ml } = label;
const dispatch = useDispatch();
const [showForm, setShowForm] = useState(false);

const toggleOpenForm = useCallback(() => setShowForm((prev) => !prev), []);
const onSubmit = useCallback((values) => {
const onSubmit = useCallback((values, { resetForm }) => {
dispatch(updateProjectLabel(values));
setShowForm(false);
resetForm();
}, []);

const deleteLabel = useCallback((values) => {
Expand Down Expand Up @@ -59,7 +60,7 @@ const EditLabelForm = ({ label, labels, setLabelToDelete, setAlertOpen }) => {
return (
<Formik
enableReinitialize
initialValues={{ _id, name, color, reviewerEnabled }}
initialValues={{ _id, name, color, reviewerEnabled, ml }}
validationSchema={schema(name)}
onSubmit={onSubmit}
>
Expand Down
60 changes: 53 additions & 7 deletions src/features/projects/ManageLabelsModal/LabelForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ import { Form, Field, useFormikContext } from 'formik';
import Button from '../../../components/Button';
import IconButton from '../../../components/IconButton.jsx';
import InfoIcon from '../../../components/InfoIcon';
import { SymbolIcon } from '@radix-ui/react-icons';
import { LockClosedIcon, SymbolIcon } from '@radix-ui/react-icons';
import { SwitchRoot, SwitchThumb } from '../../../components/Switch.jsx';
import { Tooltip, TooltipContent, TooltipArrow, TooltipTrigger } from '../../../components/Tooltip.jsx';
import {
Tooltip,
TooltipContent,
TooltipArrow,
TooltipTrigger,
} from '../../../components/Tooltip.jsx';
import { FormWrapper, FormFieldWrapper, FormError } from '../../../components/Form';
import { FormRow, FormButtons, ColorPicker } from './components';
import { getRandomColor, getTextColor } from '../../../app/utils.js';
Expand All @@ -18,13 +23,14 @@ const LabelForm = ({ onCancel }) => {
<FormWrapper>
<Form>
<FormRow>
<FormFieldWrapper>
<FormFieldWrapper css={{ position: 'relative' }}>
<label htmlFor="name">Name</label>
<Field name="name" id="name" />
<Field name="name" id="name" disabled={values.ml} />
{values.ml && <LabelLockOverlay />}
{!!errors.name && touched.name && <FormError>{errors.name}</FormError>}
</FormFieldWrapper>
<FormFieldWrapper>
<label htmlFor="name">Color</label>
<label htmlFor="color">Color</label>
<ColorPicker>
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -152,9 +158,49 @@ const ColorSwatch = styled('button', {

const ReviewerEnabledHelp = () => (
<div style={{ maxWidth: '200px' }}>
Disabling a label will prevent users from applying it to images going forward, but it will not remove existing
instances of the label on your images.
Disabling a label will prevent users from applying it to images going forward, but it will not
remove existing instances of the label on your images.
</div>
);

const LockIcon = styled(LockClosedIcon, {
marginLeft: '$2',
marginRight: '$2',
});

const Overlay = styled('div', {
position: 'absolute',
color: '$textMedium',
height: '53px',
width: '176px',
top: '30px',
left: '1px',
padding: '$1',
borderRadius: '$1',
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
});

const LabelLockOverlay = () => (
<Tooltip>
<TooltipTrigger asChild>
<Overlay>
<LockIcon />
</Overlay>
</TooltipTrigger>
<TooltipContent
side="top"
sideOffset={5}
css={{
maxWidth: 324,
}}
>
You can&apos;t edit this label&apos;s name because it is managed by a machine learning model,
but you can change it&apos;s color and enable/disable it.
<TooltipArrow />
</TooltipContent>
</Tooltip>
);

export default LabelForm;

0 comments on commit d4b2542

Please sign in to comment.