Skip to content

Commit

Permalink
Fix: the new ontology form bugs (#368)
Browse files Browse the repository at this point in the history
* add the max date option to date inputs

* show the validity date input in the ontology form if status is retired

* fix in ontology form not revealed sections after not valid save

* add show SKOS form information reveal in the ontologies new form

* add reveal component to hide/show a content depending of a condition

* use reveal component to display or hide conditional inputs in the ontology form
  • Loading branch information
syphax-bouazzouni authored Oct 31, 2023
1 parent 1e8ae5b commit 7606205
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 159 deletions.
95 changes: 0 additions & 95 deletions app/assets/javascripts/ontologies.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,102 +17,7 @@ function showRestrictionLicensed() {
}

jQuery(document).ready(function () {

// Wire up options for restriction how an ontology is viewed
jQuery("#ontology_viewingRestriction").change(function () {
var select = jQuery(this);
if (select.val() == "private") {
hideAllRestrictions()
showRestrictionPrivate();
} else if (select.val() == "licensed") {
hideAllRestrictions();
showRestrictionLicensed();
} else if (select.val() == "public") {
hideAllRestrictions();
}
});

// Make sure you can see the account select if the select list has private selected
if (jQuery("#ontology_viewingRestriction").val() == "private") {
showRestrictionPrivate();
} else if (jQuery("#ontology_viewingRestriction").val() == "licensed") {
showRestrictionLicensed();
}

jQuery("#ontology_isView").live("click", function () {
console.log(jQuery("#ontology_isView").is(":checked"))
if (jQuery("#ontology_isView").is(":checked")) {
jQuery("#ontology_viewOf").removeAttr('disabled').trigger("chosen:updated");
} else {
jQuery("#ontology_viewOf").attr('disabled', true).trigger("chosen:updated");
}
});

// Wire up chosen selectors
jQuery("#ontology_administeredBy").chosen({width: '100%'});
jQuery("#ontology_acl").chosen({width: '100%'});
jQuery("#ontology_hasDomain").chosen({width: '100%'});
jQuery("#ontology_group").chosen({width: '100%'});

jQuery('#ontology-browse-help').on('click', bpPopWindow);

// Wire up chosen selectors
jQuery("#ontology_administeredBy").chosen({width: '100%'});
jQuery("#ontology_acl").chosen({width: '100%'});
jQuery("#ontology_hasDomain").chosen({width: '100%'});

// Make acronym upcase as you type
jQuery("#ontology_acronym").on('input', function(e) {
var input = $(this);
var start = input[0].selectionStart;
$(this).val(function (_, val) {
return val.toUpperCase();
});
input[0].selectionStart = input[0].selectionEnd = start
})

// Check acronym as you type
var acronyms = jQuery("#ontology_acronym").data("acronyms");
jQuery("#ontology_acronym").on('input', function (e) {
var $this = $(this);
var errors = [];
var errorHTML = "";

if ($this.val().match("^[^a-z^A-Z]{1}")) {
errors.push("Acronym must start with a letter");
}

if ($this.val().match("[^-_0-9a-zA-Z]")) {
errors.push("Acronym must only contain the folowing characters: -, _, letters, and numbers");
}

if ($this.val().match(".{17,}")) {
errors.push("Acronym must be sixteen characters or less");
}

if (acronyms.indexOf($this.val()) > -1) {
errors.push("Acronym already in use");
}

if (errors.length > 0) {
errorHTML = "<li>" + errors.join("</li><li>") + "</li>";
}

jQuery("#acronym_errors").html(errorHTML);
});

jQuery("#ontologyForm").validate({
errorClass: "ontologyFormError",
errorElement: "div",
rules: {
"ontology[name]": "required",
"ontology[acronym]": "required",
},
messages: {
"ontology[name]": "Please enter a name",
"ontology[acronym]": "Please enter an acronym",
},
});
});

/* charts creation */
Expand Down
6 changes: 4 additions & 2 deletions app/components/input/date_component.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# frozen_string_literal: true

class Input::DateComponent < Input::InputFieldComponent
def initialize(label: '', name:, value: Date.today, placeholder: '', error_message: '', helper_text: '', id: nil)
data_flat_picker = { controller: "flatpickr", flatpickr_date_format: "Y-m-d", flatpickr_alt_input: "true", flatpickr_alt_format: "F j, Y" }
def initialize(label: '', name:, value: Date.today, placeholder: '', error_message: '', helper_text: '', id: nil, max_date: nil)
data_flat_picker = { controller: "flatpickr", flatpickr_date_format: "Y-m-d", flatpickr_alt_input: "true", flatpickr_alt_format: "F j, Y"}
data_flat_picker[:flatpickr_max_date] = max_date if max_date

super(label: label, name: name, value: value, placeholder: placeholder, error_message: error_message, helper_text: helper_text, data: data_flat_picker, id: id)
end

Expand Down
20 changes: 20 additions & 0 deletions app/components/layout/reveal_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class Layout::RevealComponent < ViewComponent::Base
renders_one :button

def initialize(init_show: false, show_condition: nil,hidden_class: 'd-none')
@hidden_class = hidden_class
@init_show = init_show
@show_condition = show_condition
end

def container_data
out = {
controller: 'reveal-component',
'reveal-component-hidden-class': @hidden_class
}
out['reveal-component-condition-value'] = @show_condition if @show_condition
out
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
%div{data: container_data}
%div{'data-action': "change->reveal-component#toggle"}
= button
%div{'data-reveal-component-target': "item", class: @init_show ? '' : @hidden_class}
= content
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Reveal from 'stimulus-reveal-controller'

export default class extends Reveal {
static values = {
condition: String
}

connect() {
super.connect()
}

toggle(event) {
if (!this.conditionValue) {
super.toggle()
} else if (this.#shown() && !this.#conditionChecked(event)) {
super.toggle()
} else if (!this.#shown() && this.#conditionChecked(event)) {
super.toggle()
}
}

#conditionChecked(event) {
return this.conditionValue === event.target.value
}

#shown() {
return !this.itemTargets[0].classList.contains(this.class);
}

}
5 changes: 3 additions & 2 deletions app/helpers/inputs_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ def text_area_input(name:, value:, label: nil, help: nil)
helper_text: help)
end

def date_input(name:, value:, label: nil, help: nil)
def date_input(name:, value:, label: nil, help: nil, max_date: nil)
render Input::DateComponent.new(label: input_label(label, name), name: name, value: value,
error_message: input_error_message(name),
helper_text: help)
helper_text: help,
max_date: max_date)
end

private
Expand Down
12 changes: 7 additions & 5 deletions app/helpers/submission_inputs_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@ def required?
end

# @param attr_key String
def attribute_input(attr_key, attr_metadata: nil, long_text: false, label: nil, show_tooltip: true)
attr = SubmissionMetadataInput.new(attribute_key: attr_key, submission: @submission, label: label, attr_metadata: attr_metadata)
def attribute_input(attr_key, long_text: false, label: nil, show_tooltip: true, max_date: nil)
attr = SubmissionMetadataInput.new(attribute_key: attr_key, submission: @submission, label: label,
attr_metadata: attr_metadata(attr_key))

if attr.type?('Agent')
generate_agent_input(attr)
elsif attr.type?('integer')
generate_integer_input(attr)
elsif attr.type?('date_time')
generate_date_input(attr)
generate_date_input(attr, max_date: max_date)
elsif attr.type?('textarea')
generate_textarea_input(attr)
elsif enforce_values?(attr)
Expand Down Expand Up @@ -161,9 +162,10 @@ def generate_agent_input(attr)

end

def generate_date_input(attr)
def generate_date_input(attr, max_date: nil)
date_input(label: attr_header_label(attr), name: attr.name,
value: attr.values)
value: attr.values,
max_date: max_date)
end

def generate_textarea_input(attr)
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/component_controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Tabs_container_component_controller
import alert_component_controller from "../../components/display/alert_component/alert_component_controller";
import Progress_pages_component_controller
from "../../components/layout/progress_pages_component/progress_pages_component_controller";
import Reveal_component_controller from "../../components/layout/reveal_component/reveal_component_controller";


application.register("turbo-modal", TurboModalController)
Expand All @@ -28,3 +29,4 @@ application.register("tabs-container", Tabs_container_component_controller)
application.register("circle-progress-bar", CircleProgressBarComponentController)
application.register("alert-component", alert_component_controller)
application.register("progress-pages", Progress_pages_component_controller)
application.register("reveal-component", Reveal_component_controller)
3 changes: 2 additions & 1 deletion app/javascript/controllers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ application.register('read-more', ReadMore)
import Timeago from 'stimulus-timeago'
application.register('timeago', Timeago)
export { application }

import Reveal from 'stimulus-reveal-controller'
application.register('reveal', Reveal)

49 changes: 12 additions & 37 deletions app/views/ontologies/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
= text_input(name: 'ontology[acronym]', value: @ontology.acronym, disabled: @is_update_ontology)
= hidden_field_tag 'ontology[acronym]', @ontology.acronym if @is_update_ontology

.upload-ontology-input-field-container#visibilityContainer
= select_input(label: "Visibility", name: "ontology[viewingRestriction]", values: %w[public private], selected: @ontology.viewingRestriction )
.upload-ontology-input-field-container#visibility-group{style: 'display: none'}
= select_input(label: "Add or remove accounts that are allowed to view classes in this ontology using the account name", name: "ontology[acl]", values: @user_select_list, selected: @ontology.acl, multiple: true)
.upload-ontology-input-field-container
= render Layout::RevealComponent.new(init_show: @ontology.viewingRestrictio&.eql?('private'), show_condition: 'private') do |c|
- c.button do
= select_input(label: "Visibility", name: "ontology[viewingRestriction]", values: %w[public private], selected: @ontology.viewingRestriction )
.upload-ontology-input-field-container
= select_input(label: "Add or remove accounts that are allowed to view classes in this ontology using the account name", name: "ontology[acl]", values: @user_select_list, selected: @ontology.acl, multiple: true)

.upload-ontology-input-field-container
= select_input(label: "Administrator", name: "ontology[administeredBy]", values: @user_select_list, selected: @ontology.administeredBy || session[:user].id, multiple: true)
Expand All @@ -25,36 +27,9 @@
= check_input(name: "ontology[group][]", id: group[:acronym] , label: group[:acronym], value: group[:id], checked: @ontology.group&.any?{|x| x.eql?(group[:id])})

.upload-ontology-input-field-container.mt-2
%span.d-flex
= switch_input(id: 'ontology_isView', name: 'ontology[isView]', label: 'Is a view of another ontology?', checked: @ontology.view?)
%div#ontology_viewOf{style: "display: #{ [email protected]? ? 'none' : 'block'}"}
= render partial: "shared/ontology_picker_single", locals: {placeholder: "", field_name: "viewOf", selected: @ontology.viewOf}
:javascript

function showPrivateAclSelect() {
const visibilityGroupDiv = document.getElementById('visibility-group');
// Get the selected value from the select element
const selectElement = document.getElementById('select_ontology[viewingRestriction]');
const selectedValue = selectElement.value;


// Check if the selected value is "private"
if (selectedValue === 'private') {
// If it's "private", show the visibility-group div
visibilityGroupDiv.style.display = 'block';
} else {
// If it's not "private", hide the visibility-group div
visibilityGroupDiv.style.display = 'none';
}
}
const parentDiv = document.getElementById('visibilityContainer');
parentDiv.addEventListener('change', () => { showPrivateAclSelect() });


jQuery("#ontology_isView").live("click", function(){
if (jQuery("#ontology_isView").is(":checked")) {
jQuery("#ontology_viewOf").removeAttr('disabled').show();
} else {
jQuery("#ontology_viewOf").attr('disabled', true).hide();
}
});
= render Layout::RevealComponent.new(init_show: @ontology.view?) do |c|
- c.button do
%span.d-flex
= switch_input(id: 'ontology_isView', name: 'ontology[isView]', label: 'Is a view of another ontology?', checked: @ontology.view?)
%div
= render partial: "shared/ontology_picker_single", locals: {placeholder: "", field_name: "viewOf", selected: @ontology.viewOf}
29 changes: 16 additions & 13 deletions app/views/ontologies/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,29 @@
.upload-ontology-input-field-container
= attribute_input("notes", label: 'Change notes')
.upload-ontology-field-container
= select_input(label: "Format", name: "submission[hasOntologyLanguage]", values: ["OBO", "OWL", "SKOS", "UMLS"], selected: @submission.hasOntologyLanguage)
.upload-ontology-desc.hide
%div
SKOS vocabularies submitted to BioPortal must contain a minimum of one concept scheme and top concept assertion. Please
refer to the NCBO wiki for a more
%a{:href => "#seethewiki"}
detailed explanation
%svg{:fill => "none", :height => "8", :viewbox => "0 0 8 8", :width => "8", :xmlns => "http://www.w3.org/2000/svg"}
%path{:d => "M5.77776 8H1.33333C0.977156 8 0.642334 7.8613 0.390512 7.60946C0.138689 7.35762 0 7.02278 0 6.66666V2.22222C0 1.86607 0.138704 1.53124 0.390527 1.27942C0.64235 1.0276 0.977172 0.888894 1.33334 0.888894H3.11111C3.35659 0.888894 3.55556 1.08787 3.55556 1.33334C3.55556 1.57881 3.35659 1.77779 3.11111 1.77779H1.33333C1.2146 1.77779 1.10301 1.82402 1.01907 1.90795C0.935144 1.99188 0.888894 2.1035 0.888894 2.22222V6.66666C0.888894 6.78538 0.935129 6.89698 1.01907 6.98094C1.10301 7.06486 1.2146 7.11111 1.33333 7.11111H5.77775C5.89647 7.11111 6.00807 7.06487 6.09202 6.98091C6.17595 6.89698 6.22218 6.78537 6.22218 6.66664V4.88889C6.22218 4.64341 6.42117 4.44445 6.66664 4.44445C6.91212 4.44445 7.11111 4.64343 7.11111 4.88889V6.66666C7.11111 7.02281 6.9724 7.35762 6.72056 7.60947C6.46872 7.8613 6.13389 8 5.77776 8ZM3.11111 5.33332C2.99736 5.33332 2.88362 5.28994 2.79685 5.20315C2.62329 5.02959 2.62329 4.74816 2.79685 4.5746L6.48254 0.888894H4.88889C4.64341 0.888894 4.44445 0.68992 4.44445 0.444447C4.44445 0.198974 4.64341 0 4.88889 0H7.55555C7.61702 0 7.67556 0.0124825 7.72882 0.0350409C7.77851 0.0560624 7.82518 0.0865233 7.86602 0.126439L7.86605 0.12647C7.86634 0.126765 7.86664 0.127045 7.86692 0.12734C7.86699 0.127417 7.8671 0.127511 7.86718 0.127588C7.8674 0.127805 7.86765 0.128038 7.86786 0.128271C7.86802 0.128427 7.86816 0.128566 7.86831 0.128721C7.86848 0.128892 7.86867 0.129079 7.86881 0.129218C7.86912 0.129529 7.86946 0.129855 7.86977 0.130181C7.87008 0.130491 7.87042 0.130833 7.87074 0.131143C7.87091 0.131299 7.87109 0.131501 7.87122 0.13164C7.87139 0.131796 7.87151 0.131935 7.87167 0.132091C7.87191 0.132323 7.87213 0.132541 7.87235 0.132789C7.87243 0.132851 7.87254 0.13296 7.8726 0.133038C7.87289 0.133333 7.87319 0.133628 7.87347 0.133923L7.8735 0.133954C7.9134 0.174817 7.94388 0.221486 7.96488 0.271167C7.98744 0.32442 7.99994 0.382951 7.99994 0.444431V3.1111C7.99994 3.35657 7.80095 3.55555 7.55548 3.55555C7.31 3.55555 7.11104 3.35657 7.11104 3.1111V1.51744L3.4253 5.20317C3.33859 5.28995 3.22485 5.33332 3.11111 5.33332Z", :fill => "#31B404"}
with examples.
= render Layout::RevealComponent.new(init_show: @submission.hasOntologyLanguage&.eql?('SKOS'), show_condition: 'SKOS') do |c|
- c.button do
= select_input(label: "Format", name: "submission[hasOntologyLanguage]", values: ["OBO", "OWL", "SKOS", "UMLS"], selected: @submission.hasOntologyLanguage)
.upload-ontology-desc
%div
SKOS vocabularies submitted to BioPortal must contain a minimum of one concept scheme and top concept assertion. Please
refer to the NCBO wiki for a more
= link_to ExternalLinkTextComponent.new(text: 'detailed explanation').call, "#seethewiki"
with examples.
.upload-ontology-field-container.mt-3
= attribute_input("status")
= render Layout::RevealComponent.new(init_show: @submission.status&.eql?('retired'), show_condition: 'retired') do |c|
- c.button do
= attribute_input("status")
.upload-ontology-field-container
= attribute_input("valid")
.upload-ontology-field-container
= render partial: 'ontologies/submission_location_form'

- c.page do
.upload-ontology-input-field-container
- if @is_update_ontology
= attribute_input('modificationDate', label: 'Modification date (dd/mm/yy)')
= attribute_input('modificationDate', label: 'Modification date (dd/mm/yy)', max_date: Date.today)
- else
= attribute_input('released', label: 'Date of original creation (dd/mm/yy)')
= attribute_input('released', label: 'Date of original creation (dd/mm/yy)', max_date: Date.today)
.upload-ontology-contact
= contact_input(show_help: false)
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
"flatpickr": "^4.6.13",
"split.js": "^1.6.5",
"stimulus-flatpickr": "^3.0.0-0",
"stimulus-read-more": "^4.1.0",
"stimulus-rails-nested-form": "^4.0.0",
"stimulus-read-more": "^4.1.0",
"stimulus-reveal-controller": "^4.1.0",
"stimulus-timeago": "^4.1.0",
"tippy.js": "^6.3.7",
"tom-select": "^2.2.2",
"vis-data": "^7.1.6",
"vis-network": "^9.1.6",
"vis-util": "^5.0.3",
"tippy.js": "^6.3.7",
"tom-select": "^2.2.2"
"vis-util": "^5.0.3"
},
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ stimulus-read-more@^4.1.0:
resolved "https://registry.yarnpkg.com/stimulus-read-more/-/stimulus-read-more-4.1.0.tgz#f34efb2dcb33fd091936d84c569937bc100506c8"
integrity sha512-SJyCJqZrhDSKpfrepnhStBaxtyv6Jnvr+b84GDg3l+/BzL5HaFLYmc6QkSNCeR6y0x+Zw7lwKuzv+XzyAm1KzQ==

stimulus-reveal-controller@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/stimulus-reveal-controller/-/stimulus-reveal-controller-4.1.0.tgz#bf0fb4c2706f22d41544b5b02e2fbd794f608575"
integrity sha512-cPpTLV/+IQgiE+J3iBMjf3kD3H9ZOeoRJjyhvcsjyPE82mdcsuWxlzpI1pwSJPN66qSud4hVkhNH5w4xadyOfA==

stimulus-timeago@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/stimulus-timeago/-/stimulus-timeago-4.1.0.tgz#5e4b712d9eadd7f0e2b3b142f35f334dba4b3857"
Expand Down

0 comments on commit 7606205

Please sign in to comment.