Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge to master: Sync with release 3.0.3 of AgroPortal #36

Merged
merged 11 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 0 additions & 52 deletions .github/workflows/tests-real-data-testportal.yml

This file was deleted.

10 changes: 5 additions & 5 deletions app/components/concept_details_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ class ConceptDetailsComponent < ViewComponent::Base

attr_reader :concept_properties

def initialize(id:, acronym:, concept_id: nil , properties: nil, top_keys: [], bottom_keys: [], exclude_keys: [])
def initialize(id:, acronym:, concept_id: nil, properties: nil, top_keys: [], bottom_keys: [], exclude_keys: [])
@acronym = acronym
@properties = properties
@top_keys = top_keys
@bottom_keys = bottom_keys
@exclude_keys = exclude_keys
@id = id
@concept_id=concept_id
@concept_id = concept_id

@concept_properties = concept_properties2hash(@properties) if @properties
end
Expand Down Expand Up @@ -55,8 +55,8 @@ def row_hash_properties(properties_set, ontology_acronym, &block)
end

out << [
{ th: content_tag(:span, remove_owl_notation(key), title: url, 'data-controller': 'tooltip') },
{ td: content_tag(:span, ajax_links.join.html_safe) }
{ th: content_tag(:span, remove_owl_notation(key), title: url, 'data-controller': 'tooltip') },
{ td: list_items_component(max_items: 5) { |r| ajax_links.map { |val| r.container { val.html_safe } } } }
]
end
out
Expand All @@ -81,7 +81,7 @@ def filter_properties(top_keys, bottom_keys, exclude_keys, concept_properties)
private

def link_to_format_modal(format, icon)
link_to_modal(nil, "/ontologies/#{@acronym}/#{escape(@concept_id)}/serialize/#{format}",{ id: "resource_content_#{format}", data: {show_modal_title_value: @concept_id, show_modal_size_value: 'modal-xl'}}) do
link_to_modal(nil, "/ontologies/#{@acronym}/#{escape(@concept_id)}/serialize/#{format}", { id: "resource_content_#{format}", data: { show_modal_title_value: @concept_id, show_modal_size_value: 'modal-xl' } }) do
inline_svg("icons/#{icon}.svg", width: '50px', height: '50px')
end
end
Expand Down
10 changes: 10 additions & 0 deletions app/components/list_items_show_more_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true
class ListItemsShowMoreComponent < ViewComponent::Base
renders_many :containers

def initialize(max_items: 10)
super
@max_items = max_items - 1
end

end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
%div{data: {controller: 'reveal-component'}}
- containers[..@max_items].each do |item|
= item

- if (@max_items + 1) < containers.size
- Array(containers[@max_items+1..]).each do |item|
%span{'data-reveal-component-target': "item", class: 'd-none'}
= item
%div{'data-reveal-component-target': "showButton", 'data-action': "click->reveal-component#show" }
%span.btn-link
See more
%div.d-none{'data-reveal-component-target': "hideButton", 'data-action': "click->reveal-component#hide" }
%span.btn-link
See less
1 change: 1 addition & 0 deletions app/controllers/ontologies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ def search_first_instance_id

def keep_only_root_categories(categories)
categories.select do |category|
next unless category.id
category.id.start_with?(rest_url) || category.parentCategory.blank?
end
end
Expand Down
1 change: 1 addition & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def show
@user_ontologies ||= []

@admin_ontologies = @ontologies.select {|o| o.administeredBy.include? @user.id }
@accessed_ontologies = @ontologies.select {|o| o.acl.include? @user.id }

projects = LinkedData::Client::Models::Project.all;
@user_projects = projects.select {|p| p.creator.include? @user.id }
Expand Down
27 changes: 27 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -460,4 +460,31 @@ def category_is_parent?(parents_list, category)
[is_parent,parent_error_message]
end

def categories_with_children(categories)
parent_to_children = Hash.new { |hash, key| hash[key] = [] }
categories.each do |category|
next unless category.parentCategory
category.parentCategory.each do |parent_id|
parent_acronym = id_to_acronym(parent_id)
child_acronym = id_to_acronym(category.id)
parent_to_children[parent_acronym] << child_acronym
end
end
parent_to_children
end

def categories_with_parents(categories_children)
categories_parents = Hash.new { |hash, key| hash[key] = [] }
categories_children.each do |child, parents|
parents.each do |parent|
categories_parents[parent] << child
end
end
categories_parents
end

def id_to_acronym(id)
id.split('/').last
end

end
7 changes: 6 additions & 1 deletion app/helpers/components_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ def chips_component(id: , name: , label: , value: , checked: false , tooltip: ni
check_input(id: id, name: name, value: value, label: label, checked: checked, disabled: disabled, &block)
end
end
def list_items_component(max_items:, &block)
render ListItemsShowMoreComponent.new(max_items: max_items) do |r|
capture(r, &block)
end
end

def group_chip_component(id: nil, name: , object: , checked: , value: nil, title: nil, disabled: false, &block)
title ||= object["name"]
Expand Down Expand Up @@ -111,7 +116,7 @@ def resolvability_check_tag(url)
end

def rounded_button_component(link)
render RoundedButtonComponent.new(link: link, target: '_blank',size: 'small',title: t("components.go_to_api"))
render RoundedButtonComponent.new(link: link, target: '_blank', size: 'small', title: t("components.go_to_api"))
end

def copy_link_to_clipboard(url, show_content: false)
Expand Down
6 changes: 3 additions & 3 deletions app/helpers/federation_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def canonical_ontology(ontologies)
end

def federation_portal_status(portal_name: nil)
Rails.cache.fetch("federation_portal_up_#{portal_name}", expires_in: 2.hours) do
Rails.cache.fetch("federation_portal_up_#{portal_name}", expires_in: 10.minutes) do
portal_api = federated_portals&.dig(portal_name,:api)
return false unless portal_api
portal_up = false
Expand Down Expand Up @@ -260,8 +260,8 @@ def external_canonical_ontology_portal(ontologies)
def most_referred_portal(ontology_submissions)
portal_counts = Hash.new(0)
ontology_submissions.each do |submission|
federated_portals.keys.each do |portal|
portal_counts[portal] += 1 if submission[:pullLocation]&.include?(portal.to_s)
request_portals.each do |portal|
portal_counts[portal.downcase] += 1 if submission[:pullLocation]&.include?(portal.downcase)
end
end
portal_counts.max_by { |_, count| count }&.first
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/home_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def format_number_abbreviated(number)

def portal_config_tooltip(portal_name, &block)
portal_id = portal_name&.downcase
title = if federation_portal_status(portal_name: portal_id)
title = if (federation_portal_status(portal_name: portal_id) || portal_id.eql?(portal_name&.downcase))
render(
TurboFrameComponent.new(
id: "portal_config_tooltip_#{portal_id}",
Expand Down
9 changes: 5 additions & 4 deletions app/helpers/multi_languages_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module MultiLanguagesHelper
include OntologiesHelper, ComponentsHelper
def portal_lang
session[:locale] || 'en'
end
Expand Down Expand Up @@ -172,15 +173,15 @@ def display_in_multiple_languages(label)
closable: true)
end



label = label.to_h.reject { |key, _| %i[links context].include?(key) } if label.is_a?(OpenStruct)

if label.is_a?(String)
content_tag(:p, label)
elsif label.is_a?(Array)
content_tag(:div) do
raw(label.map { |x| content_tag(:div, x) }.join)
list_items_component(max_items: show_max) do |r|
label.map do |x|
r.container { content_tag(:span, x, class: style_as_badge ? 'badge bg-secondary' : '').html_safe }
end
end
else
content_tag(:div) do
Expand Down
12 changes: 4 additions & 8 deletions app/helpers/ontologies_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'iso-639'
module OntologiesHelper

REST_URI = $REST_URL
API_KEY = $API_KEY
LANGUAGE_FILTERABLE_SECTIONS = %w[classes schemes collections instances properties].freeze
Expand Down Expand Up @@ -801,10 +800,6 @@ def submission_languages(submission = @submission)
Array(submission&.naturalLanguage).map { |natural_language| natural_language["iso639"] && natural_language.split('/').last }.compact
end

def id_to_acronym(id)
id.split('/').last
end

def browse_taxonomy_tooltip(taxonomy_type)
return nil unless taxonomy_type.eql?("categories") || taxonomy_type.eql?("groups")

Expand All @@ -817,9 +812,10 @@ def browse_taxonomy_tooltip(taxonomy_type)
def browse_chip_filter(key:, object:, values:, countable: true, count: nil)
title = (key.to_s.eql?("categories") || key.to_s.eql?("groups")) ? nil : ''
checked = values.any? { |obj| [link_last_part(object["id"]), link_last_part(object["value"])].include?(obj) }

group_chip_component(name: key, object: object, checked: checked, title: title) do |c|
c.count { browse_chip_count_badge(key: key, id: object["id"], count: count) } if countable
content_tag(:div, (key.to_s.eql?("categories") ? { 'data-action' => 'click->parent-categories-selector#check' } : {})) do
group_chip_component(name: key, object: object, checked: checked, title: title) do |c|
c.count { browse_chip_count_badge(key: key, id: object["id"], count: count) } if countable
end
end
end

Expand Down
13 changes: 10 additions & 3 deletions app/helpers/submission_inputs_helper.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module SubmissionInputsHelper

class SubmissionMetadataInput
include MetadataHelper
include MetadataHelper, ApplicationHelper

def initialize(attribute_key:, attr_metadata:, submission: nil, label: nil)
@attribute_key = attribute_key
Expand Down Expand Up @@ -128,14 +128,21 @@ def ontology_administered_by_input(ontology = @ontology, users_list = @user_sele

def ontology_categories_input(ontology = @ontology, categories = @categories)
categories ||= LinkedData::Client::Models::Category.all(display_links: false, display_context: false)
categories_children = categories_with_children(categories)
categories_parents = categories_with_parents(categories_children)

render Input::InputFieldComponent.new(name: '', label: 'Categories') do
content_tag(:div, class: 'upload-ontology-chips-container') do
content_tag(:div, class: 'upload-ontology-chips-container', 'data-controller': 'parent-categories-selector',
'data-parent-categories-selector-categories-children-value': "#{categories_children.to_json}",
'data-parent-categories-selector-categories-parents-value': "#{categories_parents.to_json}",
'data-parent-categories-selector-target': "chips") do
hidden_field_tag('ontology[hasDomain][]') +
categories.map do |category|
categories.map do |category|
content_tag(:div, 'data-action': 'click->parent-categories-selector#check') do
category_chip_component(id: category[:acronym], name: "ontology[hasDomain][]",
object: category, value: category[:id],
checked: ontology.hasDomain&.any? { |x| x.eql?(category[:id]) })
end
end.join.html_safe
end
end
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,6 @@ application.register('mappings', MappingsController)

import ConceptsJsonButtonController from "./concepts_json_button_controller.js"
application.register('concepts-json', ConceptsJsonButtonController)

import ParentCategoriesSelectorController from "./parent_categories_selector_controller.js"
application.register('parent-categories-selector', ParentCategoriesSelectorController)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="parent-categories-selector"
export default class extends Controller {
static targets = ['chips']
static values = { categoriesChildren: Object, categoriesParents: Object}

check(event) {
const input = event.currentTarget.querySelector('input');
const allInputs = this.chipsTarget.querySelectorAll('input');
const parents = this.categoriesChildrenValue;
const children = this.categoriesParentsValue;
const browseLogic = !this.hasCategoriesParentsValue;

// Browse page logic:
// - Selecting a category will auto select all its children
// - Deselecting a category will auto deselect all its children
// Upload/Edit forms logic:
// - Selecting a category will auto select its parents
// - Deselecting a category will auto deselect its children

const inputAcronym = this.#id_to_acronym(input.value);

if (browseLogic) {
if (inputAcronym in parents) {
const parentChildren = parents[inputAcronym];
this.#toggleInputState(allInputs, i => parentChildren.includes(this.#id_to_acronym(i.value)), input.checked);
}
} else {
if (inputAcronym in parents) {
const parentChildren = parents[inputAcronym];
this.#toggleInputState(allInputs, i => parentChildren.includes(this.#id_to_acronym(i.value)), false);
}
if (inputAcronym in children) {
const childParents = children[inputAcronym];
this.#toggleInputState(allInputs, i => childParents.includes(this.#id_to_acronym(i.value)), true);
}
}
}

#toggleInputState(inputs, condition, state) {
inputs.forEach(input => {
if (condition(input)) {
input.checked = state;
input.dispatchEvent(new Event('change', { bubbles: true }));
}
});
}

#id_to_acronym(id){
return id.split('/').pop();
}
}
6 changes: 5 additions & 1 deletion app/javascript/controllers/turbo_frame_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ export default class extends Controller {
}

this.urlValue = this.#updatedPageUrl(data)

this.frame.src = this.urlValue

requestAnimationFrame(() => {
this.frame.setAttribute('busy', 'true');
});
}
}

Expand Down
3 changes: 1 addition & 2 deletions app/views/concepts/_details.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
- t.add_row({th: t('ontology_details.concept.synonyms')}) do |h|
- h.td do
%div.d-flex
%div.d-flex
= display_in_multiple_languages(@concept.synonym)
= display_in_multiple_languages(@concept.synonym, style_as_badge: true, show_max: 5)
%div.synonym-change-request
= add_synonym_button
= remove_synonym_button
Expand Down
Loading
Loading