-
文章 · 2025年07月05日
如何使用Flex平臺(tái)完成NGS文庫(kù)建庫(kù)全過(guò)程?
閱讀全文 -
文章 · 2025年07月05日
Flex NGS工作站支持哪些建庫(kù)自動(dòng)化流程?
閱讀全文 -
文章 · 2025年07月04日
Flex平臺(tái)功能解析:遠(yuǎn)程監(jiān)控、流程記錄與異常警報(bào)全覆蓋
閱讀全文
此功能升級(jí)直接來(lái)自客戶反饋。 謝謝你! 我們很高興聽(tīng)到您的想法——請(qǐng)繼續(xù)提出!
當(dāng)協(xié)議設(shè)計(jì)器 (PD) 首次創(chuàng)建時(shí),Opentrons 設(shè)想了一個(gè)平臺(tái),科學(xué)家可以在其中快速構(gòu)建基本的移液協(xié)議,而無(wú)需編寫(xiě)任何代碼。 隨著 PD 越來(lái)越多地被我們社區(qū)所利用,它成為一種工具,使科學(xué)家能夠構(gòu)建冗長(zhǎng)而復(fù)雜的方案,以解決 DNA 提取、蛋白質(zhì)純化和 COVID-19 診斷等應(yīng)用。 當(dāng)我們開(kāi)始看到科學(xué)家使用 PD 構(gòu)建包含 100 多個(gè)步驟的方案時(shí),我們知道我們需要為他們提供更好的方法來(lái)優(yōu)化和編輯他們的方案。 科學(xué)家們有足夠多的擔(dān)憂:我們不希望他們花時(shí)間一遍又一遍地乏味地改變相同的設(shè)置。
所以,我們剛剛向 PD 添加了批量編輯模式! 用戶現(xiàn)在可以選擇、復(fù)制、刪除和編輯多個(gè)步驟,從而能夠更快地迭代和優(yōu)化科學(xué)協(xié)議。
在產(chǎn)品開(kāi)發(fā)團(tuán)隊(duì)開(kāi)始考慮如何完成此功能之前,我們就知道這將是一個(gè)巨大的工程挑戰(zhàn)。 擴(kuò)展 PD 這樣的應(yīng)用程序以支持完全不同的用戶流程(例如批量編輯)將需要大量重構(gòu),這會(huì)影響 Protocol Designer 的核心部分。 這篇文章將從工程角度重點(diǎn)討論此功能,但我也想指出完成此功能所面臨的巨大設(shè)計(jì)挑戰(zhàn)。 PD 的核心原則之一是易用性,打造易于使用、直觀的用戶體驗(yàn)來(lái)構(gòu)建和優(yōu)化復(fù)雜的科學(xué)協(xié)議絕非易事。
專為一次編輯一個(gè)步驟而設(shè)計(jì)
PD 旨在從頭開(kāi)始構(gòu)建科學(xué)方案,依次創(chuàng)建和編輯步驟。 流程如下:
這意味著在任何給定時(shí)間,PD 中的主“設(shè)計(jì)”選項(xiàng)卡都會(huì)顯示以下部分/全部?jī)?nèi)容:
PD 的 UI 組件(內(nèi)置于 React)和全局狀態(tài)管理存儲(chǔ)(在 Redux 中實(shí)現(xiàn))就是為了適應(yīng)這種用戶流程而構(gòu)建的。 這意味著 PD 的 redux 存儲(chǔ)會(huì)跟蹤“選定步驟”之類的內(nèi)容,以便用戶可以直觀地看到協(xié)議的特定部分實(shí)際發(fā)生的情況。 它還會(huì)跟蹤“未保存的表單”等內(nèi)容,在提交之前跟蹤待處理的更改。
請(qǐng)注意上面捕獲的數(shù)據(jù)的奇異性(選定的步驟,未保存的形式)。 PD 的 redux 存儲(chǔ)和 React 組件旨在與一個(gè)步驟交互,而不是多個(gè)步驟。 為了說(shuō)明這一點(diǎn),讓我們看看 PD 如何根據(jù)選擇的步驟填充實(shí)驗(yàn)室器皿上的孔(這就是上圖中孔顯示為綠色的方式)。
但是,當(dāng)我們開(kāi)始跟蹤多個(gè)選定步驟而不是僅跟蹤一個(gè)步驟時(shí),會(huì)發(fā)生什么情況呢? 特別是,上面的步驟 3 會(huì)發(fā)生什么? 如果我們選擇了多個(gè)項(xiàng)目,我們?cè)撛趺崔k?
為了防止同時(shí)選擇/編輯多個(gè)步驟時(shí)組件損壞,我們必須對(duì)數(shù)據(jù)的表示和轉(zhuǎn)換方式進(jìn)行核心更改。 讓我們回顧一下我們所做的事情。
跟蹤多個(gè)選定的步驟
在此功能之前,我們僅在 Redux 存儲(chǔ)中跟蹤單個(gè)“selectedItem”。 我們的“selectedItem”reducer 類型接口類似于下面的代碼片段。 請(qǐng)注意,本文中的所有代碼片段均采用 JavaScript 編寫(xiě),并使用 flow js 鍵入。
Type SelectableItem = SingleSelectedItem const selectedItem = (state: SelectItemState, action: SelectedItemAction): ?SelectableItem |
減速器函數(shù)“selectedItem”接受狀態(tài)和操作,并返回所選項(xiàng)目(保存所選項(xiàng)目相關(guān)信息的對(duì)象),如果沒(méi)有所選項(xiàng)目,則返回 null。
為了避免在批量編輯模式下添加新的縮減器來(lái)保存多個(gè)步驟,我們選擇修改“selectedItem”縮減器以適應(yīng)返回單個(gè)步驟和多個(gè)步驟。
Type SelectableItem = SingleSelectedItem | MultipleSelectedItem const selectedItem = (state: SelectItemState, action: SelectedItemAction): ?SelectableItem |
“selectedItem”的返回類型已修改為能夠保存包含單個(gè)步驟 id 的對(duì)象(代表單一選擇類型),或包含多個(gè)步驟 id 列表的對(duì)象(代表多重選擇類型) 。 為了告訴 redux 我們已經(jīng)選擇了多個(gè)步驟,我們創(chuàng)建了一個(gè)名為“SELECT_MULTIPLE_STEPS”的操作,“selectedItem”reducer 函數(shù)將接受該操作,并更新其值以表示多個(gè)步驟(請(qǐng)參閱類型“MultipleSelectedItem”)
名為“selectedItem”的減速器肯定會(huì)有些尷尬,它可能保存表示多個(gè)項(xiàng)目的數(shù)據(jù),但我們最終決定,這種權(quán)衡是值得的,不必添加額外的減速器來(lái)表示多個(gè)選定的項(xiàng)目,從而必須取消一個(gè)或多個(gè)項(xiàng)目 另一個(gè)是在單個(gè)編輯模式和批量編輯模式之間切換時(shí)。
為了防止過(guò)去只接受一個(gè)步驟作為 props 的組件被破壞,我們能夠利用 redux 選擇器模式將來(lái)自減速器的數(shù)據(jù)轉(zhuǎn)換為我們的組件可以接受的格式。 將有關(guān)所選步驟的信息提供給我們的組件的主選擇器稱為“getSelectedStepId”,它曾經(jīng)執(zhí)行以下操作:
const getSelectedStepId: ?string = (state: State) => state.selectedItem |
這是選擇器過(guò)去所做的事情的簡(jiǎn)化,但你明白了——它基本上進(jìn)入了“selectedStep”減速器并返回其中的任何內(nèi)容。 因?yàn)槲覀兊慕M件從選擇器而不是減速器獲取選定的步驟,所以我們能夠首先轉(zhuǎn)換減速器中保存的數(shù)據(jù),然后再將其輸入到我們的組件中。
這意味著我們所要做的就是修改“getSelectedStepId”以在reducer保存“單選擇類型”時(shí)返回步驟id,否則返回null:
const getSelectedStepId: ?string = (state: State) => state.selectedItem.selectionType === SINGLE_STEP_SELECTION_TYPE ? state.selectedItem.id : null |
由于我們現(xiàn)有的組件現(xiàn)在能夠處理選擇的多個(gè)步驟,因此我們添加了一個(gè)名為“getMultiSelectItemIds”的新選擇器,它類似于“getSelectedStepId”,但在批量編輯模式下返回步驟 ID 列表,否則返回 null。 該選擇器將用于告訴 PD 在批量編輯模式下選擇了哪些步驟。
const getMultiSelectItemIds: ?Array<string> = (state: State) => state.selectedItem.selectionType === MULTI_STEP_SELECTION_TYPE ? state.selectedItem.ids : null |
從減速器 => 選擇器 => 組件中獲取數(shù)據(jù)流確實(shí)對(duì)我們有幫助,因?yàn)槲覀兡軌蚋臏p速器的結(jié)構(gòu),而不必?fù)?dān)心組件損壞。 此外,由于我們使用 reselect 將選擇器組合在一起,因此所有使用“getSelectedStepId”的高階選擇器仍然可以正常工作。
填充批量編輯表單
PD 根據(jù)規(guī)則矩陣確定多個(gè)步驟中的哪些字段是可編輯的。 例如,如果用戶選擇兩個(gè)轉(zhuǎn)移步驟,并且這兩個(gè)步驟具有不同的移液器,則他們不應(yīng)能夠修改兩個(gè)步驟之間共享的移液器流速設(shè)置。
使用規(guī)則矩陣,我們創(chuàng)建了另一個(gè)名為“getMultiSelectDisabledFields”的 redux 選擇器,顧名思義,它確定在多選模式下應(yīng)禁用哪些字段。 它會(huì)迭代所選表單中的所有字段,并確定表單是否共享相同的移液器、實(shí)驗(yàn)室器具等。根據(jù)每個(gè)字段的規(guī)則,它將返回哪些字段被禁用的映射以及每個(gè)字段被禁用的原因。 字段被禁用。 然后,批量編輯表單組件可以使用此信息來(lái)填充哪些字段可編輯,哪些字段不可編輯。
跟蹤批量編輯更改
填充批量編輯表單的字段后,需要在用戶修改它們時(shí)跟蹤其值的更改。 這是出于以下幾個(gè)原因:
對(duì)于單一編輯模式,有另一個(gè)名為“unsavedForm”的減速器,它將所有信息保存在單個(gè)未保存的表單中,但我們決定不在批量編輯模式中重用它,因?yàn)椋?/p>
1.批量編輯表單保存多個(gè)表單的信息,而不僅僅是一個(gè)表單
為了實(shí)現(xiàn)這一點(diǎn),我們創(chuàng)建了一個(gè)名為“batchEditFormChanges”的新減速器,它包含一個(gè)純 JavaScript 對(duì)象,將編輯的字段名稱表示為鍵,以及關(guān)聯(lián)的字段值。
重用表單組件
PD 的表單組件非常“智能”,因?yàn)樗鼈冞B接到 redux,因此可以訪問(wèn)表單數(shù)據(jù)。 問(wèn)題在于“智能”組件中的邏輯直接與單一編輯模式相關(guān)。 為了消除單一編輯模式的依賴,我們決定在單一編輯模式和批量編輯模式下注入表單組件,并使用一組共享名為“FieldProps”的通用 API 的 props
export type FieldProps = {| disabled: boolean, errorToShow: ?string, isIndeterminate?: boolean, name: string, onFieldBlur: () => mixed, onFieldFocus: () => mixed, tooltipContent?: ?string, updateValue: mixed => void, value: mixed, |} |
為了實(shí)現(xiàn)這一目標(biāo),我們創(chuàng)建了兩個(gè)單獨(dú)的函數(shù)(一個(gè)用于單一編輯模式,一個(gè)用于批量編輯模式),負(fù)責(zé)計(jì)算上面的每個(gè)“FieldProps”。 它們被恰當(dāng)?shù)孛麨椤癿akeSingleEditFieldProps”和“makeBatchEditFieldProps”。 單一編輯表單的主要父組件使用前者,而批量編輯表單的對(duì)應(yīng)組件則使用后者。
這兩個(gè)純函數(shù)都獲取相應(yīng)的單編輯/批量編輯狀態(tài)信息(例如每個(gè)表單中包含哪些信息),執(zhí)行必要的邏輯,并返回一個(gè)包含與上面相同的“FieldProps”接口的對(duì)象。 這意味著只要我們所有的表單組件接受“FieldProps”接口,它們就可以用于單一編輯模式和批量編輯模式。
將我們現(xiàn)有的表單組件從耦合的單一編輯模式邏輯中遷移出來(lái)是一項(xiàng)相當(dāng)大的工作(而且我們還有更多工作要做),但是創(chuàng)建這個(gè)通用的 props 接口允許我們重用現(xiàn)有的表單字段組件,同時(shí)繪制一個(gè) 單一編輯模式邏輯和批量編輯模式邏輯之間的清晰界限。
上述所有工作(以及更多)花了我們由三名工程師、一名設(shè)計(jì)師、一名產(chǎn)品經(jīng)理和一名質(zhì)量檢查工程師組成的團(tuán)隊(duì)大約三個(gè)月的時(shí)間才完成。 您可以在此處查看我們用于選擇多個(gè)步驟的史詩(shī),以及用于批量編輯表單特定工作的史詩(shī)。 我們的所有工作都是開(kāi)源的,因此請(qǐng)隨意瀏覽我們的代碼庫(kù)。
在開(kāi)始開(kāi)發(fā)此功能之前,我們問(wèn)自己整個(gè)季度的投資是否值得。 由于批量編輯是迄今為止用戶最常見(jiàn)的功能請(qǐng)求,因此我們最終決定如此。 然而,值得注意的是,用戶想要同時(shí)編輯多個(gè)步驟的原因是因?yàn)樗麄兊膮f(xié)議通常包含許多步驟,這些步驟更容易批量編輯,而不是一次編輯一個(gè)。 隨著越來(lái)越多的科學(xué)家使用 PD 來(lái)解決越來(lái)越復(fù)雜的問(wèn)題,包含許多步驟的協(xié)議問(wèn)題將會(huì)增加。
展望未來(lái),我們希望更好地了解用戶到底在使用 PD 構(gòu)建什么,以及我們可以采取哪些措施來(lái)幫助他們最大限度地減少創(chuàng)建步驟。 隨著 PD 的不斷發(fā)展和發(fā)展,我們將努力回答這些問(wèn)題。 雖然我們對(duì)此功能感到非常興奮,但我們的使命是讓科學(xué)家能夠更快地采取行動(dòng),并解決我們迫切需要他們解決的問(wèn)題,這一使命還遠(yuǎn)未結(jié)束。
經(jīng)驗(yàn)豐富的服務(wù)團(tuán)隊(duì)和強(qiáng)大的生產(chǎn)支持團(tuán)隊(duì)為客戶提供無(wú)憂的訂單服務(wù)。
簡(jiǎn)體中文
繁體中文
English
日本語(yǔ)
???