Flex应用专题 | 解锁蛋白质谱前处理自动化的无限潜能

看詳情

Opentrons 協定設計器更新:批次編輯概述

Opentrons 很高興為協議設計器發布改進的批量編輯選項。 以下是您需要了解的有關其工作原理的所有資訊。

此功能升級直接來自客戶回饋。 謝謝你! 我們很高興聽到您的想法—請繼續提出!

當協議設計器 (PD) 首次創建時,Opentrons 設想了一個平台,科學家可以在其中快速建立基本的移液協議,而無需編寫任何程式碼。 隨著 PD 越來越多地被我們社區所利用,它成為一種工具,使科學家能夠建立冗長而複雜的方案,以解決 DNA 提取、蛋白質純化和 COVID-19 診斷等應用。 當我們開始看到科學家使用 PD 建立包含 100 多個步驟的方案時,我們知道我們需要為他們提供更好的方法來優化和編輯他們的方案。 科學家有足夠多的擔憂:我們不希望他們花時間一遍又一遍地乏味地改變相同的設定。

所以,我們剛剛為 PD 新增了批次編輯模式! 使用者現在可以選擇、複製、刪除和編輯多個步驟,從而能夠更快地迭代和優化科學協議。

在產品開發團隊開始考慮如何完成此功能之前,我們就知道這將是一個巨大的工程挑戰。 擴展 PD 這樣的應用程式以支援完全不同的使用者流程(例如批次編輯)將需要大量重構,這會影響 Protocol Designer 的核心部分。 這篇文章將從工程角度重點討論此功能,但我也想指出完成此功能所面臨的巨大設計挑戰。 PD 的核心原則之一是易用性,打造易於使用、直覺的使用者體驗來建立和優化複雜的科學協議絕非易事。

專為一次編輯一個步驟而設計

PD 旨在從頭開始建立科學方案,依序建立和編輯步驟。 流程如下:

  1. 使用者建立一個步驟(轉移、混合、加熱等)
  2. 在表格中填寫相關步驟資訊(移液器、實驗室器皿、液體體積等)
  3. 儲存表格
  4. 建立下一步
  5. 等等
协议设计器

這意味著在任何給定時間,PD 中的主「設計」標籤都會顯示以下部分/全部內容:

  1. 協定中所有步驟的列表
  2. 協定特定步驟的視覺快照
  3. 供使用者填寫的表格,以指定該步驟應執行的操作

PD 的 UI 元件(內建於 React)和全域狀態管理儲存(在 Redux 中實作)就是為了適應這種使用者流程而建構的。 這意味著 PD 的 redux 儲存會追蹤「選定步驟」之類的內容,以便用戶可以直觀地看到協議的特定部分實際發生的情況。 它還會追蹤「未儲存的表單」等內容,在提交之前追蹤待處理的變更。

請注意上面捕獲的資料的奇異性(選定的步驟,未儲存的形式)。 PD 的 redux 儲存和 React 元件旨在與一個步驟交互,而不是多個步驟。 為了說明這一點,讓我們看看 PD 如何根據選擇的步驟填充實驗室器皿上的孔(這就是上圖中孔顯示為綠色的方式)。

  1. 用戶點選一個步驟
  2. 調度一個名為「SELECT_STEP」的 redux 操作,更新「所選項目」reducer
  3. 偵聽「所選項目」變更的 redux 選擇器將搜尋該特定步驟中正在使用的實驗室器皿和孔
  4. 孔訊息將傳遞到名為「LabwareRender」的元件中,然後該元件將使用該資訊對孔進行著色

但是,當我們開始追蹤多個選定步驟而不是只追蹤一個步驟時,會發生什麼事? 特別是,上面的步驟 3 會發生什麼事? 如果我們選擇了多個項目,我們該怎麼辦?

為了防止同時選擇/編輯多個步驟時元件損壞,我們必須對資料的表示和轉換方式進行核心變更。 讓我們回顧一下我們所做的事情。

追蹤多個選定的步驟

在此功能之前,我們僅在 Redux 儲存中追蹤單一「selectedItem」。 我們的「selectedItem」reducer 類型介面類似於下面的程式碼片段。 請注意,本文中的所有程式碼片段均採用 JavaScript 編寫,並使用 flow js 鍵入。

Type SelectableItem = SingleSelectedItem
const selectedItem = (state: SelectItemState, action: SelectedItemAction): ?SelectableItem 

減速器函數「selectedItem」接受狀態和操作,並傳回所選項目(保存所選項目相關資訊的物件),如果沒有所選項目,則傳回 null。

為了避免在批次編輯模式下新增新的縮減器來保存多個步驟,我們選擇修改「selectedItem」縮減器以適應返回單一步驟和多個步驟。

Type SelectableItem = SingleSelectedItem | MultipleSelectedItem
const selectedItem = (state: SelectItemState, action: SelectedItemAction): ?SelectableItem 

「selectedItem」的傳回類型已修改為能夠儲存包含單一步驟 id 的物件(代表單一選擇類型),或包含多個步驟 id 清單的物件(代表多重選擇類型) 。 為了告訴 redux 我們已經選擇了多個步驟,我們建立了一個名為「SELECT_MULTIPLE_STEPS」的操作,「selectedItem」reducer 函數將接受該操作,並更新其值以表示多個步驟(請參閱類型「MultipleSelectedItem」)

名為「selectedItem」的減速器肯定會有些尷尬,它可能保存表示多個項目的數據,但我們最終決定,這種權衡是值得的,不必添加額外的減速器來表示多個選定的項目,從而必須取消一個或多個項目另一個是在單一編輯模式和批次編輯模式之間切換時。

為了防止過去只接受一個步驟作為 props 的元件被破壞,我們能夠利用 redux 選擇器模式將來自減速器的資料轉換為我們的元件可以接受的格式。 將所選步驟的資訊提供給我們的元件的主選擇器稱為“getSelectedStepId”,它曾經執行以下操作:

const get selected step ID: ?string = (state: state) => state.selected item

這是選擇器過去所做的事情的簡化,但你明白了——它基本上進入了“selectedStep”減速器並返回其中的任何內容。 因為我們的組件從選擇器而不是減速器獲取選定的步驟,所以我們能夠首先轉換減速器中保存的數據,然後再將其輸入到我們的組件中。

這意味著我們要做的就是修改“getSelectedStepId”以在reducer保存“單選擇類型”時返回步驟id,否則返回null:

const get selected step ID: ?string = (state: state) => state.selected item.selection type === single_step_selection_type ? state.selected item.ID : null

由於我們現有的元件現在能夠處理選擇的多個步驟,因此我們新增了一個名為“getMultiSelectItemIds”的新選擇器,它類似於“getSelectedStepId”,但在批次編輯模式下返回步驟ID 列表,否則返回null。 此選擇器將用於告訴 PD 在批次編輯模式下選擇了哪些步驟。

const get multi select item IDS: ?array = (state: state) => state.selected item.selection type === multi_step_selection_type ? state.selected item.IDS : null

從減速器 => 選擇器 => 組件中獲取資料流確實對我們有幫助,因為我們能夠更改減速器的結構,而不必擔心組件損壞。 此外,由於我們使用 reselect 將選擇器組合在一起,因此所有使用「getSelectedStepId」的高階選擇器仍然可以正常運作。

填入批次編輯表單

PD 根據規則矩陣決定多個步驟中的哪些欄位是可編輯的。 例如,如果使用者選擇兩個轉移步驟,並且這兩個步驟具有不同的移液器,則他們不應能夠修改兩個步驟之間共享的移液器流速設定。

使用規則矩陣,我們建立了另一個名為「getMultiSelectDisabledFields」的 redux 選擇器,顧名思義,它決定在多選模式下應停用哪些欄位。 它會迭代所選表單中的所有字段,並確定表單是否共用相同的移液器、實驗室器具等。根據每個欄位的規則,它將傳回哪些欄位被禁用的對應以及每個欄位被停用的原因。 字段被禁用。 然後,批次編輯表單元件可以使用此資訊來填入哪些欄位可編輯,哪些欄位無法編輯。

批量编辑表单

追蹤批次編輯更改

填充批次編輯表單的欄位後,需要在使用者修改它們時追蹤其值的變更。 這是出於以下幾個原因:

  1. 我們需要知道用戶是否對表單進行了任何更改,因為如果他們進行了更改,我們想提醒他們,如果他們嘗試退出表單,他們將丟失這些更改。
  2. 一旦他們完成更改,我們需要將他們所做的未儲存的更改(影響多個步驟)合併到 PD 全域狀態內已儲存的步驟對應中。

對於單一編輯模式,有另一個名為「unsavedForm」的減速器,它將所有資訊保存在單一未儲存的表單中,但我們決定不在批次編輯模式中重複使用它,因為:

1.批量編輯表單保存多個表單的信息,而不僅僅是一個表單

  1. 在批次編輯模式下,僅保存有關哪些表單欄位已變更的資訊要有用得多。 這樣,當使用者儲存批次編輯表單時,我們所要做的就是將變更擴展到保存所有已儲存表單資訊的「savedStepForms」縮減程式中的每個受影響的步驟。 這也意味著只要表示更改的物件不為空,我們就知道使用者已進行更改。

為了實現這一點,我們創建了一個名為「batchEditFormChanges」的新減速器,它包含一個純 JavaScript 對象,將編輯的欄位名稱表示為鍵,以及關聯的欄位值。

重複使用表單元件

PD 的表單元件非常“智慧”,因為它們連接到 redux,因此可以存取表單資料。 問題在於「智慧型」元件中的邏輯直接與單一編輯模式相關。 為了消除單一編輯模式的依賴,我們決定在單一編輯模式和批次編輯模式下注入表單元件,並使用一組共用名為「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,
|}

為了實現這一目標,我們創建了兩個單獨的函數(一個用於單一編輯模式,一個用於批次編輯模式),負責計算上面的每個「FieldProps」。 它們被恰當地命名為“makeSingleEditFieldProps”和“makeBatchEditFieldProps”。 單一編輯表單的主要父元件使用前者,而批次編輯表單的對應元件則使用後者。

這兩個純函數都會取得對應的單編輯/批次編輯狀態資訊(例如每個表單中包含哪些資訊),執行必要的邏輯,並傳回一個包含與上面相同的「FieldProps」介面的物件。 這意味著只要我們所有的表單元件接受“FieldProps”接口,它們就可以用於單一編輯模式和批次編輯模式。

將我們現有的表單元件從耦合的單一編輯模式邏輯中遷移出來是一項相當大的工作(而且我們還有更多工作要做),但是創建這個通用的props 介面允許我們重複使用現有的表單欄位元件,同時繪製一個單一編輯模式邏輯和批次編輯模式邏輯之間的清晰界線。

重點

上述所有工作(以及更多)花了我們由三名工程師、一名設計師、一名產品經理和一名品質檢查工程師組成的團隊大約三個月的時間才完成。 您可以在此處查看我們用於選擇多個步驟的史詩,以及用於批量編輯表單特定工作的史詩。 我們的所有工作都是開源的,因此請隨意瀏覽我們的程式碼庫。

在開始開發此功能之前,我們問自己整個季度的投資是否值得。 由於批量編輯是迄今為止用戶最常見的功能請求,因此我們最終決定如此。 然而,值得注意的是,使用者想要同時編輯多個步驟的原因是因為他們的協議通常包含許多步驟,這些步驟更容易批量編輯,而不是一次編輯一個。 隨著越來越多的科學家使用 PD 來解決越來越複雜的問題,包含許多步驟的協議問題將會增加。

展望未來,我們希望更了解使用者到底在使用 PD 建構什麼,以及我們可以採取哪些措施來幫助他們最大限度地減少創建步驟。 隨著 PD 的不斷發展和發展,我們將努力回答這些問題。 雖然我們對此功能感到非常興奮,但我們的使命是讓科學家更快採取行動,並解決我們迫切需要他們解決的問題,這項使命還遠未結束。

聯絡我們

經驗豐富的服務團隊和強大的生產支援團隊為客戶提供無憂的訂單服務。