-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(opentrons-ai-client): Created an update protocol page (#16569)
…ol page basic layout <!-- Thanks for taking the time to open a Pull Request (PR)! Please make sure you've read the "Opening Pull Requests" section of our Contributing Guide: https://github.com/Opentrons/opentrons/blob/edge/CONTRIBUTING.md#opening-pull-requests GitHub provides robust markdown to format your PR. Links, diagrams, pictures, and videos along with text formatting make it possible to create a rich and informative PR. For more information on GitHub markdown, see: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax To ensure your code is reviewed quickly and thoroughly, please fill out the sections below to the best of your ability! --> # Overview Added a new page that allows us to upload an existing protocol for modification. It has error states for file size is zero and when uploading a non-python file. Drop down options are: const updateOptions: DropdownOption[] = [ { name: 'Adapt Python protocol from OT-2 to Flex', value: 'adapt_python_protocol', }, { name: 'Change labware', value: 'change_labware' }, { name: 'Change pipettes', value: 'change_pipettes' }, { name: 'Other', value: 'other' }, ] START STATE: <img width="755" alt="image" src="https://github.com/user-attachments/assets/615d4a89-d998-4be5-95a2-0e792565f20c"> EMPTY FILE: <img width="1503" alt="image" src="https://github.com/user-attachments/assets/068ee486-6cde-4ca9-9b76-f9b401f46de5"> NON-PYTHON FILE: <img width="1503" alt="image" src="https://github.com/user-attachments/assets/daf2ba25-3a0f-469e-8683-5bc9b074108d"> ALL FIELDS FILLED OUT: <img width="1508" alt="image" src="https://github.com/user-attachments/assets/107e4d63-8243-4962-b1e6-6f345eef3471"> <!-- Describe your PR at a high level. State acceptance criteria and how this PR fits into other work. Link issues, PRs, and other relevant resources. --> ## Test Plan and Hands on Testing Tested non python files and empty python files. Made sure the prompt text is correctly modified to include the fields filled out. <!-- Describe your testing of the PR. Emphasize testing not reflected in the code. Attach protocols, logs, screenshots and any other assets that support your testing. --> ## Changelog <!-- List changes introduced by this PR considering future developers and the end user. Give careful thought and clear documentation to breaking changes. --> ## Review requests <!-- - What do you need from reviewers to feel confident this PR is ready to merge? - Ask questions. --> ## Risk assessment <!-- - Indicate the level of attention this PR needs. - Provide context to guide reviewers. - Discuss trade-offs, coupling, and side effects. - Look for the possibility, even if you think it's small, that your change may affect some other part of the system. - For instance, changing return tip behavior may also change the behavior of labware calibration. - How do your unit tests and on hands on testing mitigate this PR's risks and the risk of future regressions? - Especially in high risk PRs, explain how you know your testing is enough. --> --------- Co-authored-by: FELIPE BELGINE <[email protected]>
- Loading branch information
1 parent
f66ffb9
commit 06cde70
Showing
12 changed files
with
732 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { css } from 'styled-components' | ||
|
||
import { | ||
ALIGN_CENTER, | ||
BORDERS, | ||
Btn, | ||
COLORS, | ||
DIRECTION_COLUMN, | ||
Flex, | ||
Icon, | ||
JUSTIFY_SPACE_BETWEEN, | ||
SPACING, | ||
LegacyStyledText, | ||
truncateString, | ||
} from '@opentrons/components' | ||
|
||
const FILE_UPLOAD_STYLE = css` | ||
&:hover > svg { | ||
background: ${COLORS.black90}${COLORS.opacity20HexCode}; | ||
} | ||
&:active > svg { | ||
background: ${COLORS.black90}${COLORS.opacity20HexCode}}; | ||
} | ||
` | ||
|
||
const FILE_UPLOAD_FOCUS_VISIBLE = css` | ||
&:focus-visible { | ||
border-radius: ${BORDERS.borderRadius4}; | ||
box-shadow: 0 0 0 ${SPACING.spacing2} ${COLORS.blue50}; | ||
} | ||
` | ||
|
||
interface FileUploadProps { | ||
file: File | ||
fileError: string | null | ||
handleClick: () => unknown | ||
} | ||
|
||
export function FileUpload({ | ||
file, | ||
fileError, | ||
handleClick, | ||
}: FileUploadProps): JSX.Element { | ||
return ( | ||
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing4}> | ||
<Btn | ||
onClick={handleClick} | ||
aria-label="remove_file" | ||
css={FILE_UPLOAD_FOCUS_VISIBLE} | ||
> | ||
<Flex | ||
alignItems={ALIGN_CENTER} | ||
backgroundColor={fileError == null ? COLORS.grey20 : COLORS.red30} | ||
borderRadius={BORDERS.borderRadius4} | ||
height={SPACING.spacing44} | ||
justifyContent={JUSTIFY_SPACE_BETWEEN} | ||
padding={SPACING.spacing8} | ||
css={FILE_UPLOAD_STYLE} | ||
> | ||
<LegacyStyledText as="p"> | ||
{truncateString(file.name, 34, 19)} | ||
</LegacyStyledText> | ||
<Icon name="close" size="1.5rem" borderRadius="50%" /> | ||
</Flex> | ||
</Btn> | ||
{fileError != null ? ( | ||
<LegacyStyledText as="label" color={COLORS.red50}> | ||
{fileError} | ||
</LegacyStyledText> | ||
) : null} | ||
</Flex> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
168 changes: 168 additions & 0 deletions
168
opentrons-ai-client/src/molecules/UploadInput/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import * as React from 'react' | ||
import styled, { css } from 'styled-components' | ||
import { useTranslation } from 'react-i18next' | ||
import { | ||
ALIGN_CENTER, | ||
BORDERS, | ||
COLORS, | ||
CURSOR_POINTER, | ||
DIRECTION_COLUMN, | ||
DISPLAY_FLEX, | ||
Flex, | ||
Icon, | ||
JUSTIFY_CENTER, | ||
LegacyStyledText, | ||
POSITION_FIXED, | ||
PrimaryButton, | ||
SPACING, | ||
TYPOGRAPHY, | ||
} from '@opentrons/components' | ||
|
||
const StyledLabel = styled.label` | ||
display: ${DISPLAY_FLEX}; | ||
cursor: ${CURSOR_POINTER}; | ||
flex-direction: ${DIRECTION_COLUMN}; | ||
align-items: ${ALIGN_CENTER}; | ||
width: 100%; | ||
padding: ${SPACING.spacing32}; | ||
border: 2px dashed ${COLORS.grey30}; | ||
border-radius: ${BORDERS.borderRadius4}; | ||
text-align: ${TYPOGRAPHY.textAlignCenter}; | ||
background-color: ${COLORS.white}; | ||
&:hover { | ||
border: 2px dashed ${COLORS.blue50}; | ||
} | ||
` | ||
const DRAG_OVER_STYLES = css` | ||
border: 2px dashed ${COLORS.blue50}; | ||
` | ||
|
||
const StyledInput = styled.input` | ||
position: ${POSITION_FIXED}; | ||
clip: rect(1px 1px 1px 1px); | ||
` | ||
|
||
export interface UploadInputProps { | ||
/** Callback function that is called when a file is uploaded. */ | ||
onUpload: (file: File) => unknown | ||
/** Optional callback function that is called when the upload button is clicked. */ | ||
onClick?: () => void | ||
/** Optional text for the upload button. If undefined, the button displays Upload */ | ||
uploadButtonText?: string | ||
/** Optional text or JSX element that is displayed above the upload button. */ | ||
uploadText?: string | JSX.Element | ||
/** Optional text or JSX element that is displayed in the drag and drop area. */ | ||
dragAndDropText?: string | JSX.Element | ||
} | ||
|
||
export function UploadInput(props: UploadInputProps): JSX.Element | null { | ||
const { | ||
dragAndDropText, | ||
onClick, | ||
onUpload, | ||
uploadButtonText, | ||
uploadText, | ||
} = props | ||
const { t } = useTranslation('protocol_info') | ||
|
||
const fileInput = React.useRef<HTMLInputElement>(null) | ||
const [isFileOverDropZone, setIsFileOverDropZone] = React.useState<boolean>( | ||
false | ||
) | ||
const [isHover, setIsHover] = React.useState<boolean>(false) | ||
const handleDrop: React.DragEventHandler<HTMLLabelElement> = e => { | ||
e.preventDefault() | ||
e.stopPropagation() | ||
Array.from(e.dataTransfer.files).forEach(f => onUpload(f)) | ||
setIsFileOverDropZone(false) | ||
} | ||
const handleDragEnter: React.DragEventHandler<HTMLLabelElement> = e => { | ||
e.preventDefault() | ||
e.stopPropagation() | ||
} | ||
const handleDragLeave: React.DragEventHandler<HTMLLabelElement> = e => { | ||
e.preventDefault() | ||
e.stopPropagation() | ||
setIsFileOverDropZone(false) | ||
setIsHover(false) | ||
} | ||
const handleDragOver: React.DragEventHandler<HTMLLabelElement> = e => { | ||
e.preventDefault() | ||
e.stopPropagation() | ||
setIsFileOverDropZone(true) | ||
setIsHover(true) | ||
} | ||
|
||
const handleClick: React.MouseEventHandler<HTMLButtonElement> = _event => { | ||
onClick != null ? onClick() : fileInput.current?.click() | ||
} | ||
|
||
const onChange: React.ChangeEventHandler<HTMLInputElement> = event => { | ||
;[...(event.target.files ?? [])].forEach(f => onUpload(f)) | ||
if ('value' in event.currentTarget) event.currentTarget.value = '' | ||
} | ||
|
||
return ( | ||
<Flex | ||
height="100%" | ||
flexDirection={DIRECTION_COLUMN} | ||
justifyContent={JUSTIFY_CENTER} | ||
alignItems={ALIGN_CENTER} | ||
gridGap={SPACING.spacing24} | ||
> | ||
{uploadText != null ? ( | ||
<> | ||
{typeof uploadText === 'string' ? ( | ||
<LegacyStyledText | ||
as="p" | ||
textAlign={TYPOGRAPHY.textAlignCenter} | ||
marginTop={SPACING.spacing16} | ||
> | ||
{uploadText} | ||
</LegacyStyledText> | ||
) : ( | ||
<>{uploadText}</> | ||
)} | ||
</> | ||
) : null} | ||
<PrimaryButton | ||
onClick={handleClick} | ||
id="UploadInput_protocolUploadButton" | ||
> | ||
{uploadButtonText ?? t('upload')} | ||
</PrimaryButton> | ||
|
||
<StyledLabel | ||
data-testid="file_drop_zone" | ||
onDrop={handleDrop} | ||
onDragOver={handleDragOver} | ||
onDragEnter={handleDragEnter} | ||
onDragLeave={handleDragLeave} | ||
onMouseEnter={() => { | ||
setIsHover(true) | ||
}} | ||
onMouseLeave={() => { | ||
setIsHover(false) | ||
}} | ||
css={isFileOverDropZone ? DRAG_OVER_STYLES : undefined} | ||
> | ||
<Icon | ||
width="4rem" | ||
color={isHover ? COLORS.blue50 : COLORS.grey60} | ||
name="upload" | ||
marginBottom={SPACING.spacing24} | ||
/> | ||
{dragAndDropText} | ||
<StyledInput | ||
id="file_input" | ||
data-testid="file_input" | ||
ref={fileInput} | ||
type="file" | ||
onChange={onChange} | ||
multiple | ||
/> | ||
</StyledLabel> | ||
</Flex> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.