diff --git a/app/assets/stylesheets/components/tree_view.scss b/app/assets/stylesheets/components/tree_view.scss index 26c507e6f..fa3c876bd 100644 --- a/app/assets/stylesheets/components/tree_view.scss +++ b/app/assets/stylesheets/components/tree_view.scss @@ -35,7 +35,6 @@ padding:0; a.tree-link { display: inline-block; padding: 5px; - word-break: break-all; text-wrap: wrap; color: var(--primary-color); } diff --git a/app/assets/stylesheets/taxonomy.scss b/app/assets/stylesheets/taxonomy.scss index bf5c679ff..077b5bcda 100644 --- a/app/assets/stylesheets/taxonomy.scss +++ b/app/assets/stylesheets/taxonomy.scss @@ -109,4 +109,23 @@ background-color: var(--primary-color); } +.taxonomy-empty-illustration{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + .browse-empty-illustration { + margin-top: 40px; + } +} + + +.taxonomy-empty-illustration-text{ + color: var(--gray-color); + +} +.taxonomy-empty-illustration-button{ + width: 168px; +} diff --git a/app/components/federated_portal_button_component.rb b/app/components/federated_portal_button_component.rb index 4d8a1e886..920407bb4 100644 --- a/app/components/federated_portal_button_component.rb +++ b/app/components/federated_portal_button_component.rb @@ -2,6 +2,7 @@ class FederatedPortalButtonComponent < ViewComponent::Base attr_reader :name, :tooltip, :link, :color, :light_color + include UrlsHelper def initialize(name:, link:, color:, tooltip:, light_color:) @name = name @@ -10,4 +11,8 @@ def initialize(name:, link:, color:, tooltip:, light_color:) @color = color @light_color = light_color end + + def internal? + !link?(@link) + end end diff --git a/app/components/federated_portal_button_component/federated_portal_button_component.html.haml b/app/components/federated_portal_button_component/federated_portal_button_component.html.haml index e45a6f052..b59554ff8 100644 --- a/app/components/federated_portal_button_component/federated_portal_button_component.html.haml +++ b/app/components/federated_portal_button_component/federated_portal_button_component.html.haml @@ -1,7 +1,7 @@ %span{'data-controller': 'federation-portals-colors', 'data-federation-portals-colors-color-value': color, 'data-federation-portals-colors-portal-name-value': name.downcase} -%a{ href: link, target: '_blank', 'data-controller' => 'tooltip', title: tooltip, class: 'federation-portal-button button icon-right', style: color ? "background-color: #{light_color} !important" : '' } +%a{ href: link, target: internal? ? '_top' : '_blank', 'data-controller' => 'tooltip', title: tooltip, class: 'federation-portal-button button icon-right', style: color ? "background-color: #{light_color} !important" : '' } = inline_svg_tag('logos/ontoportal.svg', class: "federated-icon-#{name.downcase}") %div{ class: 'text', style: color ? "color: #{color} !important" : '' } = name.humanize.gsub("portal", "Portal") diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c27651a48..e6182c033 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,7 +27,7 @@ def set_locale cookies.permanent[:locale] = I18n.locale if cookies[:locale].nil? logger.debug "* Locale set to '#{I18n.locale}'" - I18n.locale = portal_lang if portal_language_enabled?(I18n.locale) + I18n.locale = portal_lang unless portal_language_enabled?(I18n.locale) session[:locale] = I18n.locale end @@ -430,7 +430,7 @@ def json_link(url, optional_params) optional_params_str = filtered_params.map { |param, value| "#{param}=#{value}" }.join("&") return base_url + optional_params_str + "&apikey=#{$API_KEY}" end - + def set_federated_portals RequestStore.store[:federated_portals] = params[:portals]&.split(',') end diff --git a/app/controllers/concerns/search_aggregator.rb b/app/controllers/concerns/search_aggregator.rb index f1f074272..a4c8699f2 100644 --- a/app/controllers/concerns/search_aggregator.rb +++ b/app/controllers/concerns/search_aggregator.rb @@ -251,18 +251,21 @@ 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| - 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 + element_ontology_id = element[:root][:ontology_id].split('/').last + element_uri = element[:root][:uri] + [element[:reuses], search_results].each do |collection| + collection.reject! do |entry| + next if entry == element + + entry_ontology_id = entry[:root][:ontology_id].split('/').last + entry_uri = entry[:root][:uri] + + if element_ontology_id == entry_ontology_id && element_uri == entry_uri + element[:root][:other_portals] << build_other_portal_entry(entry) + true + else + false + end end end end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 068d217b8..b9737ae8a 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -48,6 +48,8 @@ def portal_config @config = $PORTALS_INSTANCES.select { |x| x[:name].downcase.eql?((params[:portal] || helpers.portal_name).downcase) }.first if @config && @config[:api] @portal_config = LinkedData::Client::Models::Ontology.top_level_links(@config[:api]).to_h + @color = @portal_config[:color].present? ? @portal_config[:color] : @config[:color] + @name = @portal_config[:title].present? ? @portal_config[:title] : @config[:name] else @portal_config = {} end diff --git a/app/controllers/ontologies_controller.rb b/app/controllers/ontologies_controller.rb index 793a0f7a1..597a238e3 100644 --- a/app/controllers/ontologies_controller.rb +++ b/app/controllers/ontologies_controller.rb @@ -60,11 +60,12 @@ def ontologies_filter end end.flatten - unless request_portals.empty? + unless request_portals.length == 1 streams += [ replace('categories_refresh_for_federation') do key = "categories" objects, checked_values, _ = @filters[key.to_sym] + objects = keep_only_root_categories(objects) helpers.browse_filter_section_body(checked_values: checked_values, key: key, objects: objects, counts: @count_objects[key.to_sym]) @@ -588,4 +589,9 @@ def search_first_instance_id return !results.blank? ? results.first[:name] : nil end + def keep_only_root_categories(categories) + categories.select do |category| + category.id.start_with?(rest_url) || category.parentCategory.blank? + end + end end diff --git a/app/controllers/taxonomy_controller.rb b/app/controllers/taxonomy_controller.rb index c75dab259..8696c3e08 100644 --- a/app/controllers/taxonomy_controller.rb +++ b/app/controllers/taxonomy_controller.rb @@ -32,9 +32,9 @@ def nest_categories_children(categories) category_index[category[:id]] = category end categories.each do |category| - category[:parentCategory].each do |parent_id| + category[:parentCategory]&.each do |parent_id| parent = category_index[parent_id] - next unless parent + next if parent.nil? parent[:children] ||= [] parent[:children] << category end diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb index 318c7b6f1..8d62ea2a6 100644 --- a/app/helpers/components_helper.rb +++ b/app/helpers/components_helper.rb @@ -271,8 +271,8 @@ def properties_dropdown(id, title, tooltip, properties, is_open: false, &block) end end - def regular_button(id, value, variant: "secondary", state: "regular", size: "slim", &block) - render Buttons::RegularButtonComponent.new(id: id, value: value, variant: variant, state: state, size: size) do |btn| + def regular_button(id, value, variant: "secondary", state: "regular", size: "slim", href: nil, &block) + render Buttons::RegularButtonComponent.new(id:id, value: value, variant: variant, state: state, size: size, href: href) do |btn| capture(btn, &block) if block_given? end end diff --git a/app/helpers/fair_score_helper.rb b/app/helpers/fair_score_helper.rb index 85e1aed8e..a6ea35ef5 100644 --- a/app/helpers/fair_score_helper.rb +++ b/app/helpers/fair_score_helper.rb @@ -5,7 +5,7 @@ def user_apikey end def fairness_service_enabled? - !$FAIRNESS_DISABLED + $FAIRNESS_DISABLED == 'false' || !$FAIRNESS_DISABLED end def get_fairness_service_url(apikey = user_apikey) diff --git a/app/helpers/federation_helper.rb b/app/helpers/federation_helper.rb index 14e966037..24807bc64 100644 --- a/app/helpers/federation_helper.rb +++ b/app/helpers/federation_helper.rb @@ -3,6 +3,11 @@ module FederationHelper def federated_portals $FEDERATED_PORTALS ||= LinkedData::Client.settings.federated_portals + $FEDERATED_PORTALS.each do |key, portal| + portal[:ui] += "/" unless portal[:ui].end_with?("/") + portal[:api] += "/" unless portal[:api].end_with?("/") + end + $FEDERATED_PORTALS end def internal_portal_config(id) @@ -53,13 +58,17 @@ def ontology_portal_color(id) end def ontoportal_ui_link(id) + if id.include?($REST_URL) + return id.gsub($REST_URL,'') + end + portal_key, config = ontology_portal_config(id) return nil unless portal_key ui_link = config[:ui] api_link = config[:api] - id.gsub(api_link, "#{ui_link}/") rescue id + id.gsub(api_link, "#{ui_link}") rescue id end def internal_ontology?(id) @@ -209,14 +218,18 @@ def init_federation_portals_status end def federated_search_counts(search_results) - ids = search_results.map do |result| - result.dig(:root, :ontology_id) || rest_url - end + ids = search_results.flat_map do |result| + ontology_id = result.dig(:root, :ontology_id) || rest_url + other_portal_ids = result.dig(:root, :other_portals)&.map { |portal| portal[:link].split('?').first } || [] + [ontology_id] + other_portal_ids + end.uniq counts_ontology_ids_by_portal_name(ids) end def federated_browse_counts(ontologies) - ids = ontologies.map { |ontology| ontology[:id] } + ids = ontologies.flat_map do |ontology| + [ontology[:id]] + (ontology[:sources] || []) + end.uniq counts_ontology_ids_by_portal_name(ids) end @@ -229,8 +242,9 @@ def counts_ontology_ids_by_portal_name(portals_ids) counts[current_portal.downcase] += 1 if id.include?(current_portal.to_s.downcase) federation_portals.each do |portal| - portal_api = federated_portals[portal.downcase.to_sym][:api] - counts[portal.downcase] += 1 if id.include?(portal_api) + portal_api = federated_portals[portal.downcase.to_sym][:api].sub(/^https?:\/\//, '') + portal_ui = federated_portals[portal.downcase.to_sym][:ui].sub(/^https?:\/\//, '') + counts[portal.downcase] += 1 if (id.include?(portal_api) || id.include?(portal_ui)) end end diff --git a/app/helpers/instances_helper.rb b/app/helpers/instances_helper.rb index 79e5b1758..18a4dddd2 100644 --- a/app/helpers/instances_helper.rb +++ b/app/helpers/instances_helper.rb @@ -52,7 +52,7 @@ def link_to_class(ontology_acronym, conceptid) def link_to_property(property, ontology_acronym) link_to extract_label_from(property), - ontology_path(ontology_acronym, p: 'properties'), + ontology_path(ontology_acronym, p: 'properties', propertyid: property), { target: '_blank'} end diff --git a/app/views/home/portal_config.html.haml b/app/views/home/portal_config.html.haml index b484e9431..15f04baf1 100644 --- a/app/views/home/portal_config.html.haml +++ b/app/views/home/portal_config.html.haml @@ -4,21 +4,21 @@ .div.d-flex.align-items-center %div %div.text-center - = link_to @portal_config[:ui] || @config[:ui], target: '_blank', class: 'home-logo-instances mr-1 m-0', style: "background-color: #{@portal_config[:color] || @config[:color]}" do + = link_to @portal_config[:ui] || @config[:ui], target: '_blank', class: 'home-logo-instances mr-1 m-0', style: "background-color: #{@color}" do = inline_svg 'logo-white.svg', width: "35", height: "26" %div - %div.portal-configuration-title{style: "color: #{@portal_config[:color] || @config[:color]}"} + %div.portal-configuration-title{style: "color: #{@color}"} %h3 - = @portal_config[:title] || @config[:name] + = @name - if @portal_config[:numberOfArtefacts] .portal-config-ontologies = inline_svg_tag 'icons/ontology.svg' %span = "#{@portal_config[:numberOfArtefacts]} ontologies" - - if @portal_config[:description] + - if @portal_config[:description].present? .portal-description = @portal_config[:description] - - if @portal_config[:federated_portals] + - if @portal_config[:federated_portals].present? %div.mb-1 .home-section-title .text @@ -31,7 +31,7 @@ %p{style: "color: #{portal[:color]}"} = portal[:name] - - if @portal_config[:fundedBy] + - if @portal_config[:fundedBy].present? %div.mb-1 .home-section-title .portal-config-title-text diff --git a/app/views/taxonomy/_taxonomies.html.haml b/app/views/taxonomy/_taxonomies.html.haml index 0dd56f687..f6c0b3eb8 100644 --- a/app/views/taxonomy/_taxonomies.html.haml +++ b/app/views/taxonomy/_taxonomies.html.haml @@ -1,10 +1,17 @@ .taxonomy-section - - pairs, impairs = taxonomies.each_with_index.partition { |_, index| index.even? } - - taxonomies_first_row = pairs.map(&:first) - - taxonomies_second_row = impairs.map(&:first) - .first-row - - taxonomies_first_row.each do |taxonomy| - = render Display::TaxonomyCardComponent.new(taxonomy: taxonomy, ontologies_names: @ontologies_names) - .second-row - - taxonomies_second_row.each do |taxonomy| - = render Display::TaxonomyCardComponent.new(taxonomy: taxonomy, ontologies_names: @ontologies_names) \ No newline at end of file + - if taxonomies.blank? + .taxonomy-empty-illustration + = empty_state(t('taxonomy.no_taxonomy_created', type: type)) + - if current_user_admin? + .taxonomy-empty-illustration-button + = regular_button('create-taxonomy', "Create #{type}", variant: "secondary", size: "slim", href: "/admin?section=#{type}") + - else + - pairs, impairs = taxonomies.each_with_index.partition { |_, index| index.even? } + - taxonomies_first_row = pairs.map(&:first) + - taxonomies_second_row = impairs.map(&:first) + .first-row + - taxonomies_first_row.each do |taxonomy| + = render Display::TaxonomyCardComponent.new(taxonomy: taxonomy, ontologies_names: @ontologies_names) + .second-row + - taxonomies_second_row.each do |taxonomy| + = render Display::TaxonomyCardComponent.new(taxonomy: taxonomy, ontologies_names: @ontologies_names) \ No newline at end of file diff --git a/app/views/taxonomy/index.html.haml b/app/views/taxonomy/index.html.haml index b9b2b3a10..706e212e5 100644 --- a/app/views/taxonomy/index.html.haml +++ b/app/views/taxonomy/index.html.haml @@ -10,11 +10,11 @@ = render TabsContainerComponent.new do |c| - c.item(title: 'Groups', selected: !@category_section_active) - c.item_content do - = render partial: '/taxonomy/taxonomies', locals: { taxonomies: @groups } + = render partial: '/taxonomy/taxonomies', locals: { taxonomies: @groups, type: 'groups' } - c.item(title: 'Categories', selected: @category_section_active) - c.item_content do - = render partial: '/taxonomy/taxonomies', locals: { taxonomies: @categories } + = render partial: '/taxonomy/taxonomies', locals: { taxonomies: @categories, type: 'categories' } :javascript document.getElementById('categories_tab').addEventListener('click', function(event) { window.history.pushState({ path: '/categories' }, '', '/categories'); diff --git a/config/locales/en.yml b/config/locales/en.yml index 97b6b5126..8a946dd70 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1481,7 +1481,7 @@ en: groups_and_categories: Groups and Categories description: "In %{portal}, ontologies are organized in groups and tagged with categories. Typically, groups associate ontologies from the same project or organization for better identification of the provenance. Whereas categories are about subjects/topics and enable to classify ontologies. As of 2016, %{portal}'s categories were established in cooperation with FAO AIMS. In 2024, we moved to UNESCO Thesaurus (https://vocabularies.unesco.org). Groups and categories, along with other metadata, can be used on the “Browse” page of %{portal} to filter out the list of ontologies." show_sub_categories: Show sub categories - + no_taxonomy_created: "No %{type} are created yet" federation: results_from_external_portals: Results from external portals not_responding: is not responding. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 9c9a9079b..5ce6e7f89 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1518,6 +1518,8 @@ fr: groups_and_categories: Groupes et Catégories description: "Dans %{portal}, les ontologies sont organisées en groupes et étiquetées avec des catégories. Typiquement, les groupes associent des ontologies provenant du même projet ou de la même organisation pour une meilleure identification de la provenance. Tandis que les catégories concernent des sujets/thématiques et permettent de classifier les ontologies. En 2016, les catégories d'%{portal} ont été établies en coopération avec FAO AIMS. En 2024, nous sommes passés au Thésaurus de l'UNESCO (https://vocabularies.unesco.org). Les groupes et les catégories, ainsi que d'autres métadonnées, peuvent être utilisés sur la page “Parcourir” d'%{portal} pour filtrer la liste des ontologies." show_sub_categories: Afficher les sous-catégories + no_taxonomy_created: "Aucun %{type} n'a encore été créé" + federation: results_from_external_portals: Résultats provenant de portails externes not_responding: ne répond pas.