Skip to content

Commit

Permalink
Merge tag '0.21.2' into release/0.21
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed Oct 11, 2022
2 parents 88baa44 + 6b79696 commit 1dbb2bd
Show file tree
Hide file tree
Showing 29 changed files with 447 additions and 64 deletions.
36 changes: 31 additions & 5 deletions app/assets/javascripts/components/cdx_select_autocomplete.js.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
var CdxSelectAutocomplete = React.createClass({
getInitialState: function () {
return {
options: null,
};
},

render: function () {
return (<Select
ref={this.setSelectRef}
className={this.props.className}
name={this.props.name}
value={this.props.value}
placeholder={this.props.placeholder}
searchable={true}
clearable={true}
asyncOptions={this.asyncOptions.bind(this)}
asyncOptions={this.asyncOptions}
value={this.props.value || ""}
onChange={this.onChange}
/>);
},

asyncOptions: function (query, callback) {
if (!query || /^\s*$/.test(query)) {
return callback(null, []);
}
query = query.trim();
if (!query) return callback(null, []);

var autoselect = this.props.autoselect;
var prepareOptions = this.props.prepareOptions;
var url = this.props.url;
url += (url.includes("?") ? "&query=" : "?query=") + encodeURIComponent(query);

Expand All @@ -24,15 +34,31 @@ var CdxSelectAutocomplete = React.createClass({
url: url,

success: function (options) {
if (prepareOptions) {
options = prepareOptions.call(null, options);
}
callback(null, {
options: options,
complete: options.size < 10,
});
},
if (autoselect && options.length === 1 && options[0].value === query) {
this.selectRef.setValue(query);
}
}.bind(this),

error: function (_, error) {
callback(error);
},
})
},

onChange: function (value, options) {
if (this.props.onSelect) {
this.props.onSelect.call(null, value, options);
}
},

setSelectRef: function (ref) {
this.selectRef = ref;
}
});
102 changes: 102 additions & 0 deletions app/assets/javascripts/components/samples_selector.js.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
var SamplesSelector = React.createClass({
getInitialState: function () {
return {
samples: this.props.samples,
};
},

render: function () {
return (<div className="samples-selector">
{this.renderTitle()}
{this.state.samples.map(this.renderSample)}

<a className="add-samples" href="#" onClick={this.addSample}>
<div className="add-samples">
<div className="icon-circle-plus icon-blue icon-margin"></div>
<div className="add-sample-link">ADD SAMPLE</div>
</div>
</a>
</div>);
},

renderTitle() {
var samples = this.state.samples;
if (!samples.length) return;

var count = samples.reduce(function (a, e) {
return e.uuid ? a + 1 : a;
}, 0);

return (<div className="samples-count">
<div className="title">{count}&nbsp;{count == 1 ? "sample" : "samples"}</div>
</div>);
},

renderSample(sample, index) {
if (sample.uuid) {
function removeSample(event) {
this.removeSample(event, index);
}
return (<div className="batches-samples" key={"samples-selector-" + index}>
<div className="samples-row">
<div className="samples-item">{sample.uuid}</div>
<div className="samples-row-actions">
<input type="hidden" name={this.props.name + "[" + index + "]"} value={sample.uuid}/>
<span>{sample.batch_number}</span>
<a href="#" onClick={removeSample.bind(this)} title="Remove this sample">
<i className="icon-close icon-gray bigger"></i>
</a>
</div>
</div>
</div>);
} else {
function selectSample(_, options) {
this.selectSample(index, options && options[0]);
}
return (<div className="batches-samples" key={"samples-selector-" + index}>
<div className="samples-row">
<CdxSelectAutocomplete
className={this.props.className}
url={this.props.url}
placeholder={this.props.placeholder}
value={sample.uuid}
prepareOptions={this.prepareOptions}
autoselect={true}
onSelect={selectSample.bind(this)}
/>
</div>
</div>);
}
},

prepareOptions: function (options) {
return options.map(function (option) {
option.value = option.uuid;
option.label = option.uuid + " (" + option.batch_number + ")";
return option;
});
},

addSample: function (event) {
event.preventDefault();

var samples = this.state.samples;
samples.push({ uuid: "" });
this.setState({ samples: samples });
},

selectSample: function (index, sample) {
var samples = this.state.samples;
samples[index] = sample;
this.setState({ samples: samples });
},

removeSample: function (event, index) {
event.preventDefault();

var samples = this.state.samples;
samples.splice(index, 1);

this.setState({ samples: samples });
},
});
5 changes: 5 additions & 0 deletions app/assets/stylesheets/_batches.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
align-items: center;
min-height: 40px;
}
.samples-row-actions {
display: flex;
align-items: center;
gap: 10px;
}

.transfer-data {
color: black;
Expand Down
3 changes: 3 additions & 0 deletions app/assets/stylesheets/_sprites.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
color: inherit;
}

&.bigger {
font-size: 24px;
}
&.medium {
font-size: 35px;
}
Expand Down
24 changes: 22 additions & 2 deletions app/controllers/boxes_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class BoxesController < ApplicationController
before_action :load_box, except: %i[index new create bulk_destroy]
helper_method :samples_data

def index
@can_create = has_access?(@navigation_context.institution, CREATE_INSTITUTION_BOX)
Expand Down Expand Up @@ -59,6 +60,7 @@ def create

@box_form = BoxForm.build(@navigation_context, box_params)
@box_form.batches = check_access(load_batches, READ_BATCH)
@box_form.samples = check_access(load_samples, READ_SAMPLE)

if @box_form.valid?
@box_form.build_samples
Expand Down Expand Up @@ -106,13 +108,31 @@ def load_batches
.where(uuid: @box_form.batch_uuids.values.reject(&:blank?))
end

def load_samples
Sample
.within(@navigation_context.entity, @navigation_context.exclude_subsites)
.find_all_by_any_uuid(@box_form.sample_uuids.values.reject(&:blank?))
end

def box_params
if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 0
params.require(:box).permit(:purpose, :media).tap do |allowed|
allowed[:batch_uuids] = params[:box][:batch_uuids].permit!
allowed[:batch_uuids] = params[:box][:batch_uuids].try(&:permit!)
allowed[:sample_uuids] = params[:box][:sample_uuids].try(&:permit!)
end
else
params.require(:box).permit(:purpose, :media, batch_uuids: {})
params.require(:box).permit(:purpose, :media, batch_uuids: {}, sample_uuids: [])
end
end

def samples_data(samples)
# NOTE: duplicates the samples/autocomplete template (but returns an
# Array<Hash> instead of rendering to a JSON String)
samples.map do |sample|
{
uuid: sample.uuid,
batch_number: sample.batch_number,
}
end
end
end
14 changes: 14 additions & 0 deletions app/controllers/samples_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ def index
.preload(:batch, :sample_identifiers)
end

def autocomplete
samples = Sample
.where(institution: @navigation_context.institution)
.within(@navigation_context.entity, @navigation_context.exclude_subsites)

samples = samples.without_qc if params[:qc] == "0"

@samples = check_access(samples, READ_SAMPLE)
.joins(:sample_identifiers)
.autocomplete(params[:query])
.limit(10)
.preload(:batch)
end

def edit_or_show
sample = Sample.find(params[:id])

Expand Down
8 changes: 4 additions & 4 deletions app/controllers/transfer_packages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ def confirm
return unless authorize_resource(confirmation_resource(transfer_package), UPDATE_BOX)

if transfer_package.confirmed?
flash[:info] = "Transfer had already been confirmed."
redirect_to transfer_package
flash[:notice] = "Transfer had already been confirmed."
redirect_to transfer_packages_path
return
end

transfer_package.confirm!
flash[:success] = "Transfer has been confirmed."
redirect_to transfer_package
flash[:notice] = "Transfer has been confirmed."
redirect_to transfer_packages_path
end

def unblind
Expand Down
25 changes: 24 additions & 1 deletion app/helpers/cdx_form_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,35 @@ def form_actions(&block)
end
end

private
def fields_for(record_name, record_object = nil, fields_options = {}, &block)
if record_object.nil? && @object.respond_to?(record_name)
record_object = @object.send(record_name)
end

super(record_name, record_object, objectify_options(fields_options)) do |form|
# Clear errors that are handeld in the nested form
form.errors_to_show.each do |nested_key|
errors_to_show.delete("#{record_name}.#{nested_key}".to_sym)
end

block.call(form)

@template.concat form.form_errors
end
end

def has_error?(attr_name)
errors_to_show.include?(attr_name.to_sym)
end

protected

def errors_to_show
@errors_to_show ||= @object.errors.keys
end

private

def error_messages_to_show
Hash[errors_to_show.map do |attribute|
messages = @object.errors.full_messages_for(attribute)
Expand Down
2 changes: 1 addition & 1 deletion app/models/box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def blind_attributes
%i[concentration concentration_formula replicate]
when "Variants"
%i[batch_number virus_lineage]
when "Challenge"
when "Challenge", "Other"
%i[batch_number concentration concentration_formula replicate virus_lineage]
else
[]
Expand Down
Loading

0 comments on commit 1dbb2bd

Please sign in to comment.