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