Skip to content
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

Split cell lines #1971

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
af51e8e
feature: scaffhold of cell line sample copy created
FabianMauz Apr 18, 2024
caf9b08
feat: create empty CelllineSample when copy is executed.
Apr 18, 2024
c51fe20
feat: create new cell_line with copied attributes
Apr 18, 2024
6bd053a
refactor: add loading to copy test
FabianMauz Apr 29, 2024
0a01175
feat: update short label and counter at copiing cell lines
FabianMauz Apr 29, 2024
9cd9da9
feat: add rest endpoint for copy cell lines
FabianMauz Apr 29, 2024
9996875
feat: add links to collections of copied cell lines
FabianMauz Apr 29, 2024
4c302c9
merged with main
FabianMauz Apr 29, 2024
aa460fe
feat: add frontend ui for creating cell lines
FabianMauz Apr 30, 2024
9cb2796
feat: add container update/creation
FabianMauz Apr 30, 2024
cfb18f7
test: add container to spec
FabianMauz May 2, 2024
c514055
refactor: extract api params to own file
FabianMauz May 7, 2024
44e95bc
feat: reenabled ElementPolicy check
FabianMauz May 7, 2024
8570333
feat: fixed element policy for cell lines
FabianMauz May 7, 2024
cc6997c
Merge branch 'main' into 1878-copy-cell-lines
May 16, 2024
9bee601
chore: remove accidentally doubled changelog information
May 16, 2024
7c2e475
Merge branch 'main' into 1878-copy-cell-lines
May 24, 2024
b931b80
Merge branch 'main' into 1878-copy-cell-lines
May 24, 2024
b9bb1c2
refactor: remove unnecessary space
May 24, 2024
7639ad4
Merge remote-tracking branch 'origin/main' into 1878-copy-cell-lines
May 24, 2024
0f1128d
Merge remote-tracking branch 'refs/remotes/origin/main'
FabianMauz May 31, 2024
aef1d29
feat: add root container if not present after creation
FabianMauz May 31, 2024
50e58a2
test: add failing test for split cell line
FabianMauz May 31, 2024
cb0c48a
feat: add usecase for splitting cell lines
FabianMauz May 31, 2024
3001284
feat: add ancestry column to cell lines
FabianMauz May 31, 2024
24fc8ff
feat: add ancestry gem functionality to cell lines
FabianMauz May 31, 2024
b9d83fd
feat: create ancestry relationship
FabianMauz May 31, 2024
02c8b5b
feat: calculate short label based on children
FabianMauz May 31, 2024
3a399d4
feat: add split menu item for cell lines
FabianMauz Jun 10, 2024
89abda3
fix: persist splitted cell line to save updated label
FabianMauz Jun 10, 2024
c6582ef
chore: fix wrong comment
FabianMauz Jun 10, 2024
c261471
feat: add split cell lines functionality
FabianMauz Jun 10, 2024
b4f28aa
fix: update of cell line counter after creation of copy
FabianMauz Jun 10, 2024
2d73ba7
fix: updating to latest counter information after cell line copy
FabianMauz Jun 10, 2024
9e2d849
feat: add message after copy
FabianMauz Jun 10, 2024
96a3a2c
refactor: moved message parameter to utils
FabianMauz Jun 11, 2024
1d37471
feat: add message after split
FabianMauz Jun 11, 2024
a58a21f
chore: make rubocop happy
FabianMauz Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also check for presence of :container like in the :split endpoint (line 142)?

rescue StandardError => e
error!(e, 400)
end
return present copied_cell_line_sample, with: Entities::CellLineSampleEntity
end
end

desc 'Splits a cell line'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename from "Splits a cell line" to "Split a cell line"? Then it'd be consistent with the other descriptions that use the grammatical base form of the verb, not the third-person (e.g., "Copy a cell line").

Copy link
Collaborator

Choose a reason for hiding this comment

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

Apart from use_case this endpoint duplicates the :copy endpoint. Is drying this up worth it, or do we apply the rule of three?

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
9 changes: 9 additions & 0 deletions app/models/cellline_sample.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# rubocop:disable Rails/InverseOf, Rails/HasManyOrHasOneDependent
class CelllineSample < ApplicationRecord
acts_as_paranoid
has_ancestry

include ElementUIStateScopes
include Taggable
Expand All @@ -35,6 +36,10 @@ class CelllineSample < ApplicationRecord
belongs_to :cellline_material
belongs_to :creator, class_name: 'User', foreign_key: 'user_id'

has_many :sync_collections_users, through: :collections

after_create :create_root_container

scope :by_sample_name, lambda { |query, collection_id|
joins(:collections).where(collections: { id: collection_id })
.where('name ILIKE ?', "%#{sanitize_sql_like(query)}%")
Expand All @@ -46,5 +51,9 @@ class CelllineSample < ApplicationRecord
.where('collections.id=?', collection_id)
.where('cellline_materials.name ILIKE ?', "%#{sanitize_sql_like(query)}%")
}

def create_root_container
self.container = Container.create_root_container if container.nil?
end
end
# rubocop:enable Rails/InverseOf, Rails/HasManyOrHasOneDependent
18 changes: 17 additions & 1 deletion app/packs/src/components/contextActions/CreateButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,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 @@ -105,6 +110,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 @@ -272,8 +288,8 @@ export default class CreateButton extends React.Component {
<MenuItem divider />
<MenuItem onSelect={() => this.copySample()} disabled={this.isCopySampleDisabled()}>Copy Sample</MenuItem>
<MenuItem onSelect={() => this.copyReaction()} disabled={this.isCopyReactionDisabled()}>Copy Reaction</MenuItem>
<MenuItem onSelect={() => this.copyCellLine()} disabled={this.isCopyCellLineDisabled()}>Copy Cell line</MenuItem>
</SplitButton>

)
}
}
Expand Down
6 changes: 6 additions & 0 deletions app/packs/src/components/contextActions/SplitElementBtn.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export default class SplitElementBtn extends React.Component {
>
Split Wellplate
</MenuItem>
<MenuItem
onSelect={() => ElementActions.splitAsSubCellLines(UIStore.getState())}
disabled={this.noSelected('cell_line') || this.isAllCollection()}
>
Split Cell line
</MenuItem>
{itemTables}
</DropdownButton>
);
Expand Down
Loading
Loading