From e5387e5f902f896b29dcfe80d0711100ac29473b Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:38:39 +0100 Subject: [PATCH 01/22] Fix: project page ontologies not selected (#790) * fix the issue in the projects page when the ontologies are private * fix ontologies selector name in projects from * pass the correct project ontologies value in project ontologies selector * pass an empty array if used ontologies of a group is nil --- app/controllers/projects_controller.rb | 14 +++++++------- app/views/projects/_form.html.haml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 490072b4bd..5816730466 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -26,13 +26,13 @@ def show redirect_to projects_path return end - + @project = projects.first @ontologies_used = [] onts_used = @project.ontologyUsed onts_used.each do |ont_used| ont = LinkedData::Client::Models::Ontology.find(ont_used) - unless ont.nil? + unless ont.nil? || ont.errors @ontologies_used << Hash["name", ont.name, "acronym", ont.acronym] end end @@ -62,7 +62,7 @@ def edit @project = projects.first @user_select_list = LinkedData::Client::Models::User.all.map {|u| [u.username, u.id]} @user_select_list.sort! {|a,b| a[1].downcase <=> b[1].downcase} - @usedOntologies = @project.ontologyUsed || [] + @usedOntologies = @project.ontologyUsed&.map{|o| o.split('/').last} @ontologies = LinkedData::Client::Models::Ontology.all end @@ -76,7 +76,7 @@ def create @project = LinkedData::Client::Models::Project.new(values: project_params) @project_saved = @project.save - + # Project successfully created. if response_success?(@project_saved) flash[:notice] = t('projects.project_successfully_created') @@ -160,10 +160,10 @@ def destroy def project_params p = params.require(:project).permit(:name, :acronym, :institution, :contacts, { creator:[] }, :homePage, :description, { ontologyUsed:[] }) - + p[:creator]&.reject!(&:blank?) - p[:ontologyUsed]&.reject!(&:blank?) - p.to_h + p[:ontologyUsed] ||= [] + p = p.to_h end def flash_error(msg) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index cd3eea4235..55bdb61edc 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -53,5 +53,5 @@ %div#ontology_picker_project{style: "padding-top: 2em;"} - selected_ontologies = @project.ontologyUsed && @project.ontologyUsed.map {|id| id.split('/').last } || [] - locals = { sel_text: t('projects.form.select_ontologies'), selected_ontologies: selected_ontologies, form_object: :project, form_attribute: "ontologyUsed" } - = ontologies_selector(id:'projects_page_ontologies_selector' ,name: 'ontologies') + = ontologies_selector(id:'projects_page_ontologies_selector' ,name: 'project[ontologyUsed][]', selected: @usedOntologies) From 1aa8d3850eb5f87b39d84b13f78edaa14f8abfa2 Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:40:04 +0100 Subject: [PATCH 02/22] fix collection tree issue by including MultiLanguagesHelper to make sure main_language_label is defined in collections helper (#793) --- app/helpers/collections_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/helpers/collections_helper.rb b/app/helpers/collections_helper.rb index b366a1401c..9a80d24111 100644 --- a/app/helpers/collections_helper.rb +++ b/app/helpers/collections_helper.rb @@ -1,4 +1,5 @@ module CollectionsHelper + include MultiLanguagesHelper def get_collections(ontology, add_colors: false) From 70f0e4daa445de6006baa15f420c5874b40d1bd7 Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:45:32 +0100 Subject: [PATCH 03/22] Fix: ontologies selector localization text and add "[view]" of the views in the list (#791) * fix ontologies selector weird results sentence * show [view] beside ontology views in ontologies selector --- app/helpers/application_helper.rb | 4 ++-- .../ontologies_selector/ontologies_selector_results.html.haml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3f69732afd..acf5335c1c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -107,14 +107,14 @@ def error_message_alert end def onts_for_select(include_views: false) - ontologies ||= LinkedData::Client::Models::Ontology.all({include: "acronym,name", include_views: include_views}) + ontologies ||= LinkedData::Client::Models::Ontology.all({include: "acronym,name,viewOf", include_views: include_views}) onts_for_select = [['', '']] ontologies.each do |ont| next if ( ont.acronym.nil? or ont.acronym.empty? ) acronym = ont.acronym name = ont.name abbreviation = acronym.empty? ? "" : "(#{acronym})" - ont_label = "#{name.strip} #{abbreviation}" + ont_label = "#{name.strip} #{abbreviation}#{ont.viewOf ? ' [view]' : ''}" onts_for_select << [ont_label, acronym] end onts_for_select.sort! { |a,b| a[0].downcase <=> b[0].downcase } diff --git a/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml b/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml index 2aeafa23df..9bd25a770a 100644 --- a/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml +++ b/app/views/ontologies/ontologies_selector/ontologies_selector_results.html.haml @@ -2,7 +2,7 @@ .ontologies-selector-results .horizontal-line .results-number - = t("ontologies.showing_ontologies_size", ontologies_size: @ontologies.length, analytics_size: @total_ontologies_number) + = t("ontologies.showing_ontologies_size", ontologies_size: @ontologies.length, analytics_size: @total_ontologies_number, portals: portal_name) %span.select-all{'data-action': 'click->ontologies-selector#selectall'} = t('ontologies_selector.select_all') .ontologies From 1e4b80996ec39f9f70191d9f45043ac7c6596887 Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Wed, 30 Oct 2024 15:57:12 +0100 Subject: [PATCH 04/22] Fix: update select_language_label helper to select f no english found any language remaining over the not tagged (#795) * update select_language_label helper to select f no english found any language remaining over the not tagged * fix tests by fixing a dependency change * fix login system tests after securing the user delete action in the API --- Gemfile.lock | 2 +- app/components/tree_link_component.rb | 46 ++++++++++++++-------- app/helpers/multi_languages_helper.rb | 2 +- test/helpers/application_test_helpers.rb | 50 +++++++++++++++--------- test/system/login_flows_test.rb | 2 - test/system/submission_flows_test.rb | 16 +++----- 6 files changed, 69 insertions(+), 49 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3bb8c68812..73328d8412 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,7 +160,7 @@ GEM ed25519 (1.3.0) erubi (1.13.0) erubis (2.7.0) - excon (1.0.0) + excon (0.112.0) execjs (2.10.0) faraday (2.0.1) faraday-net_http (~> 2.0) diff --git a/app/components/tree_link_component.rb b/app/components/tree_link_component.rb index 73da902f20..fd23706d96 100644 --- a/app/components/tree_link_component.rb +++ b/app/components/tree_link_component.rb @@ -2,26 +2,19 @@ class TreeLinkComponent < ViewComponent::Base include MultiLanguagesHelper, ModalHelper, ApplicationHelper - def initialize(child:, href:, children_href: , selected: false , data: {}, muted: false, target_frame: nil, open_in_modal: false, is_reused: nil) + + def initialize(child:, href:, children_href:, selected: false, data: {}, muted: false, target_frame: nil, open_in_modal: false, is_reused: nil) + super + @child = child @active_style = selected ? 'active' : '' - #@icons = child.relation_icon(node) @muted_style = muted ? 'text-muted' : '' @href = href @children_link = children_href - label = (@child.prefLabel || @child.label) rescue @child.id - if label.nil? - @pref_label_html = link_last_part(child.id) - else - pref_label_lang, @pref_label_html = select_language_label(label) - pref_label_lang = pref_label_lang.to_s.upcase - @tooltip = pref_label_lang.eql?("@NONE") ? "" : pref_label_lang - if child.obsolete? - @pref_label_html = "#{@pref_label_html}".html_safe - end - end - @data ||= { controller: 'tooltip', 'tooltip-position-value': 'right', turbo: true, 'turbo-frame': target_frame, action: 'click->simple-tree#select'} + @pref_label_html, @tooltip = node_label(child) + + @data ||= { controller: 'tooltip', 'tooltip-position-value': 'right', turbo: true, 'turbo-frame': target_frame, action: 'click->simple-tree#select' } @data.merge!(data) do |_, old, new| "#{old} #{new}" @@ -32,7 +25,6 @@ def initialize(child:, href:, children_href: , selected: false , data: {}, muted @is_reused = is_reused end - # This gives a very hacky short code to use to uniquely represent a class # based on its parent in a tree. Used for unique ids in HTML for the tree view def short_uuid @@ -49,7 +41,7 @@ def open? end def border_left - !@child.hasChildren ? 'pl-3 tree-border-left' : '' + !@child.hasChildren ? 'pl-3 tree-border-left' : '' end def li_id @@ -75,4 +67,26 @@ def open_children_link end + private + + def node_label(child) + label = begin + child.prefLabel || child.label + rescue + child.id + end + + if label.nil? + pref_label_html = link_last_part(child.id) + else + pref_label_lang, pref_label_html = select_language_label(label) + pref_label_lang = pref_label_lang.to_s.upcase + tooltip = pref_label_lang.eql?("@NONE") ? "" : pref_label_lang + + pref_label_html = "#{pref_label_html}".html_safe if child.obsolete? + end + + [pref_label_html, tooltip] + end + end diff --git a/app/helpers/multi_languages_helper.rb b/app/helpers/multi_languages_helper.rb index 9e21f2e0ed..6e127b94e0 100644 --- a/app/helpers/multi_languages_helper.rb +++ b/app/helpers/multi_languages_helper.rb @@ -153,7 +153,7 @@ def select_language_label(concept_label, platform_languages = %i[en fr]) end end - concept_value || concept.to_a.first + concept_value || concept.reject { |k| k.to_s.eql?('@none') }.first || concept.first end def main_language_label(label) diff --git a/test/helpers/application_test_helpers.rb b/test/helpers/application_test_helpers.rb index 975c220eac..28530711f7 100644 --- a/test/helpers/application_test_helpers.rb +++ b/test/helpers/application_test_helpers.rb @@ -16,17 +16,27 @@ module Users def sign_in_as(username) user = fixtures(:users)[username] logged_in_user = LinkedData::Client::Models::User.authenticate(user.username, user.password) - if logged_in_user && !logged_in_user.errors - logged_in_user = create_user(user) - end + logged_in_user = create_user(user) if logged_in_user && !logged_in_user.errors logged_in_user end def create_user(user, admin: false) - admin_user = LinkedData::Client::Models::User.authenticate('admin', 'password') if admin + admin_user = LinkedData::Client::Models::User.authenticate('admin', 'password') existent_user = LinkedData::Client::Models::User.find_by_username(user.username).first - existent_user.delete if existent_user + conn = Faraday.new(url: LinkedData::Client.settings.rest_url) do |faraday| + faraday.request :url_encoded + faraday.response :logger + faraday.adapter Faraday.default_adapter + faraday.headers = { + "Accept" => "application/json", + "Authorization" => "apikey token=#{admin_user.apikey}", + "User-Agent" => "NCBO API Ruby Client v0.1.0" + } + + end + + conn.delete("/users/#{user.username}") if existent_user values = user.to_h values[:role] = ["ADMINISTRATOR"] if admin @@ -34,17 +44,6 @@ def create_user(user, admin: false) if admin # Overwrite the normal ".save" to accept creating admin user - conn = Faraday.new(url: LinkedData::Client.settings.rest_url) do |faraday| - faraday.request :url_encoded - faraday.response :logger - faraday.adapter Faraday.default_adapter - faraday.headers = { - "Accept" => "application/json", - "Authorization" => "apikey token=#{admin_user.apikey}", - "User-Agent" => "NCBO API Ruby Client v0.1.0" - } - - end conn.post(existent_user.class.collection_path, existent_user.to_hash.to_json, 'Content-Type' => 'application/json') else existent_user.save @@ -61,7 +60,22 @@ def delete_users(users = LinkedData::Client::Models::User.all) end def delete_user(user) - LinkedData::Client::Models::User.find_by_username(user.username).first&.delete + admin_user = LinkedData::Client::Models::User.authenticate('admin', 'password') + existent_user = LinkedData::Client::Models::User.find_by_username(user.username).first + + conn = Faraday.new(url: LinkedData::Client.settings.rest_url) do |faraday| + faraday.request :url_encoded + faraday.response :logger + faraday.adapter Faraday.default_adapter + faraday.headers = { + "Accept" => "application/json", + "Authorization" => "apikey token=#{admin_user.apikey}", + "User-Agent" => "NCBO API Ruby Client v0.1.0" + } + + end + + conn.delete("/users/#{user.username}") if existent_user end end @@ -133,4 +147,4 @@ def delete_agents(agents = LinkedData::Client::Models::Agent.all) Array(agents).each { |g| g.delete } end end -end \ No newline at end of file +end diff --git a/test/system/login_flows_test.rb b/test/system/login_flows_test.rb index d6ff0deb49..8bed283d20 100644 --- a/test/system/login_flows_test.rb +++ b/test/system/login_flows_test.rb @@ -22,8 +22,6 @@ class LoginFlowsTest < ApplicationSystemTestCase new_user = @user_john delete_user(new_user) - LinkedData::Client::Models::User.find_by_username(new_user.username).first&.delete - fill_in 'user_firstName', with: new_user.firstName fill_in 'user_lastName', with: new_user.lastName fill_in 'user_username', with: new_user.username diff --git a/test/system/submission_flows_test.rb b/test/system/submission_flows_test.rb index 6045308d04..a0c06a4f47 100644 --- a/test/system/submission_flows_test.rb +++ b/test/system/submission_flows_test.rb @@ -46,7 +46,6 @@ class SubmissionFlowsTest < ApplicationSystemTestCase assert_text cat.acronym.titleize end - assert_text @new_submission.URI assert_text @new_submission.description assert_text @new_submission.pullLocation @@ -103,7 +102,6 @@ class SubmissionFlowsTest < ApplicationSystemTestCase click_on "Licensing" submission_licensing_edit_fill(ontology_2, submission_2) - # Persons and organizations tab click_on "Persons and organizations" submission_agent_edit_fill(submission_2) @@ -148,7 +146,10 @@ class SubmissionFlowsTest < ApplicationSystemTestCase assert_text submission_2.URI assert_text submission_2.versionIRI + + wait_for '.submission-status' assert_selector '.submission-status', text: submission_2.version + assert_selector ".flag-icon-fr" # todo fix this submission_2.identifier.each do |id| assert_text id @@ -258,7 +259,6 @@ class SubmissionFlowsTest < ApplicationSystemTestCase assert_text "rdfs" assert_text "dct" - open_dropdown "#configuration" submission_2.keyClasses.each do |key| @@ -341,10 +341,8 @@ class SubmissionFlowsTest < ApplicationSystemTestCase sleep 0.5 click_button 'Back' - fill_ontology(ontology_2, submission_2, add_submission: true) - assert_selector 'h2', text: 'Ontology submitted successfully!' click_on current_url.gsub("/ontologies/success/#{existent_ontology.acronym}", '') + ontology_path(existent_ontology.acronym) @@ -362,7 +360,6 @@ class SubmissionFlowsTest < ApplicationSystemTestCase assert_text submission_2.description assert_text submission_2.pullLocation - # check assert_selector '.fas.fa-key' if submission_2.status.eql?('private') @@ -380,7 +377,6 @@ class SubmissionFlowsTest < ApplicationSystemTestCase assert_text group.name end - open_dropdown "#dates" assert_date submission_2.modificationDate assert_date existent_submission.released @@ -483,7 +479,6 @@ def submission_agent_edit_fill(submission) list_inputs "#submissioncontact_from_group_input", "submission[contact]", submission.contact - agent1 = fixtures(:agents)[:agent1] agent2 = fixtures(:agents)[:agent2] @@ -624,7 +619,6 @@ def fill_ontology(new_ontology, new_submission, add_submission: false) list_checks new_ontology.hasDomain.map(&:acronym), @categories.map(&:acronym) list_checks new_ontology.group.map(&:acronym), @groups.map(&:acronym) - click_button 'Next' # Page 2 @@ -644,9 +638,9 @@ def fill_ontology(new_ontology, new_submission, add_submission: false) # Page 3 if add_submission - date_picker_fill_in 'submission[modificationDate]', new_submission.modificationDate + date_picker_fill_in 'submission[modificationDate]', new_submission.modificationDate else - date_picker_fill_in 'submission[released]', new_submission.released + date_picker_fill_in 'submission[released]', new_submission.released end list_inputs "#submissioncontact_from_group_input", "submission[contact]", new_submission.contact From d67ba52615725d5768353877ca29a535090c2dbb Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:00:49 +0100 Subject: [PATCH 05/22] Fix: clean concepts controller code to improve tree view performance (#794) --- app/controllers/concepts_controller.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/concepts_controller.rb b/app/controllers/concepts_controller.rb index 196a61f97d..1063c953b4 100644 --- a/app/controllers/concepts_controller.rb +++ b/app/controllers/concepts_controller.rb @@ -45,14 +45,15 @@ def index @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first @ob_instructions = helpers.ontolobridge_instructions_template(@ontology) - @submission = @ontology.explore.latest_submission(include: 'all') + @submission = @ontology.explore.latest_submission(include:'uriRegexPattern,preferredNamespaceUri') + + @concept = @ontology.explore.single_class({dispay: 'prefLabel'}, params[:id]) - @concept = @ontology.explore.single_class({full: true}, params[:id]) concept_not_found(params[:id]) if @concept.nil? @schemes = params[:concept_schemes].split(',') @concept.children = @concept.explore.children(pagesize: 750, concept_schemes: Array(@schemes).join(','), language: request_lang, display: 'prefLabel,obsolete,hasChildren').collection || [] - @concept.children.sort! { |x, y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase } unless @concept.children.empty? + render turbo_stream: [ replace(helpers.child_id(@concept) + '_open_link') { TreeLinkComponent.tree_close_icon }, replace(helpers.child_id(@concept) + '_childs') do From e616842389ae436b47d09f95fe7cc5bfbf2911e2 Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Wed, 30 Oct 2024 17:38:56 +0100 Subject: [PATCH 06/22] Fix: Disable slices not hiding the slices section in the home page (#797) * update select_language_label helper to select f no english found any language remaining over the not tagged * hide the slices section in the home page if slices disabled --- app/helpers/application_helper.rb | 3 +++ app/views/home/index.html.haml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index acf5335c1c..6d565bdb22 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -121,6 +121,9 @@ def onts_for_select(include_views: false) onts_for_select end + def slices_enabled? + $ENABLE_SLICES.eql?(true) + end def at_slice? !@subdomain_filter.nil? && !@subdomain_filter[:active].nil? && @subdomain_filter[:active] == true diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 253e0546ad..8bc39eba97 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -176,7 +176,7 @@ .home-statistics-link.justify-content-end{style: @analytics.empty? && "visibility: hidden"} = link_to t("home.see_details"),'/statistics', target: "_blank" - - if @slices + - if slices_enabled? .home-section .home-section-title .text From f1773c1c09e3014d488906c047215c75bdd3c961 Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:54:09 +0100 Subject: [PATCH 07/22] Feature: update concept mappings table UI (#798) * fix mappings table style * hide relations column when it's completely empty * use icons and Abbreviations types and sources * hide actions column if no mapping is of type REST * update create new mapping button style * remove concept mapping table padding * remove relation column and remove Action title * make the column width for the mapping to and ontology larger * move some mappings helper to the mapping controller as used only there * move the logic from the mapping table view to helpers * fix link text component icon size * change mappings action icons colors to primary color * pass button component in create new mapping instead of using only the css of it * internationalize create new mapping button text * internationalize mapping types description * fix interportal mapping issue when the interportal_hash is empty * limit mapping type tooltip by 300px width --------- Co-authored-by: Syphax --- app/assets/stylesheets/mappings.scss | 25 +++ app/components/link_text_component.rb | 2 +- app/controllers/mappings_controller.rb | 54 +++++- app/helpers/mappings_helper.rb | 174 +++++++++--------- .../mappings/_concept_mappings.html.haml | 17 +- app/views/mappings/_mapping_table.html.haml | 12 +- app/views/mappings/_show_line.html.haml | 57 ++---- config/locales/en.yml | 7 + config/locales/fr.yml | 8 + 9 files changed, 202 insertions(+), 154 deletions(-) diff --git a/app/assets/stylesheets/mappings.scss b/app/assets/stylesheets/mappings.scss index 89a7ebffbe..20ddbb6940 100644 --- a/app/assets/stylesheets/mappings.scss +++ b/app/assets/stylesheets/mappings.scss @@ -320,6 +320,28 @@ div#map_from_concept_details_table, div#map_to_concept_details_table { #concept_mappings_table { width: 100%; + word-break: break-word; + font-size: 13px; +} +.mappings-table-mapping-to{ + width: 45%; +} +.mappings-table-mapping-to .chip-button-component-container{ + text-wrap: wrap !important; +} +.mappings-table-mapping-to a{ + background-color: unset; + line-height: unset; + padding: unset; + font-weight: unset; + font-size: unset; +} +.mappings-table-icon{ + width: 18px; + height: 18px; +} +.mappings-table-icon path{ + fill: var(--gray-color); } .summary-mappings-tab-table { @@ -341,4 +363,7 @@ div#map_from_concept_details_table, div#map_to_concept_details_table { padding: 10px; outline: none; margin-left: 0 !important; +} +.mappings-table-actions svg path{ + fill: var(--primary-color); } \ No newline at end of file diff --git a/app/components/link_text_component.rb b/app/components/link_text_component.rb index 47ea0f6dfc..36dc79ba33 100644 --- a/app/components/link_text_component.rb +++ b/app/components/link_text_component.rb @@ -10,7 +10,7 @@ def initialize(text:, icon: nil, target: nil) end def call - svg_icon = !@icon&.empty? ? inline_svg(@icon) : '' + svg_icon = !@icon&.empty? ? inline_svg(@icon, width: '14px', height: '14px') : '' extra_span = @text == t('mappings.upload_mappings') ? '' : "#{svg_icon}" "#{@text}#{extra_span}".html_safe end diff --git a/app/controllers/mappings_controller.rb b/app/controllers/mappings_controller.rb index b1bcfc8c32..df582acb4e 100644 --- a/app/controllers/mappings_controller.rb +++ b/app/controllers/mappings_controller.rb @@ -342,4 +342,56 @@ def valid_values?(values) end errors end -end \ No newline at end of file + + def set_mapping_target(concept_to_id:, ontology_to:, mapping_type: ) + case mapping_type + when 'interportal' + @map_to_interportal, @map_to_interportal_ontology = ontology_to.match(%r{(.*)/ontologies/(.*)}).to_a[1..] + @map_to_interportal_class = concept_to_id + when 'external' + @map_to_external_ontology = ontology_to + @map_to_external_class = concept_to_id + else + @map_to_bioportal_ontology_id = ontology_to + @map_to_bioportal_full_id = concept_to_id + end + end + + def get_mappings_target_params + mapping_type = Array(params[:mapping_type]).first + external = true + case mapping_type + when 'interportal' + ontology_to = "#{params[:map_to_interportal]}/ontologies/#{params[:map_to_interportal_ontology]}" + concept_to_id = params[:map_to_interportal_class] + when 'external' + ontology_to = params[:map_to_external_ontology] + concept_to_id = params[:map_to_external_class] + else + ontology_to = params[:map_to_bioportal_ontology_id] + concept_to_id = params[:map_to_bioportal_full_id] + external = false + end + [ontology_to, concept_to_id, external] + end + + def get_mappings_target + ontology_to, concept_to_id, external_mapping = get_mappings_target_params + target = '' + if external_mapping + target_ontology = ontology_to + target = concept_to_id + else + if helpers.link?(ontology_to) + target_ontology = LinkedData::Client::Models::Ontology.find(ontology_to) + else + target_ontology = LinkedData::Client::Models::Ontology.find_by_acronym(ontology_to).first + end + if target_ontology + target = target_ontology.explore.single_class(concept_to_id).id + target_ontology = target_ontology.id + end + end + [target_ontology, target, external_mapping] + end +end diff --git a/app/helpers/mappings_helper.rb b/app/helpers/mappings_helper.rb index bfe583a41b..c1e503b547 100644 --- a/app/helpers/mappings_helper.rb +++ b/app/helpers/mappings_helper.rb @@ -2,43 +2,85 @@ module MappingsHelper # Used to replace the full URI by the prefixed URI RELATIONSHIP_PREFIX = { - "http://www.w3.org/2004/02/skos/core#" => "skos:", - "http://www.w3.org/2000/01/rdf-schema#" => "rdfs:", - "http://www.w3.org/2002/07/owl#" => "owl:", - "http://www.w3.org/1999/02/22-rdf-syntax-ns#" => "rdf:", - "http://purl.org/linguistics/gold/" => "gold:", - "http://lemon-model.net/lemon#" => "lemon:" + 'http://www.w3.org/2004/02/skos/core#' => 'skos:', + 'http://www.w3.org/2000/01/rdf-schema#' => 'rdfs:', + 'http://www.w3.org/2002/07/owl#' => 'owl:', + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf:', + 'http://purl.org/linguistics/gold/' => 'gold:', + 'http://lemon-model.net/lemon#' => 'lemon:' } INTERPORTAL_HASH = $INTERPORTAL_HASH - - # a little method that returns true if the URIs array contain a gold:translation or gold:freeTranslation - def translation?(relation_array) - if relation_array.kind_of?(Array) - relation_array.map!(&:downcase) - if relation_array.include? "http://purl.org/linguistics/gold/translation" - true - elsif relation_array.include? "http://purl.org/linguistics/gold/freetranslation" - true - else - false + def mapping_links(mapping, concept) + target_concept = mapping.classes.select do |c| + c.id != concept.id && c.links['ontology'] != concept.links['ontology'] + end.first + target_concept ||= mapping.classes.last + process = mapping.process || {} + + if inter_portal_mapping?(target_concept) + cls_link = ajax_to_inter_portal_cls(target_concept) + ont_name = target_concept.links['ontology'] + ont_link = link_to ont_name, get_inter_portal_ui_link(ont_name, process['name']), target: '_blank' + source_tooltip = 'Internal-portal' + elsif internal_mapping?(target_concept) + begin + ont = target_concept.explore.ontology + ont_name = ont.acronym + ont_link = link_to ont_name, ontology_path(ont_name), 'data-turbo-frame': '_top' + rescue + ont_name = target_concept.links['ontology'] || target_concept.id + ont_link = ont_name end + cls_link = raw(get_link_for_cls_ajax(target_concept.id, ont_name, '_top')) + source_tooltip = 'Internal' else - false + cls_label = ExternalLinkTextComponent.new(text: target_concept.links['self']).call + cls_link = raw("#{cls_label}") + ont_name = target_concept.links['ontology'] + ont_link = link_to ExternalLinkTextComponent.new(text: ont_name).call, target_concept.links['ontology'], + target: '_blank' + source_tooltip = 'External' end + + [cls_link, ont_link, source_tooltip] + end + + def mapping_prefixed_relations(mapping) + process = mapping.process || {} + Array(process[:relation]).each { |relation| get_prefixed_uri(relation) } + end + + def mapping_type_tooltip(map) + relations = mapping_prefixed_relations(map) + process = map.process || {} + type = if map.source.to_s.include? 'SKOS' + 'SKOS' + else + map.source + end + types_description = { + 'CUI' => t('mappings.types_description.cui'), + 'LOOM' => t('mappings.types_description.loom'), + 'REST' => t('mappings.types_description.rest'), + 'SAME_URI' => t('mappings.types_description.same_uri'), + 'SKOS' => t('mappings.types_description.skos') + } + type_tooltip = content_tag(:div, "#{map.source} #{relations.join(', ')} : #{types_description[type]} #{process[:source_name]}".strip, style: 'width: 300px') + [type, type_tooltip] end # a little method that returns the uri with a prefix : http://purl.org/linguistics/gold/translation become gold:translation def get_prefixed_uri(uri) RELATIONSHIP_PREFIX.each { |k, v| uri.sub!(k, v) } - return uri + uri end # method to get (using http) prefLabel for interportal classes # Using bp_ajax_controller.ajax_process_interportal_cls will try to resolve class labels. def ajax_to_inter_portal_cls(cls) - inter_portal_acronym = get_inter_portal_acronym(cls.links["ui"]) + inter_portal_acronym = get_inter_portal_acronym(cls.links['ui']) href_cls = " href='#{cls.links["ui"]}' " if inter_portal_acronym data_cls = " data-cls='#{cls.links["self"]}?apikey=' " @@ -52,7 +94,7 @@ def ajax_to_inter_portal_cls(cls) def ajax_to_internal_cls(cls) link_to("#{cls.id}".html_safe, - ontology_path(cls.explore.ontology.acronym, p: 'classes', conceptid: cls.id), target: "_blank") + ontology_path(cls.explore.ontology.acronym, p: 'classes', conceptid: cls.id), target: '_blank') end # to get the apikey from the interportal instance of the interportal class. @@ -60,7 +102,7 @@ def ajax_to_internal_cls(cls) def get_inter_portal_acronym(class_ui_url) if !INTERPORTAL_HASH.nil? INTERPORTAL_HASH.each do |key, value| - if class_ui_url.start_with?(value["ui"]) + if class_ui_url.start_with?(value['ui']) return key else return nil @@ -71,11 +113,11 @@ def get_inter_portal_acronym(class_ui_url) # method to extract the prefLabel from the external class URI def get_label_for_external_cls(class_uri) - if class_uri.include? "#" - prefLabel = class_uri.split("#")[-1] - else - prefLabel = class_uri.split("/")[-1] - end + prefLabel = if class_uri.include? '#' + class_uri.split('#')[-1] + else + class_uri.split('/')[-1] + end return prefLabel end @@ -86,11 +128,11 @@ def ajax_to_external_cls(cls) # Replace the inter_portal mapping ontology URI (that link to the API) by the link to the ontology in the UI def get_inter_portal_ui_link(uri, process_name) process_name = '' if process_name.nil? - interportal_acronym = process_name.split(" ")[2] - if interportal_acronym.nil? || interportal_acronym.empty? + interportal_acronym = process_name.split(' ')[2] + if interportal_acronym.nil? || interportal_acronym.empty? || INTERPORTAL_HASH[interportal_acronym].nil? uri else - uri.sub!(INTERPORTAL_HASH[interportal_acronym]["api"], INTERPORTAL_HASH[interportal_acronym]["ui"]) + uri.sub!(INTERPORTAL_HASH[interportal_acronym]['api'], INTERPORTAL_HASH[interportal_acronym]['ui']) end end @@ -99,66 +141,14 @@ def internal_mapping?(cls) end def inter_portal_mapping?(cls) - !internal_mapping?(cls) && cls.links.has_key?("ui") - end - - def get_mappings_target_params - mapping_type = Array(params[:mapping_type]).first - external = true - case mapping_type - when 'interportal' - ontology_to = "#{params[:map_to_interportal]}/ontologies/#{params[:map_to_interportal_ontology]}" - concept_to_id = params[:map_to_interportal_class] - when 'external' - ontology_to = params[:map_to_external_ontology] - concept_to_id = params[:map_to_external_class] - else - ontology_to = params[:map_to_bioportal_ontology_id] - concept_to_id = params[:map_to_bioportal_full_id] - external = false - end - [ontology_to, concept_to_id, external] - end - - def set_mapping_target(concept_to_id:, ontology_to:, mapping_type: ) - case mapping_type - when 'interportal' - @map_to_interportal, @map_to_interportal_ontology = ontology_to.match(%r{(.*)/ontologies/(.*)}).to_a[1..] - @map_to_interportal_class = concept_to_id - when 'external' - @map_to_external_ontology = ontology_to - @map_to_external_class = concept_to_id - else - @map_to_bioportal_ontology_id = ontology_to - @map_to_bioportal_full_id = concept_to_id - end - end - - def get_mappings_target - ontology_to, concept_to_id, external_mapping = get_mappings_target_params - target = '' - if external_mapping - target_ontology = ontology_to - target = concept_to_id - else - if helpers.link?(ontology_to) - target_ontology = LinkedData::Client::Models::Ontology.find(ontology_to) - else - target_ontology = LinkedData::Client::Models::Ontology.find_by_acronym(ontology_to).first - end - if target_ontology - target = target_ontology.explore.single_class(concept_to_id).id - target_ontology = target_ontology.id - end - end - [target_ontology, target, external_mapping] + !internal_mapping?(cls) && cls.links.has_key?('ui') end def type?(type) @mapping_type.nil? && type.eql?('internal') || @mapping_type.eql?(type) end - def concept_mappings_loader(ontology_acronym: ,concept_id: ) + def concept_mappings_loader(ontology_acronym:, concept_id:) content_tag(:span, id: 'mapping_count') do concat(content_tag(:div, class: 'concepts-mapping-count ml-1 mr-1') do render(TurboFrameComponent.new( @@ -173,21 +163,23 @@ def concept_mappings_loader(ontology_acronym: ,concept_id: ) end def client_filled_modal - link_to_modal "", "" + link_to_modal '', '' end def mappings_bubble_view_legend content_tag(:div, class: 'mappings-bubble-view-legend') do - mappings_legend_section(t('mappings.bubble_view_legend.bubble_size'), t('mappings.bubble_view_legend.bubble_size_desc'), 'mappings-bubble-size-legend') + + mappings_legend_section(t('mappings.bubble_view_legend.bubble_size'), + t('mappings.bubble_view_legend.bubble_size_desc'), 'mappings-bubble-size-legend') + mappings_legend_section( - t('mappings.bubble_view_legend.color_degree'),t('mappings.bubble_view_legend.color_degree_desc'),'mappings-bubble-color-legend') + + t('mappings.bubble_view_legend.color_degree'), t('mappings.bubble_view_legend.color_degree_desc'), 'mappings-bubble-color-legend') + content_tag(:div, class: 'content-container') do content_tag(:div, class: 'bubble-view-legend-item') do content_tag(:div, class: 'title') do - content_tag(:div, t('mappings.bubble_view_legend.yellow_bubble'), class: 'd-inline') + content_tag(:span, t('mappings.bubble_view_legend.selected_bubble')) + content_tag(:div, t('mappings.bubble_view_legend.yellow_bubble'), + class: 'd-inline') + content_tag(:span, t('mappings.bubble_view_legend.selected_bubble')) end + - content_tag(:div, class: "mappings-bubble-size-legend d-flex justify-content-center") do - content_tag(:div, '', class: "bubble yellow") + content_tag(:div, class: 'mappings-bubble-size-legend d-flex justify-content-center') do + content_tag(:div, '', class: 'bubble yellow') end end end @@ -209,7 +201,7 @@ def mappings_legend_section(title_text, description_text, css_class) def mappings_legend(css_class) content_tag(:div, class: css_class) do content_tag(:div, t('mappings.bubble_view_legend.less_mappings'), class: 'mappings-legend-text') + - (1..6).map { |i| content_tag(:div, "", class: "bubble bubble#{i}") }.join.html_safe + + (1..6).map { |i| content_tag(:div, '', class: "bubble bubble#{i}") }.join.html_safe + content_tag(:div, t('mappings.bubble_view_legend.more_mappings'), class: 'mappings-legend-text') end end diff --git a/app/views/mappings/_concept_mappings.html.haml b/app/views/mappings/_concept_mappings.html.haml index c71fe9066b..2a6b56b29e 100644 --- a/app/views/mappings/_concept_mappings.html.haml +++ b/app/views/mappings/_concept_mappings.html.haml @@ -2,17 +2,16 @@ = "#{@mappings.size}" = turbo_frame_tag @type.eql?('modal') ? 'application_modal_content' : 'concept_mappings' do - %div{:style => "padding: 1%; width: 98%"} + %div.p-1 - if session[:user].nil? = link_to "Create New Mapping", "/login?redirect=/ontologies/#{@ontology.acronym}/?p=classes&t=mappings&conceptid=#{escape(@concept.id)}", :method => :get, :class => "btn btn-default mb-3" - else - = link_to_modal("Create New Mapping", - new_mapping_path(ontology_from: "#{@ontology.id}", conceptid_from: "#{@concept.id}"), - id: "new_mapping_btn", - role: "button", - class: "btn btn-default mb-3", - data: { show_modal_title_value: "Create a new mapping for #{@concept.prefLabel}" }, - ) + %div{style: 'width: 250px; margin: 0 0 10px 0;'} + = link_to_modal(nil, + new_mapping_path(ontology_from: "#{@ontology.id}", conceptid_from: "#{@concept.id}"), + data: { show_modal_title_value: "Create a new mapping for #{@concept.prefLabel}" }, + ) do + = render Buttons::RegularButtonComponent.new(id:'new_mapping_btn' , value:t('mappings.create_new_mapping'), variant: 'secondary', size: 'slim', state: 'no-anim') #mapping_details - = render :partial => '/mappings/mapping_table' \ No newline at end of file + = render :partial => '/mappings/mapping_table' diff --git a/app/views/mappings/_mapping_table.html.haml b/app/views/mappings/_mapping_table.html.haml index 1d91b3b5bb..20efcd92d5 100644 --- a/app/views/mappings/_mapping_table.html.haml +++ b/app/views/mappings/_mapping_table.html.haml @@ -1,16 +1,14 @@ = check_box_tag "delete_mappings_permission", @delete_mapping_permission, @delete_mapping_permission, style: "display: none;" %div#concept_mappings_tables_div = render_alerts_container(MappingsController) - %table#concept_mappings_table.table-content-stripped.table-content{width: "100%", style:'word-break: break-word'} + %table#concept_mappings_table.table-content-stripped.table-content.table-mini %thead %tr %th= t("mappings.mapping_table.mapping_to") - %th{width: "30%"}= t("mappings.count.ontology") - %th= t("mappings.mapping_table.relations") - %th= t("mappings.mapping_table.source") + %th= t("mappings.count.ontology") %th= t("mappings.mapping_table.type") - - if current_user_admin? - %th{:class => 'delete_mappings_column'}= t("mappings.mapping_table.actions") + - if current_user_admin? && !@mappings.all? { |obj| !obj.source.eql?('REST') } + %th{:class => 'delete_mappings_column'} %tbody#concept_mappings_table_content - @mappings.each do |map| = render partial: 'mappings/show_line' , locals: {map: map, concept: @concept} @@ -19,4 +17,4 @@ :javascript jQuery(document).ready(function(){ ajax_process_init(); - }) \ No newline at end of file + }) diff --git a/app/views/mappings/_show_line.html.haml b/app/views/mappings/_show_line.html.haml index bbfab2b78e..4c94555c4d 100644 --- a/app/views/mappings/_show_line.html.haml +++ b/app/views/mappings/_show_line.html.haml @@ -1,56 +1,23 @@ -- process = map.process || {} -- source = "#{map.source} #{process[:source_name]}" -- relations = process[:relation]&.each { |relation| get_prefixed_uri(relation)} +- type, type_tooltip = mapping_type_tooltip(map) +- cls_link, ont_link, source_tooltip = mapping_links(map, concept) - map_id = map.id.to_s.split("/").last -- target_concept = map.classes.select {|target_concept| target_concept.id != concept.id && target_concept.links['ontology'] != concept.links['ontology']}.first || map.classes.last -- if inter_portal_mapping?(target_concept) - - cls_link = ajax_to_inter_portal_cls(target_concept) - - ont_name = target_concept.links['ontology'] - - ont_acronym = ont_name - - ont_link = link_to ont_acronym , get_inter_portal_ui_link(target_concept.links['ontology'], process["name"]), target: '_blank' - - type = 'Inter-portal' -- elsif internal_mapping?(target_concept) - - begin - - ont = target_concept.explore.ontology - - ont_name = ont.acronym - - ont_link = link_to ont_name, ontology_path(ont_name), 'data-turbo-frame':'_top' - - rescue - - ont_name = target_concept.links['ontology'] || target_concept.id - - ont_link = ont_name - - cls_link = raw(get_link_for_cls_ajax(target_concept.id, ont_name, '_top')) - - type = 'Internal' -- else - - cls_label = get_label_for_external_cls(target_concept.links["self"]) - - cls_link = raw("#{cls_label}") - - ont_name = target_concept.links['ontology'] - - ont_link = link_to ont_name, target_concept.links['ontology'], target: "_blank" - - type = 'External' - %tr.human{:id => map_id} - %td + %td.mappings-table-mapping-to = cls_link - %td + %td.mappings-table-mapping-to = ont_link %td - - relations&.each do |r| - = r - %br/ - %td - #{source} - - if !process.nil? - - if translation?(process["relation"]) - %img{:src => asset_path('sifr/english_language_flag.png'), :style => "padding: 5px", :align => "right", :title => "Traduction"} - %td - = type + = render ChipButtonComponent.new(class: 'chip_button_small mr-1', text: type, tooltip:"#{source_tooltip} mapping of type #{type_tooltip}") + - if current_user_admin? %td{:class => 'delete_mappings_column'} - if map.id && !map.id.empty? && session[:user] && (session[:user].id.to_i == map.creator || session[:user].admin?) && map.source.eql?('REST') - %div.d-flex - = link_to_modal(t("mappings.show_line.edit_modal"), + %div.d-flex.mappings-table-actions + = link_to_modal(nil, mapping_path(map_id, {conceptid_from: @concept.id}), - role: "button", - class: "btn btn-link", + class: 'btn btn-link p-0 mr-1', data: { show_modal_title_value: t("mappings.show_line.edit_mapping", preflabel: @concept.prefLabel)}, - ) - = button_to t("mappings.show_line.delete_button"), CGI.unescape(mapping_path(map.id)), method: :delete, class:'btn btn-link', form: {data: { turbo: true, turbo_confirm: t("mappings.show_line.turbo_confirm"), turbo_frame: '_top'}} \ No newline at end of file + ) do + = inline_svg_tag "edit.svg", width: '15px', height: '15px' + = button_to inline_svg_tag('icons/delete.svg', width: '16px', heigth: '16px'), CGI.unescape(mapping_path(map.id)), class: 'btn btn-link p-0', method: :delete, form: {data: { turbo: true, turbo_confirm: t("mappings.show_line.turbo_confirm"), turbo_frame: '_top'}} diff --git a/config/locales/en.yml b/config/locales/en.yml index 4f9ee4c48b..a63e3500eb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -572,12 +572,19 @@ en: date: Date ontology_visits: Ontology visits mappings: + create_new_mapping: Create new mapping all: All description: Dive into an overview of the mappings in the bubble view, efficiently locate a specific ontology in the table view or upload your own mappings. tabs: bubble_view: Bubbles view table_view: Table view upload_mappings: Upload mappings + types_description: + cui: Created between 2 concepts that have the same CUI (Concept Unique Identifiers) + loom: Lexical mappings created between 2 concepts with very similar labels (preferred name) + rest: A mapping added by a user using the REST API (or the UI, which is calling the API to create it) + same_uri: Created between 2 concepts with the same URI. + skos: Mappings based on SKOS relationships, (e.g. skos:exactMatch or skos:closeMatch) filter_ontologies: Filter ontologies in the bubble view filter_bubbles: Filter bubbles external_mappings: "External Mappings (%{number_with_delimiter})" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 0b319d391e..d0969e5795 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -580,12 +580,20 @@ fr: ontology_visits: Visites d'ontologies mappings: + create_new_mapping: Créer un nouveau mapping all: Tous description: Plongez dans une vue d'ensemble des mappings dans la vue en bulles, localisez efficacement une ontologie spécifique dans la vue en tableau ou téléchargez vos propres mappings. tabs: bubble_view: Vue en bulles table_view: Vue en tableau upload_mappings: Télécharger des mappings + types_description: + cui: Créé entre 2 concepts ayant le même CUI (Identifiants Uniques de Concepts) + loom: Mappings lexicaux créés entre 2 concepts avec des libellés très similaires (nom préféré) + rest: Un mapping ajouté par un utilisateur via l'API REST (ou l'interface utilisateur, qui appelle l'API pour le créer) + same_uri: Créé entre 2 concepts ayant la même URI. + skos: Mapping basés sur des relations SKOS (par exemple, skos:exactMatch ou skos:closeMatch) + filter_ontologies: Filtrer les ontologies dans la vue en bulles filter_bubbles: Filtrer les bulles external_mappings: "Mappings externes (%{number_with_delimiter})" From b7318e03ccce5777ed05695e90852970ceaf4c43 Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:41:33 +0100 Subject: [PATCH 08/22] Fix: Browse page switch style, and don't display current portal name button in browse results (#828) * fix broken switch style when using a long text with it * don't show current portal name button in browse page results * adjest switch text max-width only for browse filter * don't show portal name only if it's unique in browse page federated results --- app/assets/stylesheets/browse.scss | 3 +++ app/controllers/concerns/submission_filter.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/app/assets/stylesheets/browse.scss b/app/assets/stylesheets/browse.scss index a55292bde0..57e857442c 100644 --- a/app/assets/stylesheets/browse.scss +++ b/app/assets/stylesheets/browse.scss @@ -266,6 +266,9 @@ z-index: 1; } +.browse-filter .switch-filter > p, .switch-filter > div{ + max-width: 207px; +} .browse-search-bar input:focus { box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px; diff --git a/app/controllers/concerns/submission_filter.rb b/app/controllers/concerns/submission_filter.rb index c039147280..5bb9937e1a 100644 --- a/app/controllers/concerns/submission_filter.rb +++ b/app/controllers/concerns/submission_filter.rb @@ -72,6 +72,7 @@ def merge_by_acronym(submissions) submissions.group_by { |x| x[:ontology]&.acronym }.each do |acronym, ontologies| ontology = canonical_ontology(ontologies) ontology[:sources] = ontologies.map { |x| x[:id] } + ontology[:sources].reject! { |id| id.include?(portal_name.downcase) } if ontology[:sources].size.eql?(1) merged_submissions << ontology end merged_submissions From a9dd3b7148f426434cdce965a118f5d271a9434e Mon Sep 17 00:00:00 2001 From: Bilel Kihal <61744974+Bilelkihal@users.noreply.github.com> Date: Thu, 7 Nov 2024 05:32:42 +0100 Subject: [PATCH 09/22] Fix: Search federation duplicated results merging issue (#830) * replace unexisting key :ontology_acronym and get the ontology acronym from the ontology_id when checking ontology duplication in federation * clean code of merge federated results method --- app/controllers/concerns/search_aggregator.rb | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/app/controllers/concerns/search_aggregator.rb b/app/controllers/concerns/search_aggregator.rb index 078c89c5c9..f1f074272f 100644 --- a/app/controllers/concerns/search_aggregator.rb +++ b/app/controllers/concerns/search_aggregator.rb @@ -251,17 +251,15 @@ def blacklist_cls_id_components(cls_id, blacklist_words) def merge_federated_results(search_results) search_results.each do |element| element[:root][:other_portals] = [] + element[:reuses].reject! do |reuse| - if (element[:root][:ontology_acronym] == reuse[:root][:ontology_acronym]) && (element[:root][:uri] == reuse[:root][:uri]) - portal_name = reuse[:root][:portal_name] - link = reuse[:root][:link] - element[:root][:other_portals] << { - name: portal_name, - color: federated_portal_color(portal_name), - light_color: federated_portal_light_color(portal_name), - link: link, - ontology_id: reuse[:root][:ontology_id] - } + element_ontology_id = element[:root][:ontology_id].split('/').last + element_uri = element[:root][:uri] + reuse_ontology_id = reuse[:root][:ontology_id].split('/').last + reuse_uri = reuse[:root][:uri] + + if element_ontology_id == reuse_ontology_id && element_uri == reuse_uri + element[:root][:other_portals] << build_other_portal_entry(reuse) true else false @@ -270,6 +268,16 @@ def merge_federated_results(search_results) end end + def build_other_portal_entry(reuse) + { + name: reuse[:root][:portal_name], + color: federated_portal_color(reuse[:root][:portal_name]), + light_color: federated_portal_light_color(reuse[:root][:portal_name]), + link: reuse[:root][:link], + ontology_id: reuse[:root][:ontology_id] + } + end + def swap_canonical_portal_results_first(search_results) all_submissions = LinkedData::Client::Models::OntologySubmission.all(include: 'pullLocation', include_views: true, display_links: false, display_context: false) From a3b1d97e034a6500d703d1c94487e8ef5057b0f3 Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Thu, 7 Nov 2024 10:15:19 +0100 Subject: [PATCH 10/22] Feature: Migrate Label Ajax stimulus and Jquery code to Turbo (#821) * update select_language_label helper to select f no english found any language remaining over the not tagged * disable label ajax container * create label fetch component that for a id/uri fetch its label if found * add the possibility for the turbo frame to have custom error messages * remove and replace ontology entities link helpers * replace the label-ajax stimulus with turbo frame using ajax_link_chip * fix an uncatched error in concept label helper * remove label-ajax stimulus code * remove bp_ajax_controller old js code and update mappings to use the label fetcher component * fix bug of not opening eternal mapping details popup * remove label_link component * add a helper for the label fetcher component for clarity * add extern_link argument to ajax_link_chip to enforce external or not --- app/assets/javascripts/application.js | 3 - app/assets/javascripts/bp_ajax_controller.js | 187 ------------------ .../chip_button_component.html.haml | 2 +- app/components/label_fetcher_component.rb | 56 ++++++ .../label_fetcher_component.html.haml | 10 + app/components/label_link_component.rb | 22 --- app/components/turbo_frame_component.rb | 1 + .../turbo_frame_component.html.haml | 8 +- app/controllers/collections_controller.rb | 11 +- app/controllers/concepts_controller.rb | 16 +- app/controllers/label_xl_controller.rb | 7 +- app/controllers/mappings_controller.rb | 3 +- app/controllers/schemes_controller.rb | 13 +- app/helpers/application_helper.rb | 96 ++------- app/helpers/collections_helper.rb | 10 +- app/helpers/components_helper.rb | 4 + app/helpers/concepts_helper.rb | 16 +- app/helpers/mappings_helper.rb | 39 ++-- app/helpers/schemes_helper.rb | 11 +- app/javascript/controllers/index.js | 6 - .../controllers/label_ajax_controller.js | 83 -------- .../labels_ajax_container_controller.js | 10 - .../turbo_frame_error_controller.js | 5 +- app/views/collections/_list_view.html.haml | 2 +- app/views/concepts/_show.html.haml | 2 +- app/views/mappings/_mapping_table.html.haml | 4 - app/views/mappings/_show.html.haml | 9 +- 27 files changed, 162 insertions(+), 474 deletions(-) delete mode 100644 app/assets/javascripts/bp_ajax_controller.js create mode 100644 app/components/label_fetcher_component.rb create mode 100644 app/components/label_fetcher_component/label_fetcher_component.html.haml delete mode 100644 app/components/label_link_component.rb delete mode 100644 app/javascript/controllers/label_ajax_controller.js delete mode 100644 app/javascript/controllers/labels_ajax_container_controller.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 1a42c65807..617e38d373 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,7 +12,6 @@ // //= require bioportal //= require admin/licenses -//= require bp_ajax_controller //= require bp_notes //= require bp_form_complete //= require bp_admin @@ -20,5 +19,3 @@ //= require projects //= require Chart.min //= require application_esbuild - - diff --git a/app/assets/javascripts/bp_ajax_controller.js b/app/assets/javascripts/bp_ajax_controller.js deleted file mode 100644 index a67e66550a..0000000000 --- a/app/assets/javascripts/bp_ajax_controller.js +++ /dev/null @@ -1,187 +0,0 @@ - -"use strict"; - -// Note similar code in concepts_helper.rb mirrors the following code: -function bp_ont_link(ont_acronym){ - return "/ontologies/" + ont_acronym; -} -function bp_cls_link(cls_id, ont_acronym){ - return bp_ont_link(ont_acronym) + "?p=classes&conceptid=" + encodeURIComponent(cls_id); -} -function get_link_for_cls_ajax(cls_id, ont_acronym) { - // ajax call will replace the class label using data attributes (triggered by class='cls4ajax') - let ajax_uri = '/ajax/classes/label' - let data_cls = `data-label-ajax-cls-id-value='${cls_id}' ` - let data_ont = `data-label-ajax-ontology-acronym-value='${ont_acronym}'` - let data_ajax_uri = `data-label-ajax-ajax-uri-value='${ajax_uri}' ` - - let data = `data-controller='label-ajax' ${data_ont} ${data_cls} ${data_ajax_uri}` - - return `${cls_id}` -} - -function get_link_for_ont_ajax(ont_acronym) { - var data_ont = " data-ont='" + ont_acronym + "' "; - return "" + ont_acronym + ""; -} - -var - ajax_process_interportal_cls_interval = null, - ajax_process_ont_interval = null, - ajax_process_timeout = 20, // Timeout after 20 sec. - ajax_process_timing = 250; // It takes about 250 msec to resolve a class ID to a prefLabel - -var ajax_process_init = function () { - ajax_process_ont_init(); - ajax_process_interportal_cls_init(); -}; - -var ajax_process_halt = function () { - ajax_process_ont_halt(); - ajax_process_interportal_cls_halt(); -}; - - -// ************************************************************************************** -// ONTOLOGY NAMES - -// Note: If we don't query every time, using the array should be faster; it -// means the ajax_ont_init must be called after all the elements -// are created because they will not be detected in a dynamic iteration. -var ajax_ont_array = []; -var ajax_process_ont_init = function() { - ajax_ont_array = jQuery("a.ont4ajax").toArray(); - ajax_process_ont_interval = window.setInterval(ajax_process_ont, ajax_process_timing); -}; -var ajax_process_ont_halt = function () { - ajax_ont_array = []; - window.clearInterval(ajax_process_ont_interval); // stop the ajax process - // Note: might leave faulty href links, but it usually means moving on to entirely different content - // so it's not likely those links will be available for interaction. - // clear all the classes and ontologies to be resolved by ajax - //jQuery("a.ont4ajax").removeClass('ont4ajax'); - //jQuery("a.ajax-modified-ont").removeClass('ajax-modified-ont'); -}; -var ajax_process_ont = function() { - if( ajax_ont_array.length === 0 ){ - ajax_process_ont_halt(); - return true; - } - // Note: If we don't query every time, using the array should be faster; it - // means the ajax_ont_init must be called after all the elements - // are created because they will not be detected in a dynamic iteration. - //var linkA = jQuery("a.ont4ajax").first(); - var linkA = ajax_ont_array.shift(); - if(linkA === undefined){ - return true; - } - linkA = jQuery(linkA); - if(linkA.hasClass('ajax-modified-ont') ){ - // How did we get here? It should not have the ont4ajax class! - linkA.removeClass('ont4ajax'); - return true; // processed this one already. - } - linkA.removeClass('ont4ajax'); // processing this one. - var ont_acronym = linkA.attr('data-ont'); - var ajax_uri = "/ajax/json_ontology/?ontology=" + encodeURIComponent(ont_acronym); - jQuery.ajax({ - url: ajax_uri, - timeout: ajax_process_timeout * 1000, - success: function(data){ - if(typeof data !== "undefined" && data.hasOwnProperty('name')){ - var ont_name = data.name; - linkA.text(ont_name); - linkA.addClass('ajax-modified-ont'); // processed this one. - // find and process any identical ontologies - jQuery('a[href="/ontologies/' + data.acronym + '"]').each(function(i,e){ - var link = jQuery(this); - if(! link.hasClass('ajax-modified-ont') ){ - link.removeClass('ont4ajax'); // processing this one. - link.text(ont_name); - link.addClass('ajax-modified-ont'); // processed this one. - } - }); - } - }, - error: function(data){ - linkA.addClass('ajax-error'); // processed this one. - } - }); -}; - - -// ************************************************************************************** -// INTERPORTAL CLASS LABELS - -// Note: If we don't query every time, using the array should be faster; it -// means the ajax_process_init must be called after all the elements -// are created because they will not be detected in a dynamic iteration. -var ajax_interportal_cls_array = []; - -var ajax_process_interportal_cls_init = function() { - ajax_interportal_cls_array = jQuery("a.interportalcls4ajax").toArray(); - ajax_process_interportal_cls_interval = window.setInterval(ajax_process_interportal_cls, ajax_process_timing); -}; - -var ajax_process_interportal_cls_halt = function () { - ajax_interportal_cls_array = []; - window.clearInterval(ajax_process_interportal_cls_interval); // stop the ajax process - // Note: might leave faulty href links, but it usually means moving on to entirely different content - // so it's not likely those links will be available for interaction. - // clear all the classes and ontologies to be resolved by ajax - //jQuery("a.cls4ajax").removeClass('cls4ajax'); - //jQuery("a.ajax-modified-cls").removeClass('ajax-modified-cls'); -}; - -var ajax_process_interportal_cls = function() { - // Check on whether to stop the ajax process - if( ajax_interportal_cls_array.length === 0 ){ - ajax_process_interportal_cls_halt(); - return true; - } - // Note: If we don't query every time, using the array should be faster; it - // means the ajax_process_init must be called after all the elements - // are created because they will not be detected in a dynamic iteration. - //var linkA = jQuery("a.cls4ajax").first(); - var linkA = ajax_interportal_cls_array.shift(); // put first item in linkA and delete it from array - if(linkA === undefined){ - return true; - } - linkA = jQuery(linkA); - if(linkA.hasClass('ajax-modified-cls') ){ - // How did we get here? It should not have the interportalcls4ajax class! - linkA.removeClass('interportalcls4ajax'); - return true; // processing or processed this one already. - } - linkA.removeClass('interportalcls4ajax'); // processing this one. - var unique_id = linkA.attr('href'); - - var portal_acronym = linkA.attr('portal-cls'); - var ajax_uri = linkA.attr('data-cls') + jQuery(document).data().bp.config.interportal_hash[portal_acronym].apikey; - jQuery.ajax({ - url: ajax_uri, - timeout: ajax_process_timeout * 1000, - success: function(data){ - var label = data.prefLabel - if (typeof label !== "undefined" && label.length > 0) { - linkA.html(label); - linkA.addClass('ajax-modified-cls'); - // find and process any identical classes (low probability) - jQuery( 'a[href="' + unique_id + '"]').each(function(i,e){ - var link = jQuery(this); - if(! link.hasClass('ajax-modified-cls') ){ - link.removeClass('interportalcls4ajax'); // processing this one. - link.html(label); - link.addClass('ajax-modified-cls'); // processed this one. - } - }); - } else { - // remove the unique_id separator and the ontology acronym from the href - linkA.addClass('ajax-modified-cls'); - } - }, - error: function(data){ - linkA.addClass('ajax-error'); // processed this one. - } - }); -}; diff --git a/app/components/chip_button_component/chip_button_component.html.haml b/app/components/chip_button_component/chip_button_component.html.haml index 26172a5487..f2dd0d3dd0 100644 --- a/app/components/chip_button_component/chip_button_component.html.haml +++ b/app/components/chip_button_component/chip_button_component.html.haml @@ -4,7 +4,7 @@ = @text || content - elsif !content %a.chip_button_container_clickable{@html_options} - = @text + = @text.html_safe - else %span.chip_button_container_clickable{@html_options} = content diff --git a/app/components/label_fetcher_component.rb b/app/components/label_fetcher_component.rb new file mode 100644 index 0000000000..f89f39d16e --- /dev/null +++ b/app/components/label_fetcher_component.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +class LabelFetcherComponent < ViewComponent::Base + include UrlsHelper, Turbo::FramesHelper, ModalHelper + + def initialize(id:, label: nil, link: nil, ajax_src: nil, open_in_modal: false, target: nil, external: false) + super + @id = id + @link = link + @ajax_src = ajax_src + @open_in_modal = open_in_modal + @target = target + @external = external + @label = label + + if external_link? + @link = id + @target ||= '_blank' + else + @target ||= '_top' + end + + end + + def external_link? + (@label.nil? || @label.eql?(@id)) && @external + end + + def label_fetcher_container(&block) + id = "#{escape(@id)}_label" + if @ajax_src + render(TurboFrameComponent.new(id: id, src: "#{@ajax_src}&target=#{@target}", loading: 'lazy')) do |t| + t.loader do + render ChipButtonComponent.new(url: @id, text: "#{@id} #{render(LoaderComponent.new(small: true))}", type: 'clickable', target: '_blank') + end + + t.error do + capture(&block) + end + end + else + turbo_frame_tag(id) do + capture(&block) + end + end + + end + + def link_with_icon + if external_link? + ExternalLinkTextComponent.new(text: @label).call + else + InternalLinkTextComponent.new(text: @label).call + end + end +end diff --git a/app/components/label_fetcher_component/label_fetcher_component.html.haml b/app/components/label_fetcher_component/label_fetcher_component.html.haml new file mode 100644 index 0000000000..80587133d1 --- /dev/null +++ b/app/components/label_fetcher_component/label_fetcher_component.html.haml @@ -0,0 +1,10 @@ += label_fetcher_container do + - if @open_in_modal + = render ChipButtonComponent.new(type: 'clickable') do + = link_to_modal(@label, @link) + - else + %span + = render ChipButtonComponent.new(url: @link, + type: 'clickable', + text: link_with_icon, + target: @target) diff --git a/app/components/label_link_component.rb b/app/components/label_link_component.rb deleted file mode 100644 index 3d8ecee988..0000000000 --- a/app/components/label_link_component.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -class LabelLinkComponent < ViewComponent::Base - - def initialize(id:, text:, icon: 'popup-link') - @id = id - @text = text - @icon = icon - end - - def call - if @id.eql?(@text) - ExternalLinkTextComponent.new(text: @text).call - else - InternalLinkTextComponent.new(text: @text).call - end - end - - def self.inline(id, text) - { plain: LabelLinkComponent.new(id: id, text: text).call } - end -end diff --git a/app/components/turbo_frame_component.rb b/app/components/turbo_frame_component.rb index d25322e154..1e54e24ce8 100644 --- a/app/components/turbo_frame_component.rb +++ b/app/components/turbo_frame_component.rb @@ -4,6 +4,7 @@ class TurboFrameComponent < ViewComponent::Base include Turbo::FramesHelper renders_one :loader + renders_one :error def initialize(id:, src: '', **html_options) @id = id diff --git a/app/components/turbo_frame_component/turbo_frame_component.html.haml b/app/components/turbo_frame_component/turbo_frame_component.html.haml index 1c5d0d9f59..a288d8eaca 100644 --- a/app/components/turbo_frame_component/turbo_frame_component.html.haml +++ b/app/components/turbo_frame_component/turbo_frame_component.html.haml @@ -8,5 +8,9 @@ - else %div.p-3 = render LoaderComponent.new(type: 'pulsing') - %div{'data-turbo-frame-error-target': 'errorMessage', style:'display: none; width: 100%'} - = render Display::AlertComponent.new(type:'danger') \ No newline at end of file + %span{'data-turbo-frame-error-target': 'errorMessage', style:'display: none; width: 100%'} + - if error? + = error + - else + %div + = render Display::AlertComponent.new(type:'danger') diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb index c01c0cf879..fcfda0256d 100644 --- a/app/controllers/collections_controller.rb +++ b/app/controllers/collections_controller.rb @@ -1,7 +1,6 @@ class CollectionsController < ApplicationController include CollectionsHelper,SearchContent - def index acronym = params[:ontology] @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first @@ -47,11 +46,13 @@ def show def show_label collection_label = '' - collection = get_request_collection - collection_label = collection['prefLabel'] if collection - collection_label = params[:id] if collection_label.nil? || collection_label.empty? + collection = get_request_collection + collection_label = collection['prefLabel'] if collection + collection_label = params[:id] if collection_label.nil? || collection_label.empty? - render LabelLinkComponent.inline(params[:id], helpers.main_language_label(collection_label)) + label = helpers.main_language_label(collection_label) + link = collection_path(collection_id: params[:id], ontology_id: params[:ontology_id], language: request_lang) + render(inline: helpers.ajax_link_chip(params[:id], label, link, external: collection.blank?), layout: false) end def show_members diff --git a/app/controllers/concepts_controller.rb b/app/controllers/concepts_controller.rb index 1063c953b4..97e316c6af 100644 --- a/app/controllers/concepts_controller.rb +++ b/app/controllers/concepts_controller.rb @@ -63,10 +63,14 @@ def index end def show_label - cls_id = params[:concept] || params[:id] # cls_id should be a full URI - ont_id = params[:ontology] # ont_id could be a full URI or an acronym - - render LabelLinkComponent.inline(cls_id, helpers.main_language_label(concept_label(ont_id, cls_id))) + cls_id = params[:concept] || params[:id] + ont_id = params[:ontology] + pref_label = concept_label(ont_id, cls_id) + cls = @ontology.explore.single_class({ language: request_lang, include: 'prefLabel' }, cls_id) + label = helpers.main_language_label(pref_label) + link = concept_path(cls_id, ont_id, request_lang) + + render(inline: helpers.ajax_link_chip(cls_id, label, link, external: cls.nil? || cls.errors), layout: nil) end def show_definition @@ -87,8 +91,8 @@ def show_tree not_found(t('concepts.missing_roots')) if @root.nil? render inline: helpers.concepts_tree_component(@root, @concept, - @ontology.acronym, Array(params[:concept_schemes]&.split(',')), request_lang, - id: 'concepts_tree_view', auto_click: params[:auto_click] || true) + @ontology.acronym, Array(params[:concept_schemes]&.split(',')), request_lang, + id: 'concepts_tree_view', auto_click: params[:auto_click] || true) end end diff --git a/app/controllers/label_xl_controller.rb b/app/controllers/label_xl_controller.rb index 521d35fb7a..e62a749084 100644 --- a/app/controllers/label_xl_controller.rb +++ b/app/controllers/label_xl_controller.rb @@ -1,5 +1,5 @@ class LabelXlController < ApplicationController - include LabelXlHelper + include LabelXlHelper, UrlsHelper def show @label_xl = get_request_label_xl @@ -9,8 +9,9 @@ def show_label label_xl = get_request_label_xl label_xl_label = label_xl ? label_xl['literalForm'] : nil label_xl_label = params[:id] if label_xl_label.nil? || label_xl_label.empty? - - render LabelLinkComponent.inline(params[:id], helpers.main_language_label(label_xl_label)) + label = helpers.main_language_label(label_xl_label) + link = "/ajax/label_xl/?id=#{escape(params[:id])}&ontology=#{params[:ontology_id]}&cls_id=#{escape(params[:cls_id])}" + render(inline: helpers.ajax_link_chip(params[:id], label, link, open_in_modal: true, external: label_xl.blank?), layout: false) end private diff --git a/app/controllers/mappings_controller.rb b/app/controllers/mappings_controller.rb index df582acb4e..0ca5fd8b77 100644 --- a/app/controllers/mappings_controller.rb +++ b/app/controllers/mappings_controller.rb @@ -118,7 +118,7 @@ def show_mappings ontology_acronym = @ontology.acronym @ontology_name = ontology_acronym end - if @target_ontology.nil? + if @target_ontology.nil? || @target_ontology.errors if params[:target] == EXTERNAL_MAPPINGS_GRAPH target_acronym = EXTERNAL_URL_PARAM_STR @target_ontology_name = t('mappings.external_mappings') @@ -132,7 +132,6 @@ def show_mappings end ontologies = [ontology_acronym, target_acronym] - @mapping_pages = LinkedData::Client::HTTP.get("#{MAPPINGS_URL}", { page: page, ontologies: ontologies.join(',') }) not_found(@mapping_pages.errors) if @mapping_pages.respond_to?(:errors) @mappings = @mapping_pages.collection diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb index 8c5c97f1f0..1116e6a740 100644 --- a/app/controllers/schemes_controller.rb +++ b/app/controllers/schemes_controller.rb @@ -23,9 +23,9 @@ def index render inline: helpers.render_search_paginated_list(container_id: 'schemes_sorted_list', - next_page_url: "/ontologies/#{@ontology.acronym}/schemes", - child_url: "/ontologies/#{@ontology.acronym}/schemes/show", child_turbo_frame: 'scheme', - child_param: :schemeid, + next_page_url: "/ontologies/#{@ontology.acronym}/schemes", + child_url: "/ontologies/#{@ontology.acronym}/schemes/show", child_turbo_frame: 'scheme', + child_param: :schemeid, results: results, next_page: next_page, total_count: total_count) end @@ -35,7 +35,7 @@ def show redirect_to(ontology_path(id: params[:ontology], p: 'schemes', schemeid: params[:id],lang: request_lang)) and return unless turbo_frame_request? @scheme = get_request_scheme - + render partial: "schemes/show" end @@ -43,8 +43,9 @@ def show_label scheme = get_request_scheme scheme_label = scheme ? scheme['prefLabel'] : params[:id] scheme_label = scheme_label.nil? || scheme_label.empty? ? params[:id] : scheme_label - - render LabelLinkComponent.inline(params[:id], helpers.main_language_label(scheme_label)) + label = helpers.main_language_label(scheme_label) + link = scheme_path(scheme_id: params[:id], ontology_id: params[:ontology_id]) + render(inline: helpers.ajax_link_chip(params[:id], label, link, external: scheme.blank?), layout: false) end private diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6d565bdb22..2a319d6874 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -9,7 +9,7 @@ module ApplicationHelper REST_URI = $REST_URL API_KEY = $API_KEY - include ModalHelper, MultiLanguagesHelper, UrlsHelper + include ModalHelper, MultiLanguagesHelper, UrlsHelper, ComponentsHelper RESOLVE_NAMESPACE = {:omv => "http://omv.ontoware.org/2005/05/ontology#", :skos => "http://www.w3.org/2004/02/skos/core#", :owl => "http://www.w3.org/2002/07/owl#", @@ -19,7 +19,7 @@ module ApplicationHelper :umls => "http://bioportal.bioontology.org/ontologies/umls/", :door => "http://kannel.open.ac.uk/ontology#", :dct => "http://purl.org/dc/terms/", :void => "http://rdfs.org/ns/void#", :foaf => "http://xmlns.com/foaf/0.1/", :vann => "http://purl.org/vocab/vann/", :adms => "http://www.w3.org/ns/adms#", :voaf => "http://purl.org/vocommons/voaf#", :dcat => "http://www.w3.org/ns/dcat#", :mod => "http://www.isibang.ac.in/ns/mod#", :prov => "http://www.w3.org/ns/prov#", - :cc => "http://creativecommons.org/ns#", :schema => "http://schema.org/", :doap => "http://usefulinc.com/ns/doap#", :bibo => "http://purl.org/ontology/bibo/", + :cc => "http://creativecommons.org/ns#", :schema => "http://schema.org/", :doap => "http://usefulinc.com/ns/doap#", :bibo => "http://purl.org/ontology/bibo/", :wdrs => "http://www.w3.org/2007/05/powder-s#", :cito => "http://purl.org/spar/cito/", :pav => "http://purl.org/pav/", :nkos => "http://w3id.org/nkos/nkostype#", :oboInOwl => "http://www.geneontology.org/formats/oboInOwl#", :idot => "http://identifiers.org/idot/", :sd => "http://www.w3.org/ns/sparql-service-description#", :cclicense => "http://creativecommons.org/licenses/", @@ -55,7 +55,6 @@ def get_apikey end end - def omniauth_providers_info $OMNIAUTH_PROVIDERS end @@ -76,7 +75,6 @@ def current_user_admin? session[:user] && session[:user].admin? end - def child_id(child) child.id.to_s.split('/').last end @@ -155,7 +153,6 @@ def add_proposal_button(parent_id, parent_type) end end - def subscribe_button(ontology_id) return if ontology_id.nil? render TurboFrameComponent.new(id: 'subscribe_button', src: ontology_subscriptions_path(ontology_id: ontology_id.split('/').last), class: 'ml-1') do |t| @@ -226,95 +223,40 @@ def notification_type(flash_key) bootstrap_alert_class[flash_key] end - def bp_ont_link(ont_acronym) - return "/ontologies/#{ont_acronym}" - end - - def bp_class_link(cls_id, ont_acronym) - return "#{bp_ont_link(ont_acronym)}?p=classes&conceptid=#{escape(cls_id)}&language=#{request_lang}" - end - - def bp_scheme_link(scheme_id, ont_acronym) - return "#{bp_ont_link(ont_acronym)}?p=schemes&schemeid=#{escape(scheme_id)}" - end - - def bp_label_xl_link(label_xl_id, ont_acronym) - return "#{bp_ont_link(ont_acronym)}/?label_xl_id=#{escape(label_xl_id)}" - end - - def bp_collection_link(collection_id, ont_acronym) - "#{bp_ont_link(ont_acronym)}?p=collection&collectionid=#{escape(collection_id)}" - end + def label_ajax_link(id, ont_acronym, ajax_uri, target) + ajax_uri = if ajax_uri.include?('?') + "#{ajax_uri}&ontology=#{ont_acronym}&id=#{escape(id)}" + else + "#{ajax_uri}?ontology=#{ont_acronym}&id=#{escape(id)}" + end - def label_ajax_data_h(cls_id, ont_acronym, ajax_uri, cls_url) - { data: - { - 'label-ajax-cls-id-value': cls_id, - 'label-ajax-ontology-acronym-value': ont_acronym, - 'label-ajax-ajax-url-value': ajax_uri, - 'label-ajax-cls-id-url-value': cls_url - } - } - end - - def label_ajax_data(cls_id, ont_acronym, ajax_uri, cls_url) - label_ajax_data_h(cls_id, ont_acronym, ajax_uri, cls_url) - end - - def label_ajax_link(link, cls_id, ont_acronym, ajax_uri, cls_url, target = nil) - data = label_ajax_data(cls_id, ont_acronym, ajax_uri, cls_url) - options = { 'data-controller': 'label-ajax' }.merge(data) - options = options.merge({ target: target }) if target - content_tag(:span, class: 'mx-1') do - render ChipButtonComponent.new(url: link, text: cls_id, type: 'clickable', **options) + content_tag(:span, class: 'concepts-mapping-count') do + ajax_link_chip(id, ajax_src: ajax_uri, target: target) end end def get_link_for_cls_ajax(cls_id, ont_acronym, target = nil) if cls_id.start_with?('http://') || cls_id.start_with?('https://') - link = bp_class_link(cls_id, ont_acronym) ajax_url = '/ajax/classes/label' - cls_url = "/ontologies/#{ont_acronym}?p=classes&conceptid=#{CGI.escape(cls_id)}" - label_ajax_link(link, cls_id, ont_acronym, ajax_url , cls_url ,target) + label_ajax_link(cls_id, ont_acronym, ajax_url, target) else content_tag(:div, cls_id) end end - def get_link_for_ont_ajax(ont_acronym) - # ajax call will replace the acronym with an ontology name (triggered by class='ont4ajax') - href_ont = " href='#{bp_ont_link(ont_acronym)}' " - data_ont = " data-ont='#{ont_acronym}' " - return "#{ont_acronym}" - end - def get_link_for_scheme_ajax(scheme, ont_acronym, target = '_blank') - link = bp_scheme_link(scheme, ont_acronym) ajax_url = "/ajax/schemes/label?language=#{request_lang}" - scheme_url = "?p=schemes&schemeid=#{CGI.escape(scheme)}" - label_ajax_link(link, scheme, ont_acronym, ajax_url, scheme_url, target) + label_ajax_link(scheme, ont_acronym, ajax_url, target) end def get_link_for_collection_ajax(collection, ont_acronym, target = '_blank') - link = bp_collection_link(collection, ont_acronym) ajax_url = "/ajax/collections/label?language=#{request_lang}" - collection_url = "?p=collections&collectionid=#{CGI.escape(collection)}" - label_ajax_link(link, collection, ont_acronym, ajax_url, collection_url, target) - end - - def get_link_for_label_xl_ajax(label_xl, ont_acronym, cls_id, modal: true) - link = label_xl - ajax_uri = "/ajax/label_xl/label?cls_id=#{CGI.escape(cls_id)}" - label_xl_url = "/ajax/label_xl/?id=#{CGI.escape(label_xl)}&ontology=#{ont_acronym}&cls_id=#{CGI.escape(cls_id)}" - data = label_ajax_data_h(label_xl, ont_acronym, ajax_uri, label_xl_url) - data[:data][:controller] = 'label-ajax' - if modal - link_to_modal(cls_id, link, {data: data[:data] , class: 'btn btn-sm btn-light m-1'}) - else - link_to(link,'', {data: data[:data], class: 'btn btn-sm btn-light m-1', target: '_blank'}) - end - + label_ajax_link(collection, ont_acronym, ajax_url, target) + end + def get_link_for_label_xl_ajax(label_xl, ont_acronym, cls_id, target = nil) + ajax_url = "/ajax/label_xl/label?cls_id=#{CGI.escape(cls_id)}" + label_ajax_link(label_xl, ont_acronym, ajax_url, target) end def ontology_viewer_page_name(ontology_name, concept_label, page) @@ -449,14 +391,14 @@ def prefixed_url(url) def show_advanced_options_button(text: nil, init: nil) content_tag(:div, class: "#{init ? 'd-none' : ''} advanced-options-button", 'data-action': 'click->reveal-component#show', 'data-reveal-component-target': 'showButton') do inline_svg_tag('icons/settings.svg') + - content_tag(:div, text, class: 'text') + content_tag(:div, text, class: 'text') end end def hide_advanced_options_button(text: nil, init: nil) content_tag(:div, class: "#{init ? '' : 'd-none'} advanced-options-button", 'data-action': 'click->reveal-component#hide', 'data-reveal-component-target': 'hideButton') do inline_svg_tag('icons/hide.svg') + - content_tag(:div, text, class: 'text') + content_tag(:div, text, class: 'text') end end diff --git a/app/helpers/collections_helper.rb b/app/helpers/collections_helper.rb index 9a80d24111..f8593cba2e 100644 --- a/app/helpers/collections_helper.rb +++ b/app/helpers/collections_helper.rb @@ -1,5 +1,5 @@ module CollectionsHelper - include MultiLanguagesHelper + include MultiLanguagesHelper, UrlsHelper def get_collections(ontology, add_colors: false) @@ -49,8 +49,8 @@ def no_collections_alert end end - def collection_path(collection_id = '', language = '') - "/ontologies/#{@ontology.acronym}/collections/show?id=#{escape(collection_id)}&language=#{language}" + def collection_path(collection_id: '', ontology_id: @ontology.acronym, language: request_lang) + "/ontologies/#{ontology_id}/collections/show?id=#{escape(collection_id)}&language=#{language}" end def request_collection_id @@ -65,8 +65,8 @@ def link_to_collection(collection, selected_collection_id) pref_label_lang, pref_label_html = get_collection_label(collection) tooltip = pref_label_lang.to_s.eql?('@none') ? '' : "data-controller='tooltip' data-tooltip-position-value='right' title='#{pref_label_lang.upcase}'" <<-EOS - #{pref_label_html} diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb index a63ba8edb5..180ea336e9 100644 --- a/app/helpers/components_helper.rb +++ b/app/helpers/components_helper.rb @@ -172,6 +172,10 @@ def tree_component(root, selected, target_frame:, sub_tree: false, id: nil, auto end end + def ajax_link_chip(id, label = nil, link = nil, external: false, open_in_modal: false, ajax_src: nil, target: '_blank') + render LabelFetcherComponent.new(id: id, label: label, link: link, open_in_modal: open_in_modal, ajax_src: ajax_src, target: target, external: external) + end + def chart_component(title: '', type:, labels:, datasets:, index_axis: 'x', show_legend: false) data = { controller: 'load-chart', diff --git a/app/helpers/concepts_helper.rb b/app/helpers/concepts_helper.rb index 3cec8ade6b..1b62c06d76 100644 --- a/app/helpers/concepts_helper.rb +++ b/app/helpers/concepts_helper.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true module ConceptsHelper - include TermsReuses + include TermsReuses, UrlsHelper + + def concept_path(id, ontology_id, language) + "/ontologies/#{ontology_id}?p=classes&conceptid=#{escape(id)}&language=#{language}" + end + def concept_link(acronym, child, language) child.id.eql?('bp_fake_root') ? '#' : "/ontologies/#{acronym}/concepts/show?id=#{CGI.escape(child.id)}&language=#{language}" end @@ -76,14 +81,9 @@ def default_sub_menu_class def concept_label(ont_id, cls_id) @ontology = LinkedData::Client::Models::Ontology.find(ont_id) @ontology ||= LinkedData::Client::Models::Ontology.find_by_acronym(ont_id).first - ontology_not_found(ont_id) unless @ontology - # Retrieve a class prefLabel or return the class ID (URI) - # - mappings may contain class URIs that are not in bioportal (e.g. obo-xrefs) + ontology_not_found(ont_id) if @ontology.nil? || @ontology.errors cls = @ontology.explore.single_class({language: request_lang, include: 'prefLabel'}, cls_id) - # TODO: log any cls.errors - # TODO: NCBO-402 might be implemented here, but it throws off a lot of ajax result rendering. - #cls_label = cls.prefLabel({:use_html => true}) || cls_id - cls.prefLabel || cls_id + cls&.prefLabel || cls_id end def concept_id_param_exist?(params) diff --git a/app/helpers/mappings_helper.rb b/app/helpers/mappings_helper.rb index c1e503b547..09b2c4d67e 100644 --- a/app/helpers/mappings_helper.rb +++ b/app/helpers/mappings_helper.rb @@ -77,24 +77,10 @@ def get_prefixed_uri(uri) uri end - # method to get (using http) prefLabel for interportal classes - # Using bp_ajax_controller.ajax_process_interportal_cls will try to resolve class labels. - def ajax_to_inter_portal_cls(cls) - inter_portal_acronym = get_inter_portal_acronym(cls.links['ui']) - href_cls = " href='#{cls.links["ui"]}' " - if inter_portal_acronym - data_cls = " data-cls='#{cls.links["self"]}?apikey=' " - portal_cls = " portal-cls='#{inter_portal_acronym}' " - raw("#{cls.id}") - else - raw("#{cls.id}") - end - - end - def ajax_to_internal_cls(cls) - link_to("#{cls.id}".html_safe, - ontology_path(cls.explore.ontology.acronym, p: 'classes', conceptid: cls.id), target: '_blank') + cls_id = cls.id + ont_acronym = cls.links['ontology'].split('/').last + get_link_for_cls_ajax(cls_id, ont_acronym, '_blank') end # to get the apikey from the interportal instance of the interportal class. @@ -111,18 +97,15 @@ def get_inter_portal_acronym(class_ui_url) end end - # method to extract the prefLabel from the external class URI - def get_label_for_external_cls(class_uri) - prefLabel = if class_uri.include? '#' - class_uri.split('#')[-1] - else - class_uri.split('/')[-1] - end - return prefLabel - end - def ajax_to_external_cls(cls) - raw("#{get_label_for_external_cls(cls.id)}") + class_uri = cls.id + text = if class_uri.include? '#' + class_uri.split('#')[-1] + else + class_uri.split('/')[-1] + end + text = render(ExternalLinkTextComponent.new(text: text)) + link_to text, cls.links['self'], target: '_blank' end # Replace the inter_portal mapping ontology URI (that link to the API) by the link to the ontology in the UI diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb index 9d3019cd36..7eec737c73 100644 --- a/app/helpers/schemes_helper.rb +++ b/app/helpers/schemes_helper.rb @@ -1,4 +1,5 @@ module SchemesHelper + include UrlsHelper def get_schemes(ontology) ontology.explore.schemes(language: request_lang) @@ -47,8 +48,8 @@ def section_name(section) t("ontology_details.sections.#{section}") end - def scheme_path(scheme_id = '', language = '') - "/ontologies/#{@ontology.acronym}/schemes/show?id=#{escape(scheme_id)}&lang=#{language}" + def scheme_path(ontology_id: @ontology.acronym, scheme_id: '', language: request_lang) + "/ontologies/#{ontology_id}/schemes/show?id=#{escape(scheme_id)}&lang=#{language}" end def no_main_scheme? @@ -64,6 +65,7 @@ def no_main_scheme_alert t('schemes.no_main_scheme_alert') end end + def no_schemes_alert render Display::AlertComponent.new do t('schemes.no_schemes_alert', acronym: @ontology.acronym) @@ -88,7 +90,6 @@ def schemes_tree(schemes_labels, main_scheme_label, selected_scheme_id, submissi scheme end.compact - main_scheme = nil if main_scheme_label.nil? children = schemes @@ -105,8 +106,8 @@ def schemes_tree(schemes_labels, main_scheme_label, selected_scheme_id, submissi root.children = children selected_scheme = selected_scheme || main_scheme || root.children.first tree_component(root, selected_scheme, target_frame: 'scheme', auto_click: false, submission: submission) do |child| - href = scheme_path(child['@id'], request_lang) rescue '' - data = { schemeid: (child['@id'] rescue '')} + href = scheme_path(scheme_id: child['@id'], ontology_id: @ontology.acronym, language: request_lang) + data = { schemeid: child['@id']} ["#", data, href] end end diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index fa09b85416..7b99fc21d4 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -34,12 +34,6 @@ application.register("form-options-display", FormDisplayController) import HistoryController from "./history_controller" application.register("history", HistoryController) -import LabelAjaxController from "./label_ajax_controller" -application.register("label-ajax", LabelAjaxController) - -import LabelsAjaxContainerController from "./labels_ajax_container_controller" -application.register("labels-ajax-container", LabelsAjaxContainerController) - import LanguageChangeController from "./language_change_controller" application.register("language-change", LanguageChangeController) diff --git a/app/javascript/controllers/label_ajax_controller.js b/app/javascript/controllers/label_ajax_controller.js deleted file mode 100644 index d3cbcfff46..0000000000 --- a/app/javascript/controllers/label_ajax_controller.js +++ /dev/null @@ -1,83 +0,0 @@ -import {Controller} from "@hotwired/stimulus" -import useAjax from "../mixins/useAjax"; - -// Connects to data-controller="label-ajax" -export default class extends Controller { - static values = { - clsId: String, - ontologyAcronym: String, - ajaxUrl: String, - clsIdUrl: String, - } - - connect() { - setTimeout(() => { - this.linkA = jQuery(this.element); - - if (this.linkA.hasClass('ajax-modified-cls')) { - return true - } - - this.cls_id = this.clsIdValue; - this.ont_acronym = this.ontologyAcronymValue; - - let ajax_uri = new URL(this.ajaxUrlValue, document.location.origin) - - ajax_uri.searchParams.set('ontology', this.ont_acronym) - ajax_uri.searchParams.set('id', this.cls_id) - - - this.request = useAjax({ - url: ajax_uri.pathname + ajax_uri.search, - timeout: ajax_process_timeout * 1000, - success: this.#ajaxSuccess.bind(this), - error: this.#ajaxError.bind(this) - }); - },1) - } - - abort() { - if (this.request) { - this.request.abort() - this.request = null - } - } - - disconnect() { - this.abort() - } - - #ajaxSuccess(data) { - data = data.trim(); - if (typeof data !== "undefined" && data.length > 0 && data.indexOf("http") !== 0) { - let cls_name = data - let cls_uri = this.clsIdUrlValue - this.linkA.html(cls_name); - this.linkA.attr('href', cls_uri); - this.linkA.addClass('ajax-modified-cls'); - //find and process any identical classes (low probability) - this.#fillIdenticalIds(cls_name, cls_uri) - } else { - // remove the unique_id separator and the ontology acronym from the href - this.linkA.attr('href', this.cls_id); // it may not be an ontology class, don't use the cls_uri - this.linkA.addClass('ajax-modified-cls'); - } - } - - #ajaxError() { - this.linkA.addClass('ajax-error') - } - - #fillIdenticalIds(cls_name, cls_uri) { - - let unique_id = this.linkA.attr('href'); - jQuery('a[href="' + unique_id + '"]').each(function () { - let link = jQuery(this); - if (!link.hasClass('ajax-modified-cls')) { - link.html(cls_name); - link.attr('href', cls_uri); - link.addClass('ajax-modified-cls') - } - }); - } -} diff --git a/app/javascript/controllers/labels_ajax_container_controller.js b/app/javascript/controllers/labels_ajax_container_controller.js deleted file mode 100644 index a8f606114c..0000000000 --- a/app/javascript/controllers/labels_ajax_container_controller.js +++ /dev/null @@ -1,10 +0,0 @@ -import {Controller} from "@hotwired/stimulus" - -// Connects to data-controller="labels-ajax-container" -export default class extends Controller { - static outlets = ['label-ajax'] - - abortAll() { - this.labelAjaxOutlets.forEach((link) => {link.abort()}) - } -} diff --git a/app/javascript/controllers/turbo_frame_error_controller.js b/app/javascript/controllers/turbo_frame_error_controller.js index 782166bc54..16d2cbbd28 100644 --- a/app/javascript/controllers/turbo_frame_error_controller.js +++ b/app/javascript/controllers/turbo_frame_error_controller.js @@ -34,7 +34,10 @@ export default class extends Turbo_frame_controller { Array.from(styles).forEach(e => el.removeChild(e)) let body = el.querySelector('h1') - this.errorMessageTarget.firstElementChild.querySelector('.alert-message').innerHTML = (body ? body.innerText : el.innerHTML) + let alertContainer = this.errorMessageTarget.firstElementChild?.querySelector('.alert-message') + if(alertContainer){ + alertContainer.innerHTML = (body ? body.innerText : el.innerHTML) + } $(this.errorMessageTarget).show() } diff --git a/app/views/collections/_list_view.html.haml b/app/views/collections/_list_view.html.haml index a50abe0ce2..d0594f157f 100644 --- a/app/views/collections/_list_view.html.haml +++ b/app/views/collections/_list_view.html.haml @@ -11,6 +11,6 @@ - scheme = OpenStruct.new(collection) - scheme.prefLabel = Array(get_collection_label(collection)).last - scheme.id = scheme['@id'] - - tree_child.child(child: scheme, href: collection_path(collection['@id'], request_lang), + - tree_child.child(child: scheme, href: collection_path(collection_id: collection['@id'], ontology_id: @ontology.acronym, language: request_lang), children_href: '#', selected: scheme.id.eql?(selected_collection_id), target_frame: 'collection', data: {collectionid: collection['@id']}, is_reused: concept_reused?(submission: @submission, concept_id: scheme.id)) diff --git a/app/views/concepts/_show.html.haml b/app/views/concepts/_show.html.haml index 8d690b65fd..bbbb95614b 100644 --- a/app/views/concepts/_show.html.haml +++ b/app/views/concepts/_show.html.haml @@ -1,4 +1,4 @@ -= render TurboFrameComponent.new(id: 'concept_show', data: {controller:'labels-ajax-container', 'action': 'turbo:before-fetch-request->labels-ajax-container#abortAll', 'labels-ajax-container-label-ajax-outlet': '#concept_show a[data-controller="label-ajax"]'}) do += render TurboFrameComponent.new(id: 'concept_show') do - if @concept.id.eql?("bp_fake_root") = render Display::AlertComponent.new do = t('concepts.use_jump_to') diff --git a/app/views/mappings/_mapping_table.html.haml b/app/views/mappings/_mapping_table.html.haml index 20efcd92d5..1492ce2eca 100644 --- a/app/views/mappings/_mapping_table.html.haml +++ b/app/views/mappings/_mapping_table.html.haml @@ -14,7 +14,3 @@ = render partial: 'mappings/show_line' , locals: {map: map, concept: @concept} %tr.empty-state %td.text-center{:colspan => "6"}= t("mappings.mapping_table.no_mappings") -:javascript - jQuery(document).ready(function(){ - ajax_process_init(); - }) diff --git a/app/views/mappings/_show.html.haml b/app/views/mappings/_show.html.haml index 6ca1cffe1f..60bebf6d9e 100644 --- a/app/views/mappings/_show.html.haml +++ b/app/views/mappings/_show.html.haml @@ -15,9 +15,7 @@ %tr - map.classes.each do |cls| %td - - if inter_portal_mapping?(cls) - = ajax_to_inter_portal_cls(cls) - - elsif internal_mapping?(cls) + - if internal_mapping?(cls) = ajax_to_internal_cls(cls) - else = ajax_to_external_cls(cls) @@ -25,8 +23,3 @@ #{map.source} #{(map.process || {})[:source_name]} .mappings-table-pagination = will_paginate @page_results, :update => 'mappings', :params => { :target => params[:target] } - - :javascript - jQuery(document).ready(function(){ - ajax_process_init(); // see bp_ajax_controller.js - }) \ No newline at end of file From aa7e2475d5f2de6bcc2a8725ad28db8cbd392346 Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Thu, 7 Nov 2024 10:16:37 +0100 Subject: [PATCH 11/22] Fix: Remove ontolobrigde code and some Jquery code (#822) * update select_language_label helper to select f no english found any language remaining over the not tagged * remove ontology bridge code * remove ont_viewer data jquery code * remove no existent fetch_results action code --- .env.sample | 2 - app/assets/javascripts/bp_ontolobridge.js | 359 ------------------ .../stylesheets/application.css.scss.erb | 1 - app/assets/stylesheets/ontolobridge.scss | 35 -- app/controllers/concepts_controller.rb | 2 - app/controllers/ontolobridge_controller.rb | 64 ---- app/controllers/ontologies_controller.rb | 1 - app/helpers/application_helper.rb | 5 - .../class_search_auto_complete_controller.js | 11 +- app/views/concepts/_request_term.html.haml | 47 --- app/views/layouts/_header.html.erb | 6 +- app/views/layouts/_ontology_viewer.html.haml | 20 - app/views/layouts/appliance.html.haml | 2 - app/views/layouts/component_preview.html.erb | 6 +- .../component_preview_not_centred.html.erb | 6 +- app/views/layouts/popup.html.erb | 2 - app/views/layouts/tool.html.haml | 3 +- .../ontologies/sections/visualize.html.haml | 8 - config/application.rb | 1 - config/bioportal_config_env.rb.sample | 9 - config/locales/en.yml | 31 +- config/locales/fr.yml | 32 -- config/routes.rb | 25 +- db/schema.rb | 2 +- 24 files changed, 21 insertions(+), 659 deletions(-) delete mode 100644 app/assets/javascripts/bp_ontolobridge.js delete mode 100644 app/assets/stylesheets/ontolobridge.scss delete mode 100644 app/controllers/ontolobridge_controller.rb delete mode 100644 app/views/concepts/_request_term.html.haml diff --git a/.env.sample b/.env.sample index 94f4a336b4..6a8e41d243 100644 --- a/.env.sample +++ b/.env.sample @@ -39,5 +39,3 @@ OP_API_URL="https://data.bioontology.org" API_IMAGE_REPOSITORY=agroportal ## Image tag/version from which the ontoportal api will be built API_IMAGE_TAG=master - - diff --git a/app/assets/javascripts/bp_ontolobridge.js b/app/assets/javascripts/bp_ontolobridge.js deleted file mode 100644 index d4acc3e977..0000000000 --- a/app/assets/javascripts/bp_ontolobridge.js +++ /dev/null @@ -1,359 +0,0 @@ -function bindAddRequestTermClick() { - jQuery("a.add_request_term").live('click', function(){ - var id = jQuery(this).attr("data-parent-id"); - addRequestTermBox(id); - }); -} - -function bindCancelRequestTermClick() { - jQuery(".request_term_form_div .cancel").live('click', function() { - removeRequestTermBox(); - }); -} - -function bindNewTermInstructionsClick() { - jQuery("#new_term_instructions").live("click", function() { - jQuery(this).trumbowyg({ - btns: [ - ['viewHTML'], - ['undo', 'redo'], // Only supported in Blink browsers - ['formatting'], - ['strong', 'em', 'del'], - ['superscript', 'subscript'], - ['link'], - ['insertImage'], - ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], - ['unorderedList', 'orderedList'], - ['horizontalRule'], - ['removeformat'], - ['fullscreen'] - ] - }); - jQuery("#new_term_instructions_submit").show(); - jQuery("#new_term_instructions_cancel").show(); - }); -} - -function bindNewTermInstructionsSubmit() { - jQuery("#new_term_instructions_submit").live("click", function() { - saveNewTermInstructions(); - }); -} - -function bindNewTermInstructionsCancel() { - jQuery("#new_term_instructions_cancel").live("click", function() { - var oldVal = jQuery("#new_term_instructions_old").val().trim(); - var curVal = jQuery('#new_term_instructions').html().trim(); - - if (oldVal != curVal) { - if (confirm('Are you sure you want to discard your changes?')) { - jQuery('#new_term_instructions').trumbowyg('destroy'); - jQuery('#new_term_instructions').html(oldVal); - hideButtons(); - } - } else { - jQuery('#new_term_instructions').trumbowyg('destroy'); - hideButtons(); - } - }); -} - -function preventNewTermInstructionsFormSubmit() { - jQuery("#new_term_instructions_form").submit(function(e) { - e.preventDefault(e); - }); -} - -function clearProgressMessage(parentContainerID) { - var progMsgElem = jQuery("#" + parentContainerID + " #progress_message"); - progMsgElem.hide(); - progMsgElem.html(""); -} - -function showProgressMessage(parentContainerID) { - clearProgressMessage(parentContainerID); - var msg = "Saving..."; - var progMsgElem = jQuery("#" + parentContainerID + " #progress_message"); - progMsgElem.text(msg).html(); - progMsgElem.show(); -} - -function saveNewTermInstructions() { - var params = jQuery('#new_term_instructions_form').serialize(); - var newInstructions = jQuery('#new_term_instructions').html().trim(); - params += '&new_term_instructions=' + newInstructions; - var parentContainerID = 'new_term_instructions_container'; - showProgressMessage(parentContainerID); - - jQuery.ajax({ - type: "POST", - url: "/ontolobridge/save_new_term_instructions", - dataType: "json", - data: params, - success: function(data) { - var status = data[1]; - - if (status && status >= 400 || data[0]['error'].length) { - showStatusMessages('', data[0]['error']); - } else { - jQuery('#new_term_instructions').trumbowyg('destroy'); - jQuery("#new_term_instructions_old").val(newInstructions); - showStatusMessages(data[0]["success"], ''); - setTimeout(function() { clearStatusMessages(); }, 5000); - } - }, - error: function(request, textStatus, errorThrown) { - showStatusMessages('', errorThrown); - }, - complete: function(request, textStatus) { - clearProgressMessage(parentContainerID); - hideButtons(); - } - }); -} - -function hideButtons() { - jQuery("#new_term_instructions_submit").hide(); - jQuery("#new_term_instructions_cancel").hide(); -} - -function bindRequestTermSaveClick() { - var success = ""; - var error = ""; - var user = jQuery(document).data().bp.user; - var ontology_id = jQuery(document).data().bp.ont_viewer.ontology_id; - var params = jQuery("#request_term_form").serialize(); - params += "&ontology=" + ontology_id + "&email=" + user["email"] - - if (user["firstName"] && user["lastName"]) { - params += "&submitter=" + user["firstName"] + " " + user["lastName"]; - } - - var parentContainerID = 'proposal_buttons'; - showProgressMessage(parentContainerID); - - jQuery.ajax({ - type: "POST", - url: "/ontolobridge", - data: params, - dataType: "json", - success: function(data) { - var status = data[1]; - - if (status && status >= 400) { - showStatusMessages('', data[0]["error"]); - } else { - var msg = "A new term request has been submitted successfully:

"; - removeRequestTermBox(); - - for (var i in data[0]) { - msg += i + ": " + data[0][i] + "
"; - } - showStatusMessages(msg, error); - } - }, - error: function(request, textStatus, errorThrown) { - error = "The following error has occurred: " + errorThrown + ". Please try again."; - showStatusMessages(success, error); - }, - complete: function(request, textStatus) { - clearProgressMessage(parentContainerID); - } - }); -} - -function removeRequestTermBox() { - jQuery(".request_term_form_div").html(""); -} - -function addRequestTermBox(id) { - clearStatusMessages(); - var formContainer = jQuery(".request_term_form_div"); - var requestTermForm = requestTermFields(id, formContainer); - var formID = requestTermForm.attr('id'); - var isPopulated = window.localStorage.getItem(formID + '_populated'); - - if (isPopulated) { - for (var key in window.localStorage) { - if (key.startsWith(formID)) { - var elemID = key.replace(formID + '_', ''); - var elem = jQuery('#' + formID + ' #' + elemID); - - if (elem.attr('type') === "checkbox") { - elem.prop("checked", true); - } else if (elem.length > 0) { - var val = window.localStorage.getItem(key); - elem.val(val); - } - window.localStorage.removeItem(key); - } - } - } - formContainer.show(); - jQuery("#label").focus(); -} - -function clearStatusMessages() { - jQuery("#ob_success_message").hide(); - jQuery("#ob_error_message").hide(); - jQuery("#ob_success_message").html(""); - jQuery("#ob_error_message").html(""); -} - -function showStatusMessages(success, error) { - if (success.length > 0) { - let ob = jQuery("#ob_success_message") - console.log('show ob message') - console.log(ob) - ob.html(success); - ob.show(); - } - - if (error.length > 0) { - jQuery("#ob_error_message").text(error).html(); - jQuery("#ob_error_message").show(); - } -} - -function requestTermButtons() { - var buttonSubmit = jQuery("