From 73ec6c2f464a24afcf7c9af8bc4e572fd5393c3f Mon Sep 17 00:00:00 2001 From: Felipe Belgine Date: Tue, 22 Oct 2024 16:46:25 -0400 Subject: [PATCH] feat: add application section, update translation files --- .../localization/en/create_protocol.json | 11 +- .../localization/en/protocol_generator.json | 8 +- .../src/atoms/ControlledInputField/index.tsx | 6 +- .../__tests__/ApplicationSection.test.tsx | 85 ++++++++++++ .../organisms/ApplicationSection/index.tsx | 83 ++++++++++++ .../src/pages/CreateProtocol/index.tsx | 121 +++++++----------- 6 files changed, 224 insertions(+), 90 deletions(-) create mode 100644 opentrons-ai-client/src/organisms/ApplicationSection/__tests__/ApplicationSection.test.tsx create mode 100644 opentrons-ai-client/src/organisms/ApplicationSection/index.tsx diff --git a/opentrons-ai-client/src/assets/localization/en/create_protocol.json b/opentrons-ai-client/src/assets/localization/en/create_protocol.json index 7d9beb05ea3..de5015cd1d1 100644 --- a/opentrons-ai-client/src/assets/localization/en/create_protocol.json +++ b/opentrons-ai-client/src/assets/localization/en/create_protocol.json @@ -1,8 +1,13 @@ { "application_title": "Application", - "application_scientific_dropdown_label": "What's your scientific application?", + "application_scientific_dropdown_title": "What's your scientific application?", "application_scientific_dropdown_placeholder": "Select an option", - "application_describe_label": "Describe what you are trying to do", - "application_describe_example": "Example: “The protocol performs automated liquid handling for Pierce BCA Protein Assay Kit to determine protein concentrations in various sample types, such as cell lysates and eluates of purification process.", + "basic_aliquoting": "Basic aliquoting", + "pcr": "PCR", + "other": "Other", + "application_other_title": "Other application", + "application_other_caption": "Example: “cherrypicking” or “serial dilution”", + "application_describe_title": "Describe what you are trying to do", + "application_describe_caption": "Example: “The protocol performs automated liquid handling for Pierce BCA Protein Assay Kit to determine protein concentrations in various sample types, such as cell lysates and eluates of purification process.", "section_confirm_button": "Confirm" } diff --git a/opentrons-ai-client/src/assets/localization/en/protocol_generator.json b/opentrons-ai-client/src/assets/localization/en/protocol_generator.json index adad193276e..dbe201a8b7f 100644 --- a/opentrons-ai-client/src/assets/localization/en/protocol_generator.json +++ b/opentrons-ai-client/src/assets/localization/en/protocol_generator.json @@ -42,11 +42,5 @@ "landing_page_button_new_protocol": "Create a new protocol", "landing_page_button_update_protocol": "Update an existing protocol", "prompt_preview_submit_button": "Submit prompt", - "prompt_preview_placeholder_message": "As you complete the sections on the left, your prompt will be built here. When all requirements are met you will be able to generate the protocol.", - "create_protocol_page_application_title": "Application", - "create_protocol_page_application_scientific_dropdown_label": "What's your scientific application?", - "create_protocol_page_application_scientific_dropdown_placeholder": "Select an option", - "create_protocol_page_application_describe_label": "Describe what you are trying to do", - "create_protocol_page_application_describe_example": "Example: “The protocol performs automated liquid handling for Pierce BCA Protein Assay Kit to determine protein concentrations in various sample types, such as cell lysates and eluates of purification process.", - "create_protocol_page_section_confirm_button": "Confirm" + "prompt_preview_placeholder_message": "As you complete the sections on the left, your prompt will be built here. When all requirements are met you will be able to generate the protocol." } diff --git a/opentrons-ai-client/src/atoms/ControlledInputField/index.tsx b/opentrons-ai-client/src/atoms/ControlledInputField/index.tsx index 71c95ccd14a..651b5d0caf2 100644 --- a/opentrons-ai-client/src/atoms/ControlledInputField/index.tsx +++ b/opentrons-ai-client/src/atoms/ControlledInputField/index.tsx @@ -7,6 +7,7 @@ import { import { Controller } from 'react-hook-form' interface ControlledInputFieldProps { + id?: string name: string rules?: any title?: string @@ -14,6 +15,7 @@ interface ControlledInputFieldProps { } export function ControlledInputField({ + id, name, rules, title, @@ -27,8 +29,8 @@ export function ControlledInputField({ { + const methods = useForm({ + defaultValues: {}, + }) + + return ( + + + + ) +} + +const render = (): ReturnType => { + return renderWithProviders(, { + i18nInstance: i18n, + }) +} + +describe('ApplicationSection', () => { + beforeEach(() => { + const { result } = renderHook(() => useFormContext()) + const methods = result.current + }) + + it('should render scientific application dropdown, describe input and confirm button', () => { + render() + + expect( + screen.getByText("What's your scientific application?") + ).toBeInTheDocument() + expect( + screen.getByText('Describe what you are trying to do') + ).toBeInTheDocument() + expect(screen.getByText('Confirm')).toBeInTheDocument() + }) + + it('should not render other application dropdown if Other option is not selected', () => { + render() + + expect(screen.queryByText('Other application')).not.toBeInTheDocument() + }) + + it('should render other application dropdown if Other option is selected', () => { + render() + + const applicationDropdown = screen.getByText('Select an option') + fireEvent.click(applicationDropdown) + + const otherOption = screen.getByText('Other') + fireEvent.click(otherOption) + + expect(screen.getByText('Other application')).toBeInTheDocument() + }) + + it('should enable confirm button when all fields are filled', async () => { + render() + + const applicationDropdown = screen.getByText('Select an option') + fireEvent.click(applicationDropdown) + + const basicAliquotingOption = screen.getByText('Basic aliquoting') + fireEvent.click(basicAliquotingOption) + + const describeInput = screen.getByRole('textbox') + fireEvent.change(describeInput, { target: { value: 'Test description' } }) + + const confirmButton = screen.getByRole('button') + await waitFor(() => expect(confirmButton).toBeEnabled()) + }) + + it('should disable confirm button when all fields are not filled', () => { + render() + + const confirmButton = screen.getByRole('button') + expect(confirmButton).toBeDisabled() + }) +}) diff --git a/opentrons-ai-client/src/organisms/ApplicationSection/index.tsx b/opentrons-ai-client/src/organisms/ApplicationSection/index.tsx new file mode 100644 index 00000000000..549d72f3e71 --- /dev/null +++ b/opentrons-ai-client/src/organisms/ApplicationSection/index.tsx @@ -0,0 +1,83 @@ +import { + DIRECTION_COLUMN, + DISPLAY_FLEX, + Flex, + JUSTIFY_FLEX_END, + LargeButton, + SPACING, +} from '@opentrons/components' +import { useFormContext } from 'react-hook-form' +import { useTranslation } from 'react-i18next' +import styled from 'styled-components' +import { ControlledDropdownMenu } from '../../atoms/ControlledDropdownMenu' +import { ControlledInputField } from '../../atoms/ControlledInputField' + +export const BASIC_ALIQUOTING = 'basic_aliquoting' +export const PCR = 'pcr' +export const OTHER = 'other' +export const APPLICATION_SCIENTIFIC_APPLICATION = + 'application.scientificApplication' +export const APPLICATION_OTHER_APPLICATION = 'application.otherApplication' +export const APPLICATION_DESCRIBE = 'application.describe' + +export function ApplicationSection(): JSX.Element | null { + const { t } = useTranslation('create_protocol') + const { + watch, + formState: { isValid }, + } = useFormContext() + + const options = [ + { name: t(BASIC_ALIQUOTING), value: BASIC_ALIQUOTING }, + { name: t(PCR), value: PCR }, + { name: t(OTHER), value: OTHER }, + ] + + const isOtherSelected = watch(APPLICATION_SCIENTIFIC_APPLICATION) === OTHER + + return ( + + + + {isOtherSelected && ( + + )} + + + + + + + + ) +} + +const ButtonContainer = styled.div` + display: ${DISPLAY_FLEX}; + justify-content: ${JUSTIFY_FLEX_END}; +` diff --git a/opentrons-ai-client/src/pages/CreateProtocol/index.tsx b/opentrons-ai-client/src/pages/CreateProtocol/index.tsx index fc58bda0bcb..12e7cd1f9a2 100644 --- a/opentrons-ai-client/src/pages/CreateProtocol/index.tsx +++ b/opentrons-ai-client/src/pages/CreateProtocol/index.tsx @@ -1,24 +1,24 @@ import { DIRECTION_COLUMN, - DISPLAY_FLEX, - DropdownMenu, Flex, - InputField, - JUSTIFY_FLEX_END, JUSTIFY_SPACE_EVENLY, - LargeButton, POSITION_RELATIVE, SPACING, - StyledText, } from '@opentrons/components' import { useTranslation } from 'react-i18next' import { Accordion } from '../../molecules/Accordion' import { useState } from 'react' import styled from 'styled-components' import { PromptPreview } from '../../molecules/PromptPreview' +import { ApplicationSection } from '../../organisms/ApplicationSection' +import { useForm, FormProvider } from 'react-hook-form' -export interface InputType { - userPrompt: string +interface CreateProtocolFormData { + application: { + scientificApplication: string + otherApplication?: string + description: string + } } export function CreateProtocol(): JSX.Element | null { @@ -27,67 +27,44 @@ export function CreateProtocol(): JSX.Element | null { true ) + const methods = useForm({ + defaultValues: { + application: { + scientificApplication: '', + otherApplication: '', + description: '', + }, + }, + }) + return ( - - - + + + + + + + - - - - {t('application_scientific_dropdown_label')} - - - - - - - {t('application_describe_label')} - - - - {t('application_describe_example')} - - - - - - - - - - - + promptPreviewData={[]} + /> + + ) } @@ -95,15 +72,3 @@ const ProtocolSections = styled(Flex)` flex-direction: ${DIRECTION_COLUMN}; width: 100%; ` - -const ButtonContainer = styled.div` - display: ${DISPLAY_FLEX}; - justify-content: ${JUSTIFY_FLEX_END}; -` - -const FormField = styled.div` - display: ${DISPLAY_FLEX}; - flex-direction: ${DIRECTION_COLUMN}; - gap: ${SPACING.spacing4}; - margin-bottom: ${SPACING.spacing16}; -`