Skip to content

feature(opentrons-ai-client): Attach file #18886

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

Open
wants to merge 19 commits into
base: edge
Choose a base branch
from

Conversation

Elyorcv
Copy link
Contributor

@Elyorcv Elyorcv commented Jul 11, 2025

Overview

Closes AUTH-2019
Figma

This introduces attach file button and attachments and send button modification
With Attach file button

image

With Attachment
image

After Send

image

Test Plan and Hands on Testing

CI

Review requests

Make sure Attach file and Send button and attachments are visible in UI

Risk assessment

Mid

@Elyorcv Elyorcv force-pushed the AUTH-2019-chat-interface-add-the-ability-to-attach-files branch from f635cf7 to c931478 Compare July 11, 2025 15:25
@Elyorcv Elyorcv marked this pull request as ready for review July 11, 2025 16:05
@Elyorcv Elyorcv requested review from koji and jerader July 11, 2025 16:32
Copy link
Collaborator

@jerader jerader left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code generally looks good! left some comments and questions. I think the big thing is to try to use CSS modules instead of styled-components, if possible 😄

@Elyorcv Elyorcv requested a review from a team as a code owner July 13, 2025 16:14
Copy link

codecov bot commented Jul 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 56.51%. Comparing base (ced0e9e) to head (a69df4f).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             edge   #18886       +/-   ##
===========================================
+ Coverage   25.38%   56.51%   +31.12%     
===========================================
  Files        3333     3333               
  Lines      287696   287767       +71     
  Branches    36490    36628      +138     
===========================================
+ Hits        73040   162633    +89593     
+ Misses     214633   124927    -89706     
- Partials       23      207      +184     
Flag Coverage Δ
app 47.44% <100.00%> (+44.56%) ⬆️
protocol-designer 19.00% <100.00%> (+<0.01%) ⬆️
step-generation 5.31% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
components/src/icons/icon-data.ts 100.00% <100.00%> (ø)

... and 1662 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Elyorcv Elyorcv force-pushed the AUTH-2019-chat-interface-add-the-ability-to-attach-files branch 3 times, most recently from fde7150 to bf78909 Compare July 13, 2025 20:07
Copy link
Collaborator

@jerader jerader left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left another round of feedback. it is looking great - thanks for using CSS modules!

@Elyorcv Elyorcv force-pushed the AUTH-2019-chat-interface-add-the-ability-to-attach-files branch from fcd8e5a to a69df4f Compare July 14, 2025 22:38
@@ -0,0 +1,47 @@
.button {
Copy link
Contributor

@koji koji Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I posted to #frontend, we decided to use lower case to the module.css file name.
could you rename this to attachfilebutton.module.css?

@@ -0,0 +1,53 @@
.button {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as AttachFileButton.module.css

@@ -0,0 +1,146 @@
.main_container {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to change the file name

@@ -0,0 +1,86 @@
.form {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to change the file name

background-color: var(--white);
border: none;
outline: none;
padding: 1.2rem 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.2 rem is not our regular spacing var. is this a special case?

font-weight: var(--font-weight-regular);
line-height: var(--line-height-20);
font-family: 'Public Sans', sans-serif;
font-style: normal;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need this?

if you remove this, what will you see in the dev tools?

border: 1px solid var(--grey-20);
border-radius: var(--border-radius-12);
background-color: var(--white);
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.05);
Copy link
Contributor

@koji koji Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from our codebase, the team is using px for box-shadow so i recommend you use px instead of rem.
I'll going to add this to the migration doc.


.main_input_container:focus-within {
border-color: var(--blue-50);
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as the above

}

.text_input_section {
padding: var(--spacing-16) var(--spacing-16) var(--spacing-4) var(--spacing-16);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
padding: var(--spacing-16) var(--spacing-16) var(--spacing-4) var(--spacing-16);
padding: var(--spacing-16) var(--spacing-16) var(--spacing-4);

Comment on lines +58 to +59
const sendButton = screen.getByRole('button', { name: 'Send' })
expect(sendButton).toBeDisabled()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

basically we define button const when we will need to check its existence + sytle/click action.

Suggested change
const sendButton = screen.getByRole('button', { name: 'Send' })
expect(sendButton).toBeDisabled()
expect(screen.getByRole('button', { name: 'Send' })).toBeDisabled()

attachedFiles.length > 0
? attachedFiles.map(file => ({
name: file.name,
type: getFileType(file) as 'pdf' | 'csv' | 'python',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit
define type like FileType something ?

{/* Error message */}
{fileError && (
<div className={styles.error_container}>
<StyledText color={COLORS.red50} fontSize={TYPOGRAPHY.fontSizeH3}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this way, probably adding lineHeight would be good for the migration.

Comment on lines +382 to +384
handleClick={() => {
handleClick()
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not work?

Suggested change
handleClick={() => {
handleClick()
}}
handleClick={handleClick}

i think the prop name I named isn't good. i will open a pr to mofity that.

Comment on lines +20 to +22
pdf: 10 * 1024 * 1024, // 10MB
csv: 2 * 1024 * 1024, // 2MB
python: 1 * 1024 * 1024, // 1MB
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just out of curiosity—how did you decide on the size?

@@ -7,6 +7,13 @@ export type ProtocolFormat = 'Protocol Designer' | 'Python'
/** assistant: ChatGPT API, user: user */
type Role = 'assistant' | 'user'

export interface FileAttachment {
name: string
type: 'pdf' | 'csv' | 'python'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need unknown?

python: ['.py'],
} as const

export type FileType = 'pdf' | 'csv' | 'python' | 'unknown'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import type { FileAttachment } from 
export type FileType = FileAttachment['type'] | 'unknown'

or may move this type to types.ts since it is exported.


const sizeLimit = FILE_SIZE_LIMITS[fileType]
if (file.size > sizeLimit) {
const sizeMB = Math.round(sizeLimit / (1024 * 1024))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

const UNIT_MB = 1024 * 1024 

export const FILE_SIZE_LIMITS = {
  pdf: 10 * UNIT_MB, // 10MB
  csv: 2 * UNIT_MB, // 2MB
  python: 1 * UNIT_MB, // 1MB
}


const sizeMB = Math.round(sizeLimit / (UNIT_MB))

Comment on lines +66 to +77
export const getFileTypeLabel = (type: FileType): string => {
switch (type) {
case 'pdf':
return 'PDF file'
case 'csv':
return 'CSV file'
case 'python':
return 'Python file'
default:
return 'File'
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit
you can use map

const fileTypeLabels: Record<FileType, string> = {
  pdf: 'PDF file',
  csv: 'CSV file',
  python: 'Python file',
  unknown: 'File',
}

export const getFileTypeLabel = (type: FileType): string => fileTypeLabels[type]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if possible, i recommend you use a different string for unknonw since there is a type, File.


export const formatFileSize = (bytes: number): string => {
if (bytes === 0) {
return '0 B'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the space between B and 0 is intentinal?

const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))

return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`
const size = bytes / Math.pow(k, i)
const rounded = size.toFixed(1)
return `${rounded} ${sizes[i] ?? 'B'}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants