Skip to content

Commit

Permalink
feat: split cell lines (ComPlat#2276)
Browse files Browse the repository at this point in the history
   - add split cell lines functionality
   - add split menu item for cell lines
   - calculate short label based on children
   - notification message after copy/split
   - create ancestry relationship
   - add ancestry gem functionality to cell lines
   - add ancestry column to cell lines
   - use-case for splitting cell lines
   - root container if not present after creation

refactor: moved message parameter to utils

af51e8e..a58a21f

refs: ComPlat#1971 ComPlat#1878
  • Loading branch information
PiTrem authored Jan 8, 2025
1 parent e751a92 commit 1fd2e42
Show file tree
Hide file tree
Showing 15 changed files with 598 additions and 115 deletions.
102 changes: 52 additions & 50 deletions app/api/chemotion/cell_line_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,21 @@ class CellLineAPI < Grape::API
include Grape::Kaminari
helpers ParamsHelpers
helpers ContainerHelpers
helpers CellLineApiParamsHelpers

rescue_from ActiveRecord::RecordNotFound do
error!('Ressource not found', 401)
end
resource :cell_lines do
desc 'return cell lines of a collection'
params do
optional :collection_id, type: Integer, desc: 'Collection id'
optional :sync_collection_id, type: Integer, desc: 'SyncCollectionsUser id'
optional :filter_created_at, type: Boolean, desc: 'filter by created at or updated at'
optional :from_date, type: Integer, desc: 'created_date from in ms'
optional :to_date, type: Integer, desc: 'created_date to in ms'
use :cell_line_get_params
end
paginate per_page: 5, offset: 0
before do
params[:per_page].to_i > 50 && (params[:per_page] = 50)
end

get do
scope = if params[:collection_id]
begin
Expand Down Expand Up @@ -82,29 +80,7 @@ class CellLineAPI < Grape::API

desc 'Create a new Cell line sample'
params do
optional :organism, type: String, desc: 'name of the donor organism of the cell'
optional :tissue, type: String, desc: 'tissue from which the cell originates'
requires :amount, type: Integer, desc: 'amount of cells'
requires :unit, type: String, desc: 'unit of cell amount'
requires :passage, type: Integer, desc: 'passage of cells'
optional :disease, type: String, desc: 'deasease of cells'
requires :material_names, type: String, desc: 'names of cell line e.g. name1;name2'
requires :collection_id, type: Integer, desc: 'Collection of the cell line sample'
optional :cell_type, type: String, desc: 'type of cells'
optional :biosafety_level, type: String, desc: 'biosafety_level of cells'
optional :growth_medium, type: String, desc: 'growth medium of cells'
optional :variant, type: String, desc: 'variant of cells'
optional :optimal_growth_temp, type: Float, desc: 'optimal_growth_temp of cells'
optional :cryo_pres_medium, type: String, desc: 'cryo preservation medium of cells'
optional :gender, type: String, desc: 'gender of donor organism'
optional :material_description, type: String, desc: 'description of cell line concept'
optional :contamination, type: String, desc: 'contamination of a cell line sample'
requires :source, type: String, desc: 'source of a cell line sample'
optional :name, type: String, desc: 'name of a cell line sample'
optional :mutation, type: String, desc: 'mutation of a cell line'
optional :description, type: String, desc: 'description of a cell line sample'
optional :short_label, type: String, desc: 'short label of a cell line sample'
requires :container, type: Hash, desc: 'root Container of element'
use :cell_line_creation_params
end
post do
error!('401 Unauthorized', 401) unless current_user.collections.find(params[:collection_id])
Expand All @@ -116,28 +92,7 @@ class CellLineAPI < Grape::API
end
desc 'Update a Cell line sample'
params do
requires :cell_line_sample_id, type: String, desc: 'id of the cell line to update'
optional :organism, type: String, desc: 'name of the donor organism of the cell'
optional :mutation, type: String, desc: 'mutation of a cell line'
optional :tissue, type: String, desc: 'tissue from which the cell originates'
requires :amount, type: Integer, desc: 'amount of cells'
requires :unit, type: String, desc: 'unit of amount of cells'
optional :passage, type: Integer, desc: 'passage of cells'
optional :disease, type: String, desc: 'deasease of cells'
optional :material_names, type: String, desc: 'names of cell line e.g. name1;name2'
optional :collection_id, type: Integer, desc: 'Collection of the cell line sample'
optional :cell_type, type: String, desc: 'type of cells'
optional :biosafety_level, type: String, desc: 'biosafety_level of cells'
optional :variant, type: String, desc: 'variant of cells'
optional :optimal_growth_temp, type: Float, desc: 'optimal_growth_temp of cells'
optional :cryo_pres_medium, type: String, desc: 'cryo preservation medium of cells'
optional :gender, type: String, desc: 'gender of donor organism'
optional :material_description, type: String, desc: 'description of cell line concept'
optional :contamination, type: String, desc: 'contamination of a cell line sample'
optional :source, type: String, desc: 'source of a cell line sample'
optional :name, type: String, desc: 'name of a cell line sample'
optional :description, type: String, desc: 'description of a cell line sample'
requires :container, type: Hash, desc: 'root Container of element'
use :cell_line_update_params
end
put do
use_case = Usecases::CellLines::Update.new(params, current_user)
Expand All @@ -146,12 +101,59 @@ class CellLineAPI < Grape::API
return present cell_line_sample, with: Entities::CellLineSampleEntity
end

desc 'Copy a cell line'
params do
requires :id, type: Integer, desc: 'id of cell line sample to copy'
requires :collection_id, type: Integer, desc: 'id of collection of copied cell line sample'
requires :container, type: Hash, desc: 'root container of element'
end
namespace :copy do
post do
cell_line_to_copy = @current_user.cellline_samples.where(id: [params[:id]]).reorder('id')

error!('401 Unauthorized', 401) unless ElementsPolicy.new(@current_user, cell_line_to_copy).update?

begin
use_case = Usecases::CellLines::Copy.new(cell_line_to_copy.first, @current_user, params[:collection_id])
copied_cell_line_sample = use_case.execute!
copied_cell_line_sample.container = update_datamodel(params[:container])
rescue StandardError => e
error!(e, 400)
end
return present copied_cell_line_sample, with: Entities::CellLineSampleEntity
end
end

desc 'Splits a cell line'
params do
requires :id, type: Integer, desc: 'id of cell line sample to copy'
requires :collection_id, type: Integer, desc: 'id of collection of copied cell line sample'
optional :container, type: Hash, desc: 'root container of element'
end
namespace :split do
post do
cell_line_to_copy = @current_user.cellline_samples.where(id: [params[:id]]).reorder('id')

error!('401 Unauthorized', 401) unless ElementsPolicy.new(@current_user, cell_line_to_copy).update?

begin
use_case = Usecases::CellLines::Split.new(cell_line_to_copy.first, @current_user, params[:collection_id])
splitted_cell_line_sample = use_case.execute!
splitted_cell_line_sample.container = update_datamodel(params[:container]) if @params.key?('container')
rescue StandardError => e
error!(e, 400)
end
return present splitted_cell_line_sample, with: Entities::CellLineSampleEntity
end
end

resource :names do
desc 'Returns all accessable cell line material names and their id'
get 'all' do
return present CelllineMaterial.all, with: Entities::CellLineMaterialNameEntity
end
end

resource :material do
params do
requires :id, type: Integer, desc: 'id of cell line material to load'
Expand Down
64 changes: 64 additions & 0 deletions app/api/helpers/cell_line_api_params_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module CellLineApiParamsHelpers
extend Grape::API::Helpers

params :cell_line_get_params do
optional :collection_id, type: Integer, desc: 'Collection id'
optional :sync_collection_id, type: Integer, desc: 'SyncCollectionsUser id'
optional :filter_created_at, type: Boolean, desc: 'filter by created at or updated at'
optional :from_date, type: Integer, desc: 'created_date from in ms'
optional :to_date, type: Integer, desc: 'created_date to in ms'
end

params :cell_line_creation_params do
optional :organism, type: String, desc: 'name of the donor organism of the cell'
optional :tissue, type: String, desc: 'tissue from which the cell originates'
requires :amount, type: Integer, desc: 'amount of cells'
requires :unit, type: String, desc: 'unit of cell amount'
requires :passage, type: Integer, desc: 'passage of cells'
optional :disease, type: String, desc: 'deasease of cells'
requires :material_names, type: String, desc: 'names of cell line e.g. name1;name2'
requires :collection_id, type: Integer, desc: 'Collection of the cell line sample'
optional :cell_type, type: String, desc: 'type of cells'
optional :biosafety_level, type: String, desc: 'biosafety_level of cells'
optional :growth_medium, type: String, desc: 'growth medium of cells'
optional :variant, type: String, desc: 'variant of cells'
optional :optimal_growth_temp, type: Float, desc: 'optimal_growth_temp of cells'
optional :cryo_pres_medium, type: String, desc: 'cryo preservation medium of cells'
optional :gender, type: String, desc: 'gender of donor organism'
optional :material_description, type: String, desc: 'description of cell line concept'
optional :contamination, type: String, desc: 'contamination of a cell line sample'
requires :source, type: String, desc: 'source of a cell line sample'
optional :name, type: String, desc: 'name of a cell line sample'
optional :mutation, type: String, desc: 'mutation of a cell line'
optional :description, type: String, desc: 'description of a cell line sample'
optional :short_label, type: String, desc: 'short label of a cell line sample'
requires :container, type: Hash, desc: 'root Container of element'
end

params :cell_line_update_params do
requires :cell_line_sample_id, type: String, desc: 'id of the cell line to update'
optional :organism, type: String, desc: 'name of the donor organism of the cell'
optional :mutation, type: String, desc: 'mutation of a cell line'
optional :tissue, type: String, desc: 'tissue from which the cell originates'
requires :amount, type: Integer, desc: 'amount of cells'
requires :unit, type: String, desc: 'unit of amount of cells'
optional :passage, type: Integer, desc: 'passage of cells'
optional :disease, type: String, desc: 'deasease of cells'
optional :material_names, type: String, desc: 'names of cell line e.g. name1;name2'
optional :collection_id, type: Integer, desc: 'Collection of the cell line sample'
optional :cell_type, type: String, desc: 'type of cells'
optional :biosafety_level, type: String, desc: 'biosafety_level of cells'
optional :variant, type: String, desc: 'variant of cells'
optional :optimal_growth_temp, type: Float, desc: 'optimal_growth_temp of cells'
optional :cryo_pres_medium, type: String, desc: 'cryo preservation medium of cells'
optional :gender, type: String, desc: 'gender of donor organism'
optional :material_description, type: String, desc: 'description of cell line concept'
optional :contamination, type: String, desc: 'contamination of a cell line sample'
optional :source, type: String, desc: 'source of a cell line sample'
optional :name, type: String, desc: 'name of a cell line sample'
optional :description, type: String, desc: 'description of a cell line sample'
requires :container, type: Hash, desc: 'root Container of element'
end
end
19 changes: 19 additions & 0 deletions app/javascript/src/components/contextActions/CreateButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export default class CreateButton extends React.Component {
return uiState.reaction.checkedIds.first();
}

getCellLineId(){
let uiState = UIStore.getState();
return uiState.cell_line.checkedIds.first();
}

isCopySampleDisabled() {
let sampleFilter = this.getSampleFilter();
return !sampleFilter.all && sampleFilter.included_ids.size == 0;
Expand Down Expand Up @@ -102,6 +107,17 @@ export default class CreateButton extends React.Component {
ElementActions.copyReactionFromId(reactionId);
}

isCopyCellLineDisabled() {
let cellLineId = this.getCellLineId();
return !cellLineId;
}

copyCellLine() {
let uiState = UIStore.getState();
let cellLineId = this.getCellLineId();
ElementActions.copyCellLineFromId(parseInt(cellLineId),uiState.currentCollection.id);
}

createWellplateFromSamples() {
let uiState = UIStore.getState();
let sampleFilter = this.filterParamsFromUIStateByElementType(uiState, "sample");
Expand Down Expand Up @@ -290,6 +306,9 @@ export default class CreateButton extends React.Component {
<Dropdown.Item onClick={() => this.copyReaction()} disabled={this.isCopyReactionDisabled()}>
Copy Reaction
</Dropdown.Item>
<Dropdown.Item onClick={() => this.copyCellLine()} disabled={this.isCopyCellLineDisabled()}>
Copy Cell line
</Dropdown.Item>
</SplitButton>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ export default class SplitElementButton extends React.Component {
>
Split Wellplate
</Dropdown.Item>
<Dropdown.Item
onClick={() => ElementActions.splitAsSubCellLines(UIStore.getState())}
disabled={this.noSelected('cell_line') || this.isAllCollection()}
>
Split Cell line
</Dropdown.Item>
{sortedGenericEls.map((el) => (
<Dropdown.Item
id={`split-${el.name}-button`}
Expand Down
Loading

0 comments on commit 1fd2e42

Please sign in to comment.