").addClass(defClass).text(shortenDefinition(res.definition));
-}
-
-function determineHTTPS(url) {
- return url.replace("http:", ('https:' == document.location.protocol ? 'https:' : 'http:'));
-}
-
-function toggleAdvancedSearchOptions() {
- var elem = jQuery("#advanced_options");
- var searchOptions = jQuery("#search_options");
-
- if (elem.text() == elem.data("text-swap")) {
- elem.text(elem.data("text-original"));
- searchOptions.hide();
- } else {
- elem.data("text-original", elem.text());
- elem.text(elem.data("text-swap"));
- searchOptions.show();
- }
-}
-
-
diff --git a/app/assets/javascripts/components/data_table/data_table.js b/app/assets/javascripts/components/data_table/data_table.js
index ecb6d1938..cca5c0a08 100644
--- a/app/assets/javascripts/components/data_table/data_table.js
+++ b/app/assets/javascripts/components/data_table/data_table.js
@@ -12,6 +12,8 @@ class DataTable extends HTMLElement{
super()
this.tableElem = document.createElement("table")
this.tableElem.style.width = "100%"
+ this.tableElem.classList.add('table-content')
+ this.tableElem.classList.add('table-content-stripped')
this.container = document.createElement("div")
this.container.appendChild(this.tableElem)
diff --git a/app/assets/javascripts/components/instances/instances_table.js b/app/assets/javascripts/components/instances/instances_table.js
index 55a036d83..8fb4371cb 100644
--- a/app/assets/javascripts/components/instances/instances_table.js
+++ b/app/assets/javascripts/components/instances/instances_table.js
@@ -32,7 +32,8 @@ class InstancesTable extends DataTable {
id: x["table"]["@id"],
label: x["table"]["label"],
prefLabel: x["table"]["prefLabel"],
- labelToPrint: x["table"]["labelToPrint"]
+ labelToPrint: x["table"]["labelToPrint"],
+ ontology: x["table"]["ontology"]
},
x["table"]["types"],
x["table"]["properties"]
@@ -70,11 +71,6 @@ class InstancesTable extends DataTable {
connectedCallback() {
super.connectedCallback()
- this.addEventListener("row-click", (e) => {
- this.openPopUpDetail(e.detail.data)
- })
-
-
}
update(ontologyAcronym, classUri) {
@@ -90,8 +86,8 @@ class InstancesTable extends DataTable {
"name": "label",
"title": 'Instance',
"render": (data) => {
- const {id, labelToPrint} = data
- return `
${labelToPrint}`
+ const {id, labelToPrint, ontology} = data
+ return `
${labelToPrint}`
}
}]
@@ -103,6 +99,7 @@ class InstancesTable extends DataTable {
"render": (data) => data.map(x => {
const id = x.type
const label = x.labelToPrint
+ const acronym = x.ontology
const href = (id === label ? id : `?p=classes&conceptid=${encodeURIComponent(id)}`)
return `
${label}`
})
@@ -125,12 +122,5 @@ class InstancesTable extends DataTable {
return this.classUri.length > 0
}
- openPopUpDetail(data) {
- let {id} = data[0]
- const href = `/ontologies/${this.ontologyAcronym}/instances/${encodeURIComponent(id)}`
- popUpElement({ajax: href})
-
- }
-
}
\ No newline at end of file
diff --git a/app/assets/javascripts/components/pop_up.js b/app/assets/javascripts/components/pop_up.js
deleted file mode 100644
index a654a6071..000000000
--- a/app/assets/javascripts/components/pop_up.js
+++ /dev/null
@@ -1,5 +0,0 @@
-function popUpElement(element){
- $.facebox(() => {
- $.facebox(element)
- })
-}
\ No newline at end of file
diff --git a/app/assets/javascripts/home.js.erb b/app/assets/javascripts/home.js.erb
deleted file mode 100644
index 5a53b5cd3..000000000
--- a/app/assets/javascripts/home.js.erb
+++ /dev/null
@@ -1,142 +0,0 @@
-function numberWithCommas(x) {
- return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-}
-
-function jumpToValueOntology() {
- var ontology = jQuery("#find_ontology")[0].value;
- var ontology_id = jQuery("#find_ontology_id").val();
-
- if (ontology_id == null || ontology_id == "") {
- // didnt pick an ont
- alert("The ontology does not exist. You must pick an ontology from the list.")
-
- return false;
- }
-
- if (!!ontology_id) {
- var sValue = jQuery("#find_ontology_id").val();
- if (sValue == null || sValue == "") {
- sValue = data;
- }
- document.location="/ontologies/"+sValue;
- jQuery.blockUI({ message: '
" /> Loading Ontology...
' });
- return;
- }
-}
-
-function formatResultOntologySearch(value, data) {
- jQuery("#find_ontology_id").val("");
- var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\
- var keywords = jQuery("#find_ontology").val().replace(specials, "\\$&").split(' ').join('|');
- var regex = new RegExp( '(' + keywords + ')', 'gi' );
- return value.replace(regex, "
$1");
-}
-
-// Sets a hidden form value that records the virtual id when a concept is chosen in the jump to
-// This is a workaround because the default autocomplete search method cannot distinguish between two
-// ontologies that have the same preferred name but different ids.
-function selectFindOntology(value, data){
- jQuery("#find_ontology_id").val(value.data[0]);
- jQuery("#find_ontology").focus();
- jumpToValueOntology();
-}
-
-var ontologies_array = [];
-var findOntologyInput = document.getElementById("find_ontology");
-if (findOntologyInput) {
- ontologies_array = JSON.parse(findOntologyInput.dataset.ontologynames);
-}
-
-jQuery(document).ready(function() {
- jQuery("#find_ontology").autocomplete({
- selectFirst: true,
- data: ontologies_array,
- minChars: 1,
- matchSubset: 1,
- maxItemsToShow: 20,
- delay: 1,
- showResult: formatResultOntologySearch,
- onItemSelect: selectFindOntology
- });
-
- var visitsChartDiv = document.getElementById("ontology-visits-chart");
-
- if (visitsChartDiv) {
- var ontNamesObject = JSON.parse(visitsChartDiv.dataset.ontnames);
- var ontNames = Object.keys(ontNamesObject);
- var ontNumbers = JSON.parse(visitsChartDiv.dataset.ontnumbers);
- var onts = JSON.parse(visitsChartDiv.dataset.ontnames);
- var ctx = document.getElementById("myChart");
-
- var myChart = new Chart(ctx, {
- type: 'horizontalBar',
- data: {
- labels: ontNames,
- datasets: [{
- label: "Ontology Visits",
- data: ontNumbers,
- backgroundColor: "rgba(151,187,205,0.2)",
- borderColor: "rgba(151,187,205,1)",
- borderWidth: 1
- }]
- },
- options: {
- responsive: true,
- legend: {
- display: false
- },
- scales: {
- xAxes: [{
- ticks: {
- beginAtZero: true,
- stepSize: 5000,
- // Return an empty string to draw the tick line but hide the tick label
- // Return `null` or `undefined` to hide the tick line entirely
- userCallback: function(value, index, values) {
- return numberWithCommas(value);
- }
- }
- }],
- yAxes: [{
- ticks: {}
- }]
- },
- tooltips: {
- enabled: true,
- callbacks: {
- title: function(tooltipItems, data) {
- lbl = onts[tooltipItems[0].yLabel];
-
- if (lbl.length > 45) {
- lbl = lbl.substring(0, 37) + "...";
- }
- return lbl + " (" + tooltipItems[0].yLabel + ")";
- },
- label: function(tooltipItem, data) {
- return data.datasets[0].label + ": " + numberWithCommas(tooltipItem.xLabel);
- }
- }
- },
- hover: {
- onHover: function(e) {
- jQuery("#myChart").css("cursor", e[0] ? "pointer" : "default");
- }
- }
- }
- });
-
- ctx.onclick = function(evt) {
- var activePoints = myChart.getElementsAtEvent(evt);
-
- if (activePoints.length > 0) {
- // get the internal index of slice in pie chart
- var clickedElementIndex = activePoints[0]["_index"];
- // get specific label by index
- var label = myChart.data.labels[clickedElementIndex];
- // get value by index
- // var value = myChart.data.datasets[0].data[clickedElementIndex];
- window.location.href = "/ontologies/" + label;
- }
- }
- }
-});
\ No newline at end of file
diff --git a/app/assets/javascripts/ontologies.js b/app/assets/javascripts/ontologies.js
deleted file mode 100644
index 413f9f267..000000000
--- a/app/assets/javascripts/ontologies.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Ontology creation & editing */
-
-
-function hideAllRestrictions() {
- jQuery(".viewing_restriction_disabled").attr("disabled", true);
- jQuery("div.viewing_restriction_types").addClass("hidden");
-}
-
-function showRestrictionPrivate() {
- jQuery("#ontology_acl").removeAttr("disabled");
- jQuery("#viewingRestrictionsPrivate").removeClass("hidden");
-}
-
-function showRestrictionLicensed() {
- jQuery("#ontology_licenseInformation").removeAttr("disabled");
- jQuery("#viewingRestrictionsLicensed").removeClass("hidden");
-}
-
-jQuery(document).ready(function () {
- jQuery('#ontology-browse-help').on('click', bpPopWindow);
-});
-
-/* charts creation */
-
-function showVisitsChat(){
- var ontologyVisitsChartCanvas = document.getElementById('visits_chart');
-
- if (ontologyVisitsChartCanvas) {
- var labels = JSON.parse(ontologyVisitsChartCanvas.dataset.labels);
- var visits = JSON.parse(ontologyVisitsChartCanvas.dataset.visits);
- var context = ontologyVisitsChartCanvas.getContext('2d');
-
- var ontologyVisitsChart = new Chart(context, {
- type: 'line',
- data: {
- labels: labels,
- datasets: [{
- label: 'Visits',
- data: visits,
- backgroundColor: 'rgba(151, 187, 205, 0.2)',
- borderColor: 'rgba(151, 187, 205, 1)',
- pointBorderColor: 'rgba(151, 187, 205, 1)',
- pointBackgroundColor: 'rgba(151, 187, 205, 1)',
- }]
- },
- options: {
- responsive: true,
- legend: {
- display: false
- },
- scales: {
- yAxes: [{
- ticks: {
- beginAtZero: false,
- callback: function (value, index, values) {
- return numberWithCommas(value);
- }
- }
- }]
- },
- tooltips: {
- displayColors: false,
- callbacks: {
- label: function (tooltipItem, data) {
- return numberWithCommas(tooltipItem.yLabel);
- }
- }
- }
- }
- });
- }
- return ontologyVisitsChart
-}
diff --git a/app/assets/javascripts/projects.js b/app/assets/javascripts/projects.js
index bcfe5ccc9..757292543 100644
--- a/app/assets/javascripts/projects.js
+++ b/app/assets/javascripts/projects.js
@@ -23,12 +23,6 @@ jQuery(document).ready(function() {
// Set the table width after it gets altered by jQuery DataTable
jQuery("#projects").css("width","100%");
- if (jQuery("#projects").length) {
- new jQuery.fn.dataTable.FixedHeader(projectsTable, {
- header: true
- });
- }
-
jQuery('#projects-help').on("click", bpPopWindow);
});
diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js
index 5eb106f47..f395ce598 100644
--- a/app/assets/javascripts/vendor.js
+++ b/app/assets/javascripts/vendor.js
@@ -6,34 +6,21 @@
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
-//
+// Jquery 2 dependencies
//= require jquery2
//= require jquery-migrate-1.3.0.min
//= require jquery_ujs
//= require jquery-ui
+// popper is required by bootstrap 4
//= require popper
//= require bootstrap-sprockets
-//
-//= require jquery.blockUI
-//= require facebox
-//= require thickbox
-//= require fg.menu
-//= require jquery.tools.min
+// Other
//= require jquery.dataTables
-//= require dataTables.fixedHeader
//= require chosen.jquery
-//= require ajax-chosen
-//= require jquery.cookie
//= require autocomplete
-//= require jquery.hoverIntent
-//= require jquery.simple.tree
-//= require jquery.scrollTo-1.4.0-min
-//= require jquery.rating.pack
-//= require history/jquery.history
+// Alertify is used the admin page
//= require alertify
-//= require jquery.tooltip
-//= require Chart.min
-//= require select2
//= require jquery.readyselector
+// can be removed used only in the ontology bridge form
//= require trumbowyg
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index ad58c2c44..190f15528 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -8,6 +8,27 @@
margin-bottom: 30px;
}
+.analytics {
+ .card-header-1{
+ color: white; font-size: 60px; font-weight: 600; word-wrap: break-word
+ }
+
+ .card-header-2{
+ color: white; font-size: 14px; font-weight: 400; word-wrap: break-word
+ }
+
+ .card-header-3{
+ color: white; opacity: 0.6; font-size: 14px; font-weight: 400; word-wrap: break-word
+ }
+}
+
+.yasgui .autocompleteWrapper, .yasgui .tabContextButton{
+ display: none !important;
+}
+.yasqe .yasqe_buttons .yasqe_share{
+ display: none !important;
+}
+
.alert-box span {
font-weight: bold;
text-transform: uppercase;
@@ -106,10 +127,7 @@ table.dataTable tbody tr.selected {
display: none;
}
-/* to fix facebox default sizing in chrome */
-#facebox .body {
- width: 375px !important;
-}
+
.zebra td {
padding: 8px 12px 8px 12px !important;
diff --git a/app/assets/stylesheets/agent_tooltip.scss b/app/assets/stylesheets/agent_tooltip.scss
index 130be89f5..7460f746e 100644
--- a/app/assets/stylesheets/agent_tooltip.scss
+++ b/app/assets/stylesheets/agent_tooltip.scss
@@ -22,8 +22,22 @@
font-size: 16px;
font-weight: 400;
color: #767676;
- margin-bottom: 3px;
+ margin-bottom: 5px;
+ display: flex;
+ align-items: center;
}
.agent-type-icon path{
fill: var(--primary-color)
+}
+.agent-dependency-icon{
+ width: 20px;
+ height: 20px;
+ margin-right: 5px;
+}
+.agent-dependency-icon.ror{
+ width: 30px;
+ height: 30px;
+}
+.agent-dependency-icon path{
+ fill: #C0C0C0
}
\ No newline at end of file
diff --git a/app/assets/stylesheets/application.css.scss.erb b/app/assets/stylesheets/application.css.scss.erb
index 0040a5ba4..966c35701 100755
--- a/app/assets/stylesheets/application.css.scss.erb
+++ b/app/assets/stylesheets/application.css.scss.erb
@@ -11,14 +11,8 @@
*= require jquery-ui
*= require alertify
*= require chosen
- *= require facebox
- *= require fg.menu
*= require jquery-ui-1.8.1.custom
*= require jquery.autocomplete
- *= require jquery.rating
- *= require jquery.tooltip
- *= require thickbox
- *= require select2
*= require trumbowyg
*= require flag-icon
*= require theme-variables
@@ -39,7 +33,6 @@
@import "recommender";
@import "search";
@import "submissions";
-@import "tree";
@import "ontolobridge";
@import "fair_assement";
@import "instances_table";
@@ -49,6 +42,7 @@
@import "tom-select/dist/scss/tom-select";
@import "tippy.js/dist/tippy";
@import 'tippy.js/themes/light-border';
+@import '@triply/yasgui/build/yasgui.min';
@import "feedback";
@import "login";
@import "components/index";
diff --git a/app/assets/stylesheets/bioportal.scss b/app/assets/stylesheets/bioportal.scss
index a00e324f2..9d1ae3b4d 100644
--- a/app/assets/stylesheets/bioportal.scss
+++ b/app/assets/stylesheets/bioportal.scss
@@ -580,7 +580,7 @@ tr.mainresource td {
}
.obsolete_class {
- color: rgb(100,100,100);
+ color: rgb(100,100,100)!important;
cursor: help;
font-style: oblique;
}
@@ -650,7 +650,8 @@ div.tree_error {
}
#bd ul.simpleTree li{
- margin-left:-10px;
+ margin-left: 0px;
+ padding: 5px 0 0 10px;
}
#bd ul.simpleTree{
@@ -668,6 +669,22 @@ div.tree_error {
overflow:auto;
border: 1px solid #444444;
*/
+ a.tree-link {
+ display: inline-block;
+ padding: 5px;
+ }
+
+ a.tree-link.active {
+ cursor: default;
+ background-color: var(--light-color);
+ font-weight: bold;
+ border-radius: 2px;
+ }
+
+ .tree-border-left{
+ border-left: 2px dotted #eee;
+ margin-left: 2px;
+ }
}
.simpleTree li {
list-style: none;
diff --git a/app/assets/stylesheets/components/index.scss b/app/assets/stylesheets/components/index.scss
index 8a6ff12cc..11229aadd 100644
--- a/app/assets/stylesheets/components/index.scss
+++ b/app/assets/stylesheets/components/index.scss
@@ -27,3 +27,4 @@
@import "alert";
@import "progress_pages";
@import "select";
+@import "search_result";
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/search_result.scss b/app/assets/stylesheets/components/search_result.scss
new file mode 100644
index 000000000..9dfa051cb
--- /dev/null
+++ b/app/assets/stylesheets/components/search_result.scss
@@ -0,0 +1,113 @@
+.search-result-component.sub-component{
+ margin-bottom: 10px;
+}
+
+
+.search-result-component .title{
+ color: var(--primary-color) !important;
+ font-size: 20px;
+ font-weight: 500;
+}
+
+.search-result-component.sub-component .title{
+ color: var(--primary-color) !important;
+ font-size: 18px;
+ font-weight: 500;
+}
+
+.search-result-component .uri{
+ color: #888888;
+ font-size: 14px;
+ margin: 3px 0;
+}
+
+.search-result-component.sub-component .uri{
+ color: #888888;
+ font-size: 12px;
+ margin: 3px 0;
+}
+
+.search-result-component .actions{
+ display: flex;
+ margin-top: 10px;
+}
+
+.search-result-component.sub-component .actions{
+ display: flex;
+ margin-top: 7px;
+}
+
+.search-result-component .actions .button{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 4px;
+ background-color: var(--light-color);
+ padding: 5px 13px;
+ margin-right: 10px;
+}
+
+.search-result-component .actions .button:hover{
+ cursor: pointer;
+}
+
+.search-result-component .actions .button svg path{
+ fill: var(--primary-color);
+}
+
+.search-result-component .actions .button .text{
+ color: var(--primary-color);
+ margin-left: 8px;
+}
+
+.search-result-component.sub-component .actions .button .text{
+ font-size: 12px;
+}
+
+.search-result-component.sub-component .actions .button svg{
+ width: 12px;
+}
+
+.search-result-component .actions .button.icon-right .text{
+ margin-right: 8px;
+ margin-left: 0;
+}
+
+.more-from-ontology{
+ display: flex;
+ margin-top: 10px;
+}
+
+.more-from-ontology .vertical-line{
+ width: 1px;
+ background-color: var(--primary-color);
+ border-radius: 100px;
+ margin-right: 30px;
+}
+
+.search-result-sub-components{
+ margin: 20px 0;
+}
+
+.search-result-sub-components .reuses-title{
+ display: flex;
+ align-items: center;
+ margin-bottom: 5px;
+}
+
+.search-result-sub-components .reuses-title div{
+ margin-left: 10px;
+ font-size: 16px;
+ font-weight: 600;
+ color: #888888;
+}
+
+.more-from-ontology.reuses{
+ background-color: #F8F8F8;
+}
+.more-from-ontology.reuses .vertical-line{
+ background-color: #888888;
+}
+
+
+
diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss
index 5c56f7d9b..6790291bd 100644
--- a/app/assets/stylesheets/home.scss
+++ b/app/assets/stylesheets/home.scss
@@ -153,7 +153,7 @@ i.fa.fa-caret-square-o-down {
.home-statistics-container{
border-radius: 8px;
box-shadow: 2px 0px 60px rgba(0, 0, 0, 0.10);
- padding: 30px 40px;
+ padding: 30px 40px 10px 40px;
}
.home-statistics-container > div {
diff --git a/app/assets/stylesheets/mappings.scss b/app/assets/stylesheets/mappings.scss
index c4dbece77..070fafea7 100644
--- a/app/assets/stylesheets/mappings.scss
+++ b/app/assets/stylesheets/mappings.scss
@@ -58,7 +58,7 @@ div#map_from_concept_details_table, div#map_to_concept_details_table {
overflow: auto;
}
-#map_to_picker, .select2-container {
+#map_to_picker {
width: 100% !important;
}
diff --git a/app/assets/stylesheets/notes.scss b/app/assets/stylesheets/notes.scss
index 43003ae26..0e957b2d2 100644
--- a/app/assets/stylesheets/notes.scss
+++ b/app/assets/stylesheets/notes.scss
@@ -136,11 +136,6 @@ textarea.create_note_inputs {
font-size: 12pt;
}
-.ontologies.show div#facebox div.discussion {
- padding-top: 1em;
- padding-left: 1.5em;
-}
-
.reply_author {
color: #234979;
}
diff --git a/app/assets/stylesheets/ontologies.scss b/app/assets/stylesheets/ontologies.scss
index c5acad290..f02dcbd00 100644
--- a/app/assets/stylesheets/ontologies.scss
+++ b/app/assets/stylesheets/ontologies.scss
@@ -261,9 +261,6 @@ $widget-table-border-color: #EFEFEF;
margin-right: 15px;
}
-#ontology-browse-help i {
- margin-left: .25em;
-}
/************************************
/* Schemes pane
diff --git a/app/assets/stylesheets/search.scss b/app/assets/stylesheets/search.scss
index ab621fb36..584ee3fad 100644
--- a/app/assets/stylesheets/search.scss
+++ b/app/assets/stylesheets/search.scss
@@ -1,185 +1,90 @@
-form.button-to {
- float: left;
+.search-page-container {
+ display: flex;
+ justify-content: center;
}
-
-#ontology_picker_head {
- font-size: 10pt !important;
-}
-
-.not_visible {
- position: fixed !important;
- top: -999999px !important;
-}
-
-#search_results_container #search_results_info {
- display: none !important;
-}
-
-#search_results_filter {
- display: none;
-}
-
-#search_spinner {
- display: inline-block;
- padding: 8px 4px;
+.search-page-subcontainer {
+ width: 1248px;
+ padding: 20px 50px;
}
-
-#search_options #ontology_ontologyId {
- display: none;
-}
-
-.class_details_pop {
- overflow: auto;
- width: 750px !important;
- display: block !important;
+.search-page-input-container{
+ width: 100%;
}
-table#search_results td {
- vertical-align: top;
- padding: 12px 8px 12px 12px;
+.search-page-input{
+ position: relative;
+ padding-bottom: 80px;
}
-
-div.search_result {
- margin-bottom: 1.5em;
-}
-
-div.class_link a {
+.search-page-input input{
+ position: absolute;
+ border-radius: 100px;
+ box-shadow: rgba(100, 100, 111, 0.1) 0 7px 29px 0;
+ border: none;
+ outline: none;
font-size: 18px;
+ padding: 15px 25px;
+ width: 100%;
}
-
-span.class_def {
- display: block;
- margin: 3px 0 2px;
- font-size: 12px;
-}
-
-.additional_ont_results {
- padding: 2em;
- margin: 2em;
- background-color: rgb(230,230,230);
-}
-
-.additional_cls_results {
- padding: 2em;
- margin: 2em;
- background-color: rgb(230,230,230);
-}
-
-.subordinate_ont_results {
- padding: 1em;
- padding-left: 2em;
- padding-top: 2em;
- margin: 1em;
- margin-left: 2em;
- margin-top: 2em;
- background-color: rgb(240,240,240);
-}
-
-.subordinate_ont_results_title {
- color: rgb(100,100,100);
- background: rgb(200,200,200);
- padding: 0.5em;
+.search-page-input input:focus{
+ box-shadow: rgba(100, 100, 111, 0.2) 0 7px 29px 0;
}
-
-div.search_result_additional {
- padding-left: 30px;
- margin: 1em 0 1.2em;
+.search-page-advanced{
+ display: flex;
+ margin-bottom: 15px;
}
-
-div.search_result_additional .class_link a {
- font-size: 15px !important;
+.search-page-advanced .left{
+ width: 600px;
+ margin-right: 40px;
}
-
-div.additional_results_link {
- margin-top: 5px;
+.search-page-advanced .filter-container{
+ margin-bottom: 15px;
}
-
-.search_result_links a {
- font-size: 11px !important;
- color: green;
+.search-page-advanced .filter-container .title{
+ margin-bottom: 5px;
+ color: #888888;
+ font-size: 14px;
}
-.hide_link {
- text-decoration: underline;
- padding-left: 7px;
-}
-.not_underlined {
- text-decoration: none;
-}
-#search_results {
- display: none;
-}
-#search_results_container {
- margin-top: .5em;
- clear: both;
+.search-page-options{
+
}
-
-div#search_categories_chzn {
- width: 432px !important;
+.search-page-button{
+ position: absolute;
+ top: 14px;
+ left: 1104px;
+ border: none;
+ background: none;
}
-
-div#search_categories_chzn .chzn-choices input {
- font-style: oblique;
+.search-page-button svg path{
+ fill: var(--primary-color)
}
-
-div#search_categories_chzn.chzn-container-active input {
- font-style: normal !important;
+.search-page-button:hover{
+ cursor: pointer;
}
-
-div#search_categories_chzn .chzn-drop {
- width: 432px !important;
+.search-page-options{
+ display: flex;
+ justify-content: space-between;
}
-
-#search_messages {
- font-style: oblique;
- color: gray;
- padding-bottom: 7px;
-}
-
-#result_stats a {
- color: gray;
+.search-page-advanced-button{
+ display: flex;
}
-
-#ontology_counts {
- display: none;
+.search-page-advanced-button :hover{
+ cursor: pointer;
}
-
-.popup_counts {
- float: right;
- display: none;
+.search-page-advanced-button .text{
+ margin-left: 10px;
+ color: var(--primary-color);
}
-.ontology_counts_tooltip {
- background-color: #EEEEEE;
- border: 1px solid black;
- color: black;
- font-size: 12px;
- padding: 10px 15px;
- text-align: left;
- z-index: 999;
- box-shadow: 3px 3px 7px gray;
+.search-page-advanced-button .icon svg path{
+ fill: var(--primary-color);
}
-
-.definition {
- cursor: help;
+.search-page-number-of-results{
+ color: #888888;
}
-.concept_uri {
- font-size: 9pt;
- color: gray;
+.search-page-result-element{
+ margin-top: 40px;
}
-
-#search_categories_chosen .chosen-container .chosen-container-multi {
- width: 432px;
-}
-
-/* Prevents placeholder text in search input from being truncated.
-/* https://github.com/harvesthq/chosen/issues/2029#issuecomment-187442769 */
-#search_options #ontology_ontologyId_chosen .search-field:only-child,
-#search_options #ontology_ontologyId_chosen .search-field:only-child input {
- width: 100% !important;
-}
-
diff --git a/app/assets/stylesheets/tree.scss b/app/assets/stylesheets/tree.scss
deleted file mode 100644
index ed2d3a7c7..000000000
--- a/app/assets/stylesheets/tree.scss
+++ /dev/null
@@ -1,323 +0,0 @@
-/********************
-## TREE VIEW
-*********************/
-div.tree_error {
- background: none repeat scroll 0 0 lightYellow;
- font-weight: 600;
- padding: 5px 10px;
-}
-.expansion_error {
- color: red;
- font-size: x-small;
- font-style: oblique;
- padding: 0 3px;
-}
-.ncboTree {
- margin:0;
- padding:0;
- font-family: sans-serif;
-}
-.ncboTree li {
- list-style: none;
- margin:0;
- padding:0 0 0 22px;
- line-height: 14px;
-}
-.ncboTree li span {
- display:inline;
- clear: left;
- white-space: nowrap;
-}
-.ncboTree ul {
- margin:0;
- padding:0;
-}
-.ncboTree .root ul {
- margin:0;
-}
-.ncboTree .root {
- margin-left:-16px !important;
-}
-.ncboTree .line {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAIABAICAgP///yH5BAEAAAEALAAAAABQABQAAAI0jI+py+0PG4i02ouz3mryD4bi+HjkiabqYq7uC2NtTNd2MN/6Tub8D5QFh8SKr4hEHpOQAgA7);
-}
-.ncboTree .line-last {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);
-}
-.ncboTree .line-over {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAMQfAICAgEVFRUZHRoKBgUlISKKionl6enJycmRkY2tra/Ly81JSUpGRkaqqq8rLyrOzstnZ2cLDwk1NTfv8+/f39+zt7Lq7u+fn5lhYV////15eXuDg4NLS0omKipqamf///yH5BAEAAB8ALAAAAABQABQAAAV44CeOH0CSQXCubOu+cAwHAvFJ3/Jhn/Yhn8Tn8DF8Bp/Oh/HxfAqfxufxsXwiH8eH84F8Np/Lp/JRfCifyScjM7FSsrh8Tq/b73Q3fs/v+/9zeoCDhIWGMIKHiouMeImNkJGSJI+TlpeFlZibnHeanaChL5+ipZshADs=);
-}
-.ncboTree .line-over-last {
- padding:0;
- line-height: 3px;
- height:3px;
- font-size:3px;
- background: 0 0 no-repeat transparent url(data:image/gif;base64,R0lGODlhUAAUAMQeAEVFRWtra+fn5k1NTWRkY3l6enJycklISMrLyvLy8////5qamV5eXvf397q7u1hYV8LDwkZHRoKBgbOzspGRkVJSUtnZ2eDg4Ozt7Pv8+6qqq9LS0omKiqKiov///wAAACH5BAEAAB4ALAAAAABQABQAAAVooCeOZOkBgKmubOu+8AhEhzd4lfd4jEd4AY/BU/BIPBwPxbPwdDwaz8Tj8EA8CM/GY/FcPAIPxpPwNDwZjyK2QrHf8Lh8Tq/b7/i8fs/v+/+AgYKDhIWGh4iJiouMjY6PkJGSk5SViSEAOw==);
-}
-.ncboTree .folder-open {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEQC6BOYAAICAgP//nHueu8aaGfn7+f/4k8TExP/////bdf/vif/kf///mQQCBMS+uaVzDcyZNM/PvNrYyuzs6OTe1s3Nzevz+7fG18mWMfr7/MuYM///paBuCJpoAsXFxZ5sBpxqBNDc58+iJqRyDPfwiZlnAf/XhMzLx6NxC7q6tNe4QLqHIsiVMJKvx523zad1D9q/bLB+GL/M2/r7+n2fvLOBG36gvb2KJfDkesKPKuKzQ7WCHf/rhMmgIbeEH6JwCsaaGv3VcOLBUKx6FNHR0fH097e3t////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEYALAAAAAARALoEAAf/gEaCg4SFhoMAh4qLi4mMRkQgLTMClQIWiiwyBJydAooCnaKfh6GiFROkhqEMra0Rn4mOggIVFRK4E7CguhEQvyaqhQIQDcYNKA3ChDE1lpaYj7OP1IfT1diC19nV29zS39ze4Yrj5Ibm54Tp6trt4O+N8fLz1vX294Xs7fvq/ef/yAUMN/BbQXH59CVctxBRQ3cPD2aTiI1it4dGLFLTCK8hR0Yf6XnEGLIcyZMRUY5MyXKly4Ul8b1MGBOdSpg3aebMV1NhS5w/dQblufNeT4ZDjRatd9RhUqZL5zWFOJPoU6lR403NmPXd1q9d+YX1NxZgWYFnCaY1uBbhVa1t/yfGrTj34luvdTfm7Qi0qtK7YgGTFWyWMFrDahGzVezWL1TGciHTlWzXMVbKejHzFWoZrmaQe0F/Ftm3NGfTVjvjHW2StUzUf1UHlj2YdmHbh3En1r2Yd2PYj31HFj6ZeGXgl41nVr45NXLPzEVHJ326unPrsZ+vnt6a+2vswbXPFl+b/G3zudHvVt+b/W/wyd0Pl1+c/nH40O0v1988O/7t/EkXIHXXFeifgeH9N56C5TF4noPpQbiehO1R+B6C8Vk4n4b1cXgfhvl5uJ+I/SUIIoAkCpgigQe2aKKLGZ64oIwN0vigjRHiOKGOFfJ4IYwh+rihkB0S+SGQKBo5ov+SJcaI5IxP1hjljVPmWOWOV/aY5Y8vdumkl0FuOaSYRZJ5JJhJmrmkmk2GiSaUb0oZJ5VzWlknlndqmSeXX/bppp9p7jmmoGUSeiagcCIqp6J0Mmqno3hCqqekfP5paaCUDpppoZseemminy4aaqOjPlpqpKdOmmqlmK6qqaucwuppq7SCWquot5Kaq6m7otqrqr+yauuwuBKrq7G8IuurssAyK2yx0B4bbbLTLltts9c+K+221HJrrbfYgqttt+R+W264545r7rrosqtuu/C+K++rwdLrrL3Z4iuuvuny666/8QI8b6z1EnyvwfkivK/C/TL8r8MBQzzwrAdTnLBYxQtj3LDGD3McsccTr2moyJ2SLKvJBYMs8MoSs6xyyzC/LDPKFdN8sc0Z47yxzh3z/LHPIbeZMtAuEx2z0TMLXbPSNzOds9M7Q92z1D9THTRGWGetdTiBAAA7);
-}
-.ncboTree .folder-open-last {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEQAWAOYAAP/bdf/vif/kf///mQQCBMS+uaVzDc/PvICAgNrYysyZNM3Nzevz++zs6OTe1smWMcXFxbfG15poAp5sBv//pZxqBPr7/MuYM6BuCLWCHX6gvdHR0cKPKuLBULB+GJlnAdq/bPfwiaRyDLe3t7eEH7q6tOKzQ7/M28mgIciVMNDc58+iJvr7+qx6FPDkeszLx7OBG5Kvx/3VcLqHIp23zb2KJcaaGqNxC6JwCv/rhH2fvNe4QP/XhPH096d1D8TExP/4k/n7+caaGXueu///nP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEYALAAAAAARABYAAAdcgEaCg4SFhoMIh4qLi4mMj4c9KjQ6Q5ZDEYoxLEGdnkOKQ56joIeiowwOpYaiBK6uCaCJjoJDDAwNuQ6xobsJB8Avq4VDBwXHBSUFw4QnGpeXmZDT1NXW19jZ1oEAOw==);
-}
-.ncboTree .folder-close-last {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgAWAOYAAOvr6//bdf//nP/vif/kf//4k//UbwQCBO/v78S+ufv7+9u3UoCAgNrYysyZNMHBwevz++Tk5M/PvOTe1smWMcKPKpxqBLB+GLOBG72KJaBuCP//uuzs6LfG17e3t5lnAbWCHdu3caNxC55sBsuYM7qHIsCNKLq6tMiVMKx6FMbGxp23zceUL/r7+q58Fr/M26VzDbeEH6d1D32fvKt5E/H0936gvZKvx6h2EJpoAqampszLx8WSLdDc57a2tvn7+Xueu///////mf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEMALAAAAAASABYAAAdfgEOCg4SFhoQMh4qLjEOJjZCHNT0rM0CXQB2LNy0/np9Ai0CfB6CipD8QE6GKowevrw2hiY+DQBAQHAccE7KivQ0HEhI7rIdAEgnKCScJxoYvNpiYmpHW19jZ2tvc2YEAOw==);
-}
-.ncboTree .folder-close {
- background: 0 -2px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgC+BOYAAICAgP//mXueu/n7+f///7a2tuvr6//Ub//4k///nP/vif/bdf/kfwQCBPv7++/v78S+udu3UtrYysyZNOTe1sHBwc/PvOTk5Ovz++zs6Nu3cbB+GLqHIrfG16BuCJlnAf//usmWMcKPKrWCHcuYM5xqBL2KJbOBG55sBqNxC7e3t8iVMJ23zcCNKKt5E6h2ELq6tL/M26ampreEH/H098bGxn6gvczLx8WSLceUL658Fn2fvPr7+qVzDad1D6x6FJKvx5poAtDc5////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEMALAAAAAASAL4EAAf/gEOCg4SFhoQAh4qLjEOJjUM0Qiw7ApYCHYtAPAOdngKLAp4Nn6GjAxgUoIqiDa6uEqCJj4MCGBgZDRkUsaG8Eg0WFjerhwIWEMkQMBDFhjE2l5eZkLSQ14fW2NuC2tzY3t/V4t/h5Ivm59nq4OzX6e6D8PGO9Izz8fju+uz86v7nAJITKI5gOXvoECoyyI3hNoftFBqC+E7iRIuFKI7DKI9jR4/1QGpsNPIeyJAeSyYUeVLlwpYwWcpMGZPmTI4u193EmPPiTos9M9bEOZRnUaBHJQZFlFTh0o82oxL9qbQpwqfdrNrDinKqVKNUnWqlx7Xs2Hxn96Xtt/Zf24Bv/wfGLTj3YNirdRvmfbg34lekd7f2rRiY7OCNf6sWRrtYbWO2j91GhjtZbmW6l+0mFptZb2e+n/16HQ12M97QhE0LRo2YNGDVhlmTPDxbtknbK2Ez1u2YN2TfkoFTFm6ZOGbjml0rRu6ZOWjnoksr5ww99fTT1VtL3/76+urstcHfFp/be2zyL3GnR6+TvU/3QtW3N7+bfm/7v/EH1z+cf3H/xwGYHHfLCdicgc8hGF13BFKnoHUNYvegdgxWWGCE300YnobjcVgehud5uJ6I84FYn4n3oZifivux2J+L/8EYoIwDWuggjQfimKCOC15oo4Q8QvhjhkFS6OORNw4ZYv+RGzLZoZMfKnmilClSuaKVLWL5opYxcjmjlzUiCSSYOZK5o5k9JikmkWgKueaSbRqp5pxjvjmlnVXieaWeWfK5pZ9dAvqloGHSySahZSJ6pqJp1mkonIy6+eidk+ZZ6Z6X9pnpn5sG2umgnxbq6KiHhpqoqYui2mippEKqqqStUhqrpbNiWqumt3Kaq6e7gtqrqKwG6+qvpxKbqrGrDiusrMvS2qytz+Iara7T8lqtr9cCq+y2zHLrrLfQgiutuNSSa6252KKrbbfsfttuuO+OG2+5855bb7r3ruvuvvDyK6+/9AJsr8D4Eqxvvwj/m3DACw/ccMEPH6zwxAxT7LBixRBjLHHFHF/cccYfb+zxyCCTLHLJKJ+scrHZsqyuy/nCbLDMEdOssc0h42yyzinzvPKxLQP9stAxEz2z0TUjfbPSOTO9s9M9Q/1zskVTfbTVSWO9tNZNn+T112CHLTY3gQAAOw==);
-}
-.ncboTree .doc {
- background: 0 -1px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgC4BOYAAICAgNvt/3V4o+Hw/+n1/+vr67e3t7a2tv///8nk/4ep3NHp/3SAsvj7/+32//v7++/v78HBwf39/djr//P5/8Df/8Ph//7//+Tk5Gdtnvz9/213qIGVw2lwotvn98bGxoyu33J8rpOq0n2Jto+z5fT09X+OvMDA//n5+W96rOTx/4SbyvX6/2t0pf7+/nN+sIqo2fb6/9jl9s7T/2Vqml5hkPf399nh7ZK877rd/83m/3qDsJS/8lWn7ZCjy87n/5G46oeh0v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEIALAAAAAASALgEAAf/gEKCg4SFhoQAh4qLjEKJjZCNj5GUhpOVmI6aiZyZjJeekaChkqSVo6aKqKmWrJCrroOwsZq0qra3uK26hbOxvq7ArMKpxKbGpMihyp7Mmc6Y0Ke8vdSI1rLYgtKU3KLatdjer+Djpdrmn+Xr6Ozi7tbpi/K57+339vnx8NT0h/679PXjxwtgNXz7EA5UWJCgLoPXGD50iAtiNokVKdqyuE0jLY7hEgpsiHGjx18ng6UctrJYy2Mvk8VcNrNZzWc3o+WcVvLjzm4/v/VEOVRlUZZHXSaFuVRmU5pPbUbFOVVnVZ4jJ14FulVo1oxdyYU999XkWHVn5wUVW9Zn2noi/+MubEuUrlG7SPEq1cuUr1O/UAFLFUyVsFXDWOWSRMyVsVfFWh2zhQxWMlnKZi2j1az27b+1l+didssZrujTi0fXVX2XdV7Xe2H3lf2XdmDbg3EX1n2Yd2LUkX03Fv4YeGXik41nRh46tXLSzDdH71z6s+eA00073x78+WrvrcG/Fh+b/GzztdHfVp+b/W73veH/5n5c/nD7xekvx59cP3T+zXXn33cDhlfgeAeWl+B5C6bX4HoPthfhexPGV+F8AmZY34X3cZifhvt52B+I/4kY4IYkEpiigSsi2KKCLzIYo4MzQlijhDdSmKOFO2KI4o8h9tihkB8CWSKRIxqpov+SLDLpopMwQimjlDRSaaOVOGKpo5Y8culjkF4OGWaRYJZ55JhJmrmkmk2y+aSbUcI5pZxV0nmlnVniuaWeXfL55Zl+ihkomYAWuqahbSL6pqJxMjqno3VCeqekeVK6p6V9YvrnoZwm2uminzYa6qOjRlrqpKdWmuqlq2ba6qaexgqqrKLSSqqtpuKKqq6q8sqqr64CC+usxNZa7K3H5prsrsv22uyvzwYb7bDGVoustcpiy6y2znILrbfSgkvtteRmW+6253ab7rfrhtvuuObGi6686tLLrr3u4gvvvPzW2++9/+Yb8L7+FgywwQIjTPDBDCfc8MIORwzxxIJqWvETqxcLm/G0G4vb8bsfgyPyyNQEAgA7);
-}
-.ncboTree .doc-last {
- background: 0 -1px no-repeat #fff url(data:image/gif;base64,R0lGODlhEgAWAOYAANvt/3V4o+Hw/+n1/4CAgOvr67e3t7a2ttHp/8nk/4ep3HSAsu32//v7++/v7/j7/8HBweTk5Njr/8Df/8Ph//39/fP5//7//5S/8pCjy4GVw1Wn7brd/2lwooqo2dvn98bGxn2Jtv7+/n+OvISbynJ8rvT09fn5+c7T//f39+Tx/8DA/5G46mdtnm13qM7n/296rHN+sJK872Vqmtjl9s3m/2t0pfX6/3qDsIeh0oyu3/z9/15hkI+z5fb6/9nh7ZOq0v///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEIALAAAAAASABYAAAcpgEKCg4SFhoQEh4qLjEKJjZCNj5GUhpOVmI6aiZyZnp+goaKjpKWmg4EAOw==);
-}
-.ncboTree .doc a.active {
- padding-left: 4px;
- margin-left: -4px;
-}
-.ncboTree .ajax {
- background: no-repeat 0 0 #ffffff url(data:image/gif;base64,R0lGODlhEAAQAMQAAP///+7u7t3d3bu7u6qqqpmZmYiIiHd3d2ZmZlVVVURERDMzMyIiIhEREQARAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFBwAQACwAAAAAEAAQAAAFdyAkQgGJJOWoQgIjBM8jkKsoPEzgyMGsCjPDw7ADpkQBxRDmSCRetpRA6Rj4kFBkgLC4IlUGhbNQIwXOYYWCXDufzYPDMaoKGBoKb886OjAKdgZAAgQkfCwzAgsDBAUCgl8jAQkHEAVkAoA1AgczlyIDczUDA2UhACH5BAUHABAALAAAAAAPABAAAAVjICSO0IGIATkqIiMKDaGKC8Q49jPMYsE0hQdrlABCGgvT45FKiRKQhWA0mPKGPAgBcTjsspBCAoH4gl+FmXNEUEBVAYHToJAVZK/XWoQQDAgBZioHaX8igigFKYYQVlkCjiMhACH5BAUHABAALAAAAAAQAA8AAAVgICSOUGGQqIiIChMESyo6CdQGdRqUENESI8FAdFgAFwqDISYwPB4CVSMnEhSej+FogNhtHyfRQFmIol5owmEta/fcKITB6y4choMBmk7yGgSAEAJ8JAVDgQFmKUCCZnwhACH5BAUHABAALAAAAAAQABAAAAViICSOYkGe4hFAiSImAwotB+si6Co2QxvjAYHIgBAqDoWCK2Bq6A40iA4yYMggNZKwGFgVCAQZotFwwJIF4QnxaC9IsZNgLtAJDKbraJCGzPVSIgEDXVNXA0JdgH6ChoCKKCEAIfkEBQcAEAAsAAAAABAADgAABUkgJI7QcZComIjPw6bs2kINLB5uW9Bo0gyQx8LkKgVHiccKVdyRlqjFSAApOKOtR810StVeU9RAmLqOxi0qRG3LptikAVQEh4UAACH5BAUHABAALAAAAAAQABAAAAVxICSO0DCQKBQQonGIh5AGB2sYkMHIqYAIN0EDRxoQZIaC6bAoMRSiwMAwCIwCggRkwRMJWKSAomBVCc5lUiGRUBjO6FSBwWggwijBooDCdiFfIlBRAlYBZQ0PWRANaSkED1oQYHgjDA8nM3kPfCmejiEAIfkEBQcAEAAsAAAAABAAEAAABWAgJI6QIJCoOIhFwabsSbiFAotGMEMKgZoB3cBUQIgURpFgmEI0EqjACYXwiYJBGAGBgGIDWsVicbiNEgSsGbKCIMCwA4IBCRgXt8bDACkvYQF6U1OADg8mDlaACQtwJCEAIfkEBQcAEAAsAAABABAADwAABV4gJEKCOAwiMa4Q2qIDwq4wiriBmItCCREHUsIwCgh2q8MiyEKODK7ZbHCoqqSjWGKI1d2kRp+RAWGyHg+DQUEmKliGx4HBKECIMwG61AgssAQPKA19EAxRKz4QCVIhACH5BAUHABAALAAAAAAQABAAAAVjICSOUBCQqHhCgiAOKyqcLVvEZOC2geGiK5NpQBAZCilgAYFMogo/J0lgqEpHgoO2+GIMUL6p4vFojhQNg8rxWLgYBQJCASkwEKLC17hYFJtRIwwBfRAJDk4ObwsidEkrWkkhACH5BAUHABAALAAAAQAQAA8AAAVcICSOUGAGAqmKpjis6vmuqSrUxQyPhDEEtpUOgmgYETCCcrB4OBWwQsGHEhQatVFhB/mNAojFVsQgBhgKpSHRTRxEhGwhoRg0CCXYAkKHHPZCZRAKUERZMAYGMCEAIfkEBQcAEAAsAAABABAADwAABV0gJI4kFJToGAilwKLCST6PUcrB8A70844CXenwILRkIoYyBRk4BQlHo3FIOQmvAEGBMpYSop/IgPBCFpCqIuEsIESHgkgoJxwQAjSzwb1DClwwgQhgAVVMIgVyKCEAIfkECQcAEAAsAAAAABAAEAAABWQgJI5kSQ6NYK7Dw6xr8hCw+ELC85hCIAq3Am0U6JUKjkHJNzIsFAqDqShQHRhY6bKqgvgGCZOSFDhAUiWCYQwJSxGHKqGAE/5EqIHBjOgyRQELCBB7EAQHfySDhGYQdDWGQyUhADs=);
- height: 16px;
- display:none;
-}
-.ncboTree .ajax li {
- display:none;
- margin:0;
- padding:0;
-}
-.ncboTree .trigger {
- display:inline;
- margin-left:-28px;
- width: 28px;
- height: 11px;
- cursor:pointer;
-}
-.ncboTree .text {
- cursor: default;
-}
-.ncboTree .active {
- cursor: default;
- background-color: #B9D5E4;
- font-weight: bold;
- padding-top: 1px;
- padding-right: 4px;
- padding-bottom: 1px;
- padding-left: 0px;
- line-height: 16px;
-}
-.ncboTree a, .ncboTree a:hover {
- text-decoration: none;
- color: black;
- font-size: 11pt;
-}
-.ncboTree a:hover {
- cursor: pointer;
-}
-
-/*
- * jQuery UI CSS Framework 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ncboAutocomplete .ui-front { z-index: 100; }
-.ncboAutocomplete .ui-helper-hidden { display: none; }
-.ncboAutocomplete .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ncboAutocomplete .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ncboAutocomplete .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ncboAutocomplete .ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ncboAutocomplete .ui-helper-clearfix { height:1%; }
-.ncboAutocomplete .ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ncboAutocomplete .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ncboAutocomplete .ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ncboAutocomplete .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ncboAutocomplete .ui-widget-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; }
-
-.jsonSuggest a {
- font-size: .8em;
-}
-
-.jsonSuggest a:hover {
- cursor: pointer;
- font-size: .8em;
-}
-
-/*
- * jQuery UI CSS Framework 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller
- */
-
-
-/* Component containers
-----------------------------------*/
-.ncboAutocomplete .ui-widget { font-family: Arial,sans-serif; font-size: 1em; }
-.ncboAutocomplete .ui-widget .ui-widget { font-size: 1em; }
-.ncboAutocomplete .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; }
-.ncboAutocomplete .ui-widget-content { border: 1px solid #B6B6B6; background: #ffffff; color: #4F4F4F; }
-.ncboAutocomplete .ui-widget-content a { color: #4F4F4F; }
-.ncboAutocomplete .ui-widget-header { border: 1px solid #B6B6B6; color: #4F4F4F; font-weight: bold; }
-.ncboAutocomplete .ui-widget-header {
- background: #ededed 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* W3C */
-}
-.ncboAutocomplete .ui-widget-header a { color: #4F4F4F; }
-
-/* Interaction states
-----------------------------------*/
-.ncboAutocomplete .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #B6B6B6; font-weight: normal; color: #4F4F4F; }
-.ncboAutocomplete .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
- background: #ededed 0 0 repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* IE10+ */
- background: linear-gradient(to bottom, #ededed 0%,#c4c4c4 100%); /* W3C */
- -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
- box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
-}
-.ncboAutocomplete .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4F4F4F; text-decoration: none; }
-.ncboAutocomplete .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #9D9D9D; font-weight: normal; color: #313131; }
-.ncboAutocomplete .ui-state-hover a, .ui-state-hover a:hover { color: #313131; text-decoration: none; }
-.ncboAutocomplete .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
- outline: none;
- color: #1c4257; border: 1px solid #7096ab;
- background: #ededed 0 -50px repeat-x; /* Old browsers */
- background: -moz-linear-gradient(to bottom, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
- background: -webkit-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
- background: -o-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
- background: -ms-linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
- background: linear-gradient(to bottom, #b9e0f5 0%,#92bdd6 100%); /* W3C */
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-.ncboAutocomplete .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #313131; text-decoration: none; }
-.ncboAutocomplete .ui-widget :active { outline: none; }
-
-/* Icons
-----------------------------------*/
-
-/* Misc visuals
-----------------------------------*/
-
-/*
- * jQuery UI Autocomplete 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ncboAutocomplete .ui-autocomplete {
- position: absolute; cursor: default; z-index: 3;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
- -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
- box-shadow: 0 1px 5px rgba(0,0,0,0.3);
-}
-
-/* workarounds */
-* html .ncboAutocomplete .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.7
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ncboAutocomplete .ui-menu {
- list-style:none;
- padding: 2px;
- margin: 0;
- display:block;
- float: left;
-}
-.ncboAutocomplete .ui-menu .ui-menu {
- margin-top: -3px;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item {
- margin:0;
- padding: 0;
- zoom: 1;
- float: left;
- clear: left;
- width: 100%;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item a {
- text-decoration:none;
- display:block;
- padding:.2em .4em;
- line-height:1.5;
- zoom:1;
-}
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-focus,
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-hover,
-.ncboAutocomplete .ui-menu .ui-menu-item a.ui-state-active {
- font-weight: normal;
- margin: -1px;
- background: #5f83b9;
- color: #FFFFFF;
- text-shadow: 0px 1px 1px #234386;
- border-color: #466086;
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
-}
diff --git a/app/components/chips_component.rb b/app/components/chips_component.rb
index 0e9628bec..9a2a4f009 100644
--- a/app/components/chips_component.rb
+++ b/app/components/chips_component.rb
@@ -1,10 +1,10 @@
class ChipsComponent < ViewComponent::Base
renders_one :count
- def initialize(id:nil, name:, label: nil, value:, checked: false)
+ def initialize(id:nil, name:, label: nil, value: nil, checked: false)
@id = id || name
@name = name
- @value = value
+ @value = value || 'true'
@checked = checked
@label = label || @value
end
diff --git a/app/components/display/alert_component.rb b/app/components/display/alert_component.rb
index 6035f36f2..a04ea94d4 100644
--- a/app/components/display/alert_component.rb
+++ b/app/components/display/alert_component.rb
@@ -1,10 +1,11 @@
class Display::AlertComponent < ViewComponent::Base
- def initialize(message: nil, closable: true, type: "info", auto_close_delay: nil, button: nil)
+ def initialize(id: nil, message: nil, closable: true, type: "info", auto_close_delay: nil, button: nil)
@message = message
@closable = closable
@type = type
@auto_close_delay = auto_close_delay
@button = button
+ @id = id
end
def closable?
diff --git a/app/components/display/alert_component/alert_component.html.haml b/app/components/display/alert_component/alert_component.html.haml
index 63a4aa5b3..7dcce0164 100644
--- a/app/components/display/alert_component/alert_component.html.haml
+++ b/app/components/display/alert_component/alert_component.html.haml
@@ -1,4 +1,4 @@
-.alert-container{data: {controller: "alert-component",
+.alert-container{id: @id, data: {controller: "alert-component",
'alert-component-auto-close-value': auto_close?,
'alert-component-auto-close-after-value': @auto_close_delay,
},
diff --git a/app/components/display/search_result_component.rb b/app/components/display/search_result_component.rb
new file mode 100644
index 000000000..026c712ad
--- /dev/null
+++ b/app/components/display/search_result_component.rb
@@ -0,0 +1,53 @@
+class Display::SearchResultComponent < ViewComponent::Base
+ include ModalHelper
+ renders_many :subresults, Display::SearchResultComponent
+ renders_many :reuses, Display::SearchResultComponent
+ def initialize(number: 0,title: nil, ontology_acronym: nil ,uri: nil, definition: nil, link: nil, is_sub_component: false)
+ @title = title
+ @uri = uri
+ @definition = definition
+ @link = link
+ @is_sub_component = is_sub_component
+ @ontology_acronym = ontology_acronym
+ @number = number.to_s
+ end
+
+ def sub_component_class
+ @is_sub_component ? 'sub-component' : ''
+ end
+
+ def sub_ontologies_id
+ string = @number+'_sub_ontologies'
+ end
+
+ def reuses_id
+ string = @number+'_reuses'
+ end
+
+ def details_button
+ link_to_modal(nil, "/ajax/class_details?modal=true&ontology=#{@ontology_acronym}&conceptid=#{@uri}&styled=false", data: { show_modal_title_value: @title, show_modal_size_value: 'modal-xl' }) do
+ content_tag(:div, class: 'button') do
+ concat inline_svg_tag('icons/details.svg')
+ concat content_tag(:div, class: 'text') { t('search.result_component.details') }
+ end
+ end
+ end
+
+ def visualize_button
+ link_to_modal(nil, "/ajax/biomixer/?ontology=#{@ontology_acronym}&conceptid=#{@uri}", data: { show_modal_title_value: @title, show_modal_size_value: 'modal-xl' }) do
+ content_tag(:div, class: 'button') do
+ concat inline_svg_tag('icons/visualize.svg')
+ concat content_tag(:div, class: 'text') { t('search.result_component.visualize') }
+ end
+ end
+ end
+
+ def reveal_ontologies_button(text,id)
+ content_tag(:div, class: 'button icon-right', 'data-action': "click->reveal-component#toggle", 'data-id': id) do
+ concat(content_tag(:div, class: 'text') do
+ text
+ end)
+ concat(inline_svg_tag("icons/arrow-down.svg"))
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/components/display/search_result_component/search_result_component.html.haml b/app/components/display/search_result_component/search_result_component.html.haml
new file mode 100644
index 000000000..613b089d2
--- /dev/null
+++ b/app/components/display/search_result_component/search_result_component.html.haml
@@ -0,0 +1,35 @@
+.search-result-component{class: sub_component_class, 'data-controller': 'reveal-component'}
+ %a.title{href: @link}
+ = @title
+ - if @uri
+ .uri
+ = @uri
+ - if @definition
+ .text
+ = @definition
+ .actions
+ = details_button
+ = visualize_button
+ - if subresults?
+ = reveal_ontologies_button("#{subresults.size} #{t('search.result_component.more_from_ontology')}", sub_ontologies_id)
+ - if reuses?
+ = reveal_ontologies_button("#{t('search.result_component.reuses_in')} #{reuses.size} ontologies", reuses_id)
+ - if subresults?
+ .more-from-ontology.d-none{id: sub_ontologies_id}
+ .vertical-line
+ .search-result-sub-components
+ - subresults.each do |result|
+ .search-result-sub-component
+ = result
+ - if reuses?
+ .more-from-ontology.reuses.d-none{id: reuses_id}
+ .vertical-line
+ .search-result-sub-components
+ .reuses-title
+ = inline_svg_tag 'icons/reuses.svg'
+ %div
+ = t('search.result_component.reuses_in_other_ontologies')
+ - reuses.each do |reuse|
+ .search-result-sub-component
+ = reuse
+
\ No newline at end of file
diff --git a/app/components/layout/reveal_component/reveal_component_controller.js b/app/components/layout/reveal_component/reveal_component_controller.js
index 52badb599..e30df8d76 100644
--- a/app/components/layout/reveal_component/reveal_component_controller.js
+++ b/app/components/layout/reveal_component/reveal_component_controller.js
@@ -1,24 +1,35 @@
-import Reveal from 'stimulus-reveal-controller'
+import { Controller } from "@hotwired/stimulus"
-export default class extends Reveal {
+export default class extends Controller{
static values = {
- condition: String
+ condition: String,
+ hiddenClass : {type: String, default: "d-none"}
}
- connect() {
- super.connect()
- }
+ static targets = ["hideButton", "showButton", 'item' ]
toggle(event) {
if (!this.conditionValue) {
- super.toggle()
+ this.#toggle(event)
} else if (this.#shown() && !this.#conditionChecked(event)) {
- super.toggle()
+ this.#toggle(event)
} else if (!this.#shown() && this.#conditionChecked(event)) {
- super.toggle()
+ this.#toggle(event)
}
}
+ show(event){
+ this.#getItems(event).classList.remove(this.hiddenClassValue)
+ this.hideButtonTarget.classList.remove(this.hiddenClassValue)
+ this.showButtonTarget.classList.add(this.hiddenClassValue)
+ }
+ hide(event){
+ this.#getItems(event).classList.add(this.hiddenClassValue)
+ this.hideButtonTarget.classList.add(this.hiddenClassValue)
+ this.showButtonTarget.classList.remove(this.hiddenClassValue)
+ }
+
+
#conditionChecked(event) {
return this.conditionValue === event.target.value
}
@@ -27,4 +38,24 @@ export default class extends Reveal {
return !this.itemTargets[0].classList.contains(this.class);
}
+ #toggle(event) {
+ this.#getItems(event).forEach((s) => {
+ s.classList.toggle(this.hiddenClassValue);
+ });
+ }
+
+ #ItemById(event){
+ let button = event.target.closest("[data-id]");
+ return document.getElementById(button.dataset.id);
+ }
+ #getItems(event){
+ let items
+ if(this.hasItemTarget){
+ items = this.itemTarget
+ } else {
+ items = [this.#ItemById(event)]
+ }
+ return items
+ }
+
}
\ No newline at end of file
diff --git a/app/components/table_component.rb b/app/components/table_component.rb
index 9670464db..e3ce96e58 100644
--- a/app/components/table_component.rb
+++ b/app/components/table_component.rb
@@ -5,12 +5,13 @@ class TableComponent < ViewComponent::Base
renders_one :header, TableRowComponent
renders_many :rows, TableRowComponent
- def initialize(id: '', stripped: true, borderless: false, layout_fixed: false )
+ def initialize(id: '', stripped: true, borderless: false, layout_fixed: false, custom_class: '' )
super
@id = id
@stripped = stripped
@borderless = borderless
@layout_fixed = layout_fixed
+ @custom_class = custom_class
end
def stripped_class
diff --git a/app/components/table_component/table_component.html.haml b/app/components/table_component/table_component.html.haml
index ed479fb66..2c0ca196d 100644
--- a/app/components/table_component/table_component.html.haml
+++ b/app/components/table_component/table_component.html.haml
@@ -1,4 +1,4 @@
-%table.table-content{id: @id, class: stripped_class + ' ' + borderless_class + ' ' + layout_fixed_class}
+%table.table-content{id: @id, class: stripped_class + ' ' + borderless_class + ' ' + layout_fixed_class + @custom_class}
%thead
= header
%tbody{id: "#{@id}_table_body"}
diff --git a/app/components/tabs_container_component/tabs_container_component.html.haml b/app/components/tabs_container_component/tabs_container_component.html.haml
index b47c875f3..a8c955a3c 100644
--- a/app/components/tabs_container_component/tabs_container_component.html.haml
+++ b/app/components/tabs_container_component/tabs_container_component.html.haml
@@ -1,5 +1,5 @@
%div{data: {controller:'tabs-container'}, class: container_class, id: @id}
- %div
+ %div{class: !pinned_right? && 'justify-content-center'}
.tab-items.nav
- items.each do |item|
%div{data: tabs_container_data(item), class: item.active_class + ' nav-item'}
diff --git a/app/components/tree_infinite_scroll_component/tree_infinite_scroll_component.html.haml b/app/components/tree_infinite_scroll_component/tree_infinite_scroll_component.html.haml
index cbaaba03a..386fa14dd 100644
--- a/app/components/tree_infinite_scroll_component/tree_infinite_scroll_component.html.haml
+++ b/app/components/tree_infinite_scroll_component/tree_infinite_scroll_component.html.haml
@@ -4,10 +4,8 @@
current_page: @current_page, next_page: @next_page) do |c|
%div
- %ul.simpleTree{data:{controller: 'simple-tree','simple-tree': { 'auto-click-value': auto_click? }, action: 'clicked->history#updateURL'}}
- %li.root
- %ul
- = content
+ = render TreeViewComponent.new(id: nil, auto_click: auto_click?) do
+ = content
- c.error do
%div.text-wrap
diff --git a/app/components/tree_link_component.rb b/app/components/tree_link_component.rb
new file mode 100644
index 000000000..81f510fb5
--- /dev/null
+++ b/app/components/tree_link_component.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+class TreeLinkComponent < ViewComponent::Base
+ include MultiLanguagesHelper
+ def initialize(child:, href:, children_href: , selected: false , data: {}, muted: false, target_frame: nil)
+ @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 rescue @child.id
+ if label.nil?
+ @pref_label_html = child.id.split('/').last
+ 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'}
+
+ @data.merge!(data) do |_, old, new|
+ "#{old} #{new}"
+ end
+ 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
+ rand(36 ** 8).to_s(36)
+ end
+
+ # TDOD check where used
+ def child_id
+ @child.id.to_s.split('/').last
+ end
+
+ def open?
+ @child.expanded? ? 'open' : ''
+ end
+
+ def border_left
+ !@child.hasChildren ? 'pl-3 tree-border-left' : ''
+ end
+
+ def li_id
+ @child.id.eql?('bp_fake_root') ? 'bp_fake_root' : short_uuid
+ end
+
+ def self.tree_close_icon
+ "
".html_safe
+ end
+
+ def open_children_link
+ return unless @child.hasChildren
+ if @child.expanded?
+ self.class.tree_close_icon
+ else
+ content_tag('turbo_frame', id: "#{child_id}_open_link") do
+ link_to @children_link,
+ data: { turbo: true, turbo_frame: "#{child_id + '_childs'}" } do
+ content_tag(:i, nil, class: "fas fa-chevron-right")
+ end
+ end
+ end
+
+ end
+
+end
diff --git a/app/components/tree_link_component/tree_link_component.html.haml b/app/components/tree_link_component/tree_link_component.html.haml
new file mode 100644
index 000000000..2bf3815b0
--- /dev/null
+++ b/app/components/tree_link_component/tree_link_component.html.haml
@@ -0,0 +1,10 @@
+%li{id:li_id , class: open?}
+ = open_children_link
+ %a{id: @child.id, data: @data, title: @tooltip,
+ href: @href, class: "tree-link #{@muted_style} #{@active_style} #{border_left} #{open?}"}
+ = @pref_label_html
+
+ - if @child.hasChildren && !@child.expanded?
+ = render TurboFrameComponent.new(id: "#{child_id}_childs")
+ - elsif @child.expanded?
+ = content
\ No newline at end of file
diff --git a/app/components/tree_view_component.rb b/app/components/tree_view_component.rb
new file mode 100644
index 000000000..4570bf8d1
--- /dev/null
+++ b/app/components/tree_view_component.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+class TreeViewComponent < ViewComponent::Base
+ include Turbo::FramesHelper
+
+
+ renders_many :children, TreeLinkComponent
+
+ def initialize(id:, auto_click: false, sub_tree: false, **html_options)
+ @id = id
+ @auto_click = auto_click
+ @html_options = html_options
+ @sub_tree = sub_tree
+ end
+
+ private
+
+ def sub_tree?
+ @sub_tree
+ end
+
+ def tree_container(&block)
+ if sub_tree?
+ content_tag(:ul, capture(&block), class: 'pl-2 tree-border-left')
+ else
+ content_tag(:div, class: 'tree_wrapper hide-if-loading') do
+ content_tag(:ul, capture(&block), class: 'simpleTree root', data: { controller: 'simple-tree',
+ 'simple-tree-auto-click-value': "#{auto_click?}",
+ action: 'clicked->history#updateURL' })
+ end
+ end
+ end
+
+ def auto_click?
+ @auto_click.to_s
+ end
+
+ # TDOD check where used
+ def child_id(child)
+ child.id.to_s.split('/').last
+ end
+
+end
+
\ No newline at end of file
diff --git a/app/components/tree_view_component/tree_view_component.html.haml b/app/components/tree_view_component/tree_view_component.html.haml
new file mode 100644
index 000000000..c8b47d1a4
--- /dev/null
+++ b/app/components/tree_view_component/tree_view_component.html.haml
@@ -0,0 +1,9 @@
+%turbo-frame{id: "#{@id}", **@html_options}
+ = tree_container do
+ - children.each do |child|
+ = child
+ = content
+
+
+
+
diff --git a/app/components/widget_block_component.rb b/app/components/widget_block_component.rb
new file mode 100644
index 000000000..473cc64fa
--- /dev/null
+++ b/app/components/widget_block_component.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class WidgetBlockComponent < ViewComponent::Base
+
+ renders_one :help_text
+ renders_one :widget
+
+ def initialize(id: , title: , description:)
+ @id = id
+ @title = title
+ @description = description
+ end
+end
diff --git a/app/components/widget_block_component/widget_block_component.html.haml b/app/components/widget_block_component/widget_block_component.html.haml
new file mode 100644
index 000000000..ac4927adc
--- /dev/null
+++ b/app/components/widget_block_component/widget_block_component.html.haml
@@ -0,0 +1,26 @@
+%div.d-flex{data: {turbo: false}}
+ %div.w-50.mr-3
+ %div
+ %div.card-body
+ %h5.card-title
+ = @title
+ %p.card-text
+ = @description
+
+ %div.w-100.d-flex.justify-content-center
+ %div.card.py-3.px-2{style: "width: 600px"}
+ = render TabsContainerComponent.new(id: @id) do |t|
+ - t.item(title: 'Widget', selected: true)
+ - t.item(title: '') do
+ %span.mx-1
+ See code
+ = inline_svg_tag('json.svg')
+
+ - t.item_content do
+ %div.py-3.d-flex.justify-content-center
+ = widget
+ - t.item_content do
+ = help_text
+
+%hr.divider.w-100
+
diff --git a/app/controllers/admin/categories_controller.rb b/app/controllers/admin/categories_controller.rb
index 8d52212bb..fb4773bca 100644
--- a/app/controllers/admin/categories_controller.rb
+++ b/app/controllers/admin/categories_controller.rb
@@ -1,5 +1,6 @@
class Admin::CategoriesController < ApplicationController
- include SubmissionUpdater
+ include SubmissionUpdater, TurboHelper
+
layout :determine_layout
before_action :unescape_id, only: [:edit, :show, :update, :destroy]
@@ -9,8 +10,7 @@ class Admin::CategoriesController < ApplicationController
ATTRIBUTE_TO_INCLUDE = 'name,acronym,created,description,parentCategory,ontologies'
def index
- response = _categories
- render :json => response
+ @categories = _categories
end
def new
@@ -22,7 +22,8 @@ def new
end
def edit
- @category = LinkedData::Client::Models::Category.find_by_acronym(params[:id], include:'name,acronym,created,description,parentCategory,ontologies' ).first
+ @category = _category
+ @acronyms = @category.ontologies.map { |url| url.match(/\/([^\/]+)$/)[1] }
@ontologies_category = LinkedData::Client::Models::Ontology.all(include: 'acronym').map {|o|[o.acronym, o.id] }
respond_to do |format|
format.html { render "edit", :layout => false }
@@ -30,7 +31,7 @@ def edit
end
def create
- response = { errors: '', success: '' }
+ response = { errors: nil, success: '' }
start = Time.now
begin
category = LinkedData::Client::Models::Category.new(values: category_params)
@@ -43,35 +44,55 @@ def create
rescue Exception => e
response[:errors] = "Problem creating the category - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :created : :internal_server_error)
+
+ if response[:errors]
+ render_turbo_stream alert_error(id: 'category') { response[:errors] }
+ else
+ success_message = 'New Category added successfully'
+ streams = [alert_success(id: 'category') { success_message }]
+
+ streams << prepend('admin_categories_table_body', partial: 'admin/categories/category', locals: { category: category_saved })
+
+ render_turbo_stream(*streams)
+ end
end
def update
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
- category = LinkedData::Client::Models::Category.find_by_acronym(params[:id], include: ATTRIBUTE_TO_INCLUDE ).first
+ category = _category
add_ontologies_to_object(category_params[:ontologies],category) if (category_params[:ontologies].present? && category_params[:ontologies].size > 0 && category_params[:ontologies].first != '')
- delete_ontologies_from_object(category_params[:ontologies],category.ontologies,category)
+ delete_ontologies_from_object(category_params[:ontologies], category.ontologies,category)
category.update_from_params(category_params)
- category_update = category.update
- if response_error?(category_update)
- response[:errors] = response_errors(category_update)
+ category.ontologies = Array(category_params[:ontologies])
+ category_updated = category.update
+ if response_error?(category_updated)
+ response[:errors] = response_errors(category_updated)
else
response[:success] = "category successfully updated in #{Time.now - start}s"
end
rescue Exception => e
response[:errors] = "Problem updating the category - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+
+ if response[:errors]
+ render_turbo_stream(alert_error(id: 'category') { response[:errors] })
+ else
+ streams = [alert_success(id: 'category') { response[:success] },
+ replace(category.id.split('/').last, partial: 'admin/categories/category', locals: { category: category })
+ ]
+ render_turbo_stream(*streams)
+ end
+
end
def destroy
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
- category = LinkedData::Client::Models::Category.find_by_acronym(params[:id]).first
+ category = _category
error_response = category.delete
if response_error?(error_response)
@@ -82,9 +103,19 @@ def destroy
rescue Exception => e
response[:errors] = "Problem deleting the category - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
+ end
end
-
private
def unescape_id
@@ -96,16 +127,10 @@ def category_params
end
def _categories
- response = { categories: Hash.new, errors: '', success: '' }
- start = Time.now
- begin
- response[:categories] = JSON.parse(LinkedData::Client::HTTP.get(CATEGORIES_URL, { include: ATTRIBUTE_TO_INCLUDE }, raw: true))
+ LinkedData::Client::HTTP.get(CATEGORIES_URL, { include: ATTRIBUTE_TO_INCLUDE })
+ end
- response[:success] = "categories successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Categories - retrieved #{response[:categories].length} groups in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving categories - #{e.message}"
- end
- response
+ def _category(id = params[:id])
+ LinkedData::Client::HTTP.get(CATEGORIES_URL+ "/#{id.split('/').last}", { include: ATTRIBUTE_TO_INCLUDE })
end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 3df27d2e0..d340c3b4a 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -1,15 +1,16 @@
class Admin::GroupsController < ApplicationController
- include SubmissionUpdater
+ include SubmissionUpdater, TurboHelper, AdminHelper
layout :determine_layout
before_action :unescape_id, only: [:edit, :show, :update, :destroy]
before_action :authorize_admin
GROUPS_URL = "#{LinkedData::Client.settings.rest_url}/groups"
+ GROUPS_SYNCHRONIZE_URL = "#{LinkedData::Client.settings.rest_url}/slices/synchronize_groups"
+
def index
- response = _groups
- render :json => response
+ @groups = _groups
end
def new
@@ -30,7 +31,7 @@ def edit
end
def create
- response = { errors: '', success: '' }
+ response = { errors: nil, success: '' }
start = Time.now
begin
group = LinkedData::Client::Models::Group.new(values: group_params)
@@ -43,18 +44,29 @@ def create
rescue Exception => e
response[:errors] = "Problem creating the group - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :created : :internal_server_error)
+
+ if response[:errors]
+ render_turbo_stream alert_error(id: 'group') { response[:errors] }
+ else
+ success_message = 'New Group added successfully'
+ streams = [alert_success(id: 'group') { success_message }]
+
+ streams << prepend('admin_groups_table_body', partial: 'admin/groups/group', locals: { group: group_saved })
+
+ render_turbo_stream(*streams)
+ end
end
def update
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
group = LinkedData::Client::Models::Group.find_by_acronym(params[:id]).first
add_ontologies_to_object(group_params[:ontologies],group) if (group_params[:ontologies].present? && group_params[:ontologies].size > 0 && group_params[:ontologies].first != '')
delete_ontologies_from_object(group_params[:ontologies],group.ontologies,group)
group.update_from_params(group_params)
+ group.ontologies = Array(group_params[:ontologies])
group_updated = group.update
if response_error?(group_updated)
response[:errors] = response_errors(group_updated)
@@ -64,11 +76,21 @@ def update
rescue Exception => e
response[:errors] = "Problem updating the group - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+
+ if response[:errors]
+ render_turbo_stream(alert_error(id: 'group') { response[:errors] })
+ else
+
+ streams = [alert_success(id: 'group') { response[:success] },
+ replace(group.id.split('/').last, partial: 'admin/groups/group', locals: { group: group })
+ ]
+ render_turbo_stream(*streams)
+ end
+
end
def destroy
- response = { errors: '', success: ''}
+ response = { errors: nil, success: ''}
start = Time.now
begin
group = LinkedData::Client::Models::Group.find_by_acronym(params[:id]).first
@@ -82,9 +104,51 @@ def destroy
rescue Exception => e
response[:errors] = "Problem deleting the group - #{e.message}"
end
- render json: response, status: (response[:errors] == '' ? :ok : :internal_server_error)
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
+ end
+ end
+
+ def synchronize_groups
+ response = {}
+
+ begin
+ response_raw = LinkedData::Client::HTTP.get(GROUPS_SYNCHRONIZE_URL, params, raw: true)
+
+ response_json = JSON.parse(response_raw, symbolize_names: true)
+
+ if !response_json.is_a?(Array) && response_json[:errors]
+ _process_errors(response_json[:errors], response, true)
+ else
+ response[:success] = "Synchronization of groups started successfully"
+ end
+ rescue JSON::ParserError => e
+ response[:errors] = "Error parsing JSON response - #{e.class}: #{e.message}"
+ rescue Exception => e
+ response[:errors] = "Problem synchronizing groups - #{e.class}: #{e.message}"
+ end
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
end
+
private
def unescape_id
@@ -96,16 +160,6 @@ def group_params
end
def _groups
- response = { groups: Hash.new, errors: '', success: '' }
- start = Time.now
- begin
- response[:groups] = JSON.parse(LinkedData::Client::HTTP.get(GROUPS_URL, { include: 'all' }, raw: true))
-
- response[:success] = "groups successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Groups - retrieved #{response[:groups].length} groups in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving groups - #{e.message}"
- end
- response
+ LinkedData::Client::HTTP.get(GROUPS_URL, { include: 'all' })
end
end
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index f182bcd34..4269e1142 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -1,5 +1,5 @@
class AdminController < ApplicationController
- include TurboHelper
+ include TurboHelper, HomeHelper, SparqlHelper
layout :determine_layout
before_action :cache_setup
@@ -10,8 +10,26 @@ class AdminController < ApplicationController
PARSE_LOG_URL = lambda { |acronym| "#{ONTOLOGY_URL.call(acronym)}/log" }
REPORT_NEVER_GENERATED = "NEVER GENERATED"
+ def sparql_endpoint
+ graph = params["named-graph-uri"]
+ if !session[:user]&.admin? && !graph.blank?
+ acronym = graph.split('/')[-3]
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(acronym).first
+ render(inline: 'Query not permitted') && return if @ontology.nil? || @ontology.errors
+ end
+
+ response = helpers.ontology_sparql_query(params[:query], graph)
+
+ render inline: response
+ end
+
def index
@users = LinkedData::Client::Models::User.all
+ @ontology_visits = ontology_visits_data
+ @users_visits = user_visits_data
+ @page_visits = page_visits_data
+ @ontologies_problems_count = _ontologies_report[:ontologies]&.select{|a,v| v[:problem]}&.size || 0
+
if session[:user].nil? || !session[:user].admin?
redirect_to :controller => 'login', :action => 'index', :redirect => '/admin'
else
@@ -19,44 +37,49 @@ def index
end
end
- def update_info
- response = {update_info: Hash.new, errors: '', success: '', notices: ''}
- json = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_info", params, raw: true)
- begin
- update_info = JSON.parse(json)
+ def update_check_enabled
+ enabled = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_check_enabled", {}, raw: false)
- if update_info["error"]
- response[:errors] = update_info["error"]
- else
- response[:update_info] = update_info
- response[:notices] = update_info["notes"] if update_info["notes"]
- response[:success] = "Update info successfully retrieved"
+ if enabled
+ response = {update_info: Hash.new, errors: nil, success: '', notices: ''}
+ json = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_info", params, raw: true)
+
+ begin
+ update_info = JSON.parse(json)
+
+ if update_info["error"]
+ response[:errors] = update_info["error"]
+ else
+ response[:update_info] = update_info
+ response[:notices] = update_info["notes"] if update_info["notes"]
+ response[:success] = "Update info successfully retrieved"
+ end
+ rescue Exception => e
+ response[:errors] = "Problem retrieving update info - #{e.message}"
end
- rescue Exception => e
- response[:errors] = "Problem retrieving update info - #{e.message}"
- end
- render :json => response
- end
- def update_check_enabled
- enabled = LinkedData::Client::HTTP.get("#{ADMIN_URL}update_check_enabled", {}, raw: false)
- render :json => enabled
- end
+ if response[:errors]
+ render_turbo_stream alert(id: 'update_check_frame', type: 'danger') { response[:errors] }
+ else
+ output = []
- def submissions
- @submissions = nil
- @acronym = params["acronym"]
- @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params["acronym"]).first
- begin
- submissions = @ontology.explore.submissions
- @submissions = submissions.sort {|a,b| b.submissionId <=> a.submissionId }
- rescue
- @submissions = []
+ output << response[:update_info]["notes"] if response[:update_info]["update_available"]
+
+ output << "Current version: #{response[:update_info]['current_version']}"
+ output << "Appliance ID: #{response[:update_info]['appliance_id']}"
+
+
+ render_turbo_stream *output.map{|message| alert(id: 'update_check_frame', type: 'info') {message} }
+
+
+ end
+ else
+ render_turbo_stream alert(id: 'update_check_frame', type: 'info') { 'not enabled' }
end
- render :partial => "layouts/ontology_report_submissions"
end
+
def parse_log
@acronym = params["acronym"]
@parse_log = LinkedData::Client::HTTP.get(PARSE_LOG_URL.call(params["acronym"]), {}, raw: false)
@@ -75,7 +98,7 @@ def parse_log
end
def clearcache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
if @cache.respond_to?(:flush_all)
begin
@@ -87,11 +110,21 @@ def clearcache
else
response[:errors] = "The UI cache does not respond to the 'flush_all' command"
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+
end
def resetcache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
if @cache.respond_to?(:reset)
begin
@@ -103,11 +136,20 @@ def resetcache
else
response[:errors] = "The UI cache does not respond to the 'reset' command"
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
end
def clear_goo_cache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
begin
response_raw = LinkedData::Client::HTTP.post("#{ADMIN_URL}clear_goo_cache", params, raw: true)
@@ -115,11 +157,21 @@ def clear_goo_cache
rescue Exception => e
response[:errors] = "Problem flushing the Goo cache - #{e.class}: #{e.message}"
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
+
end
def clear_http_cache
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
begin
response_raw = LinkedData::Client::HTTP.post("#{ADMIN_URL}clear_http_cache", params, raw: true)
@@ -127,7 +179,16 @@ def clear_http_cache
rescue Exception => e
response[:errors] = "Problem flushing the HTTP cache - #{e.class}: #{e.message}"
end
- render :json => response
+
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render_turbo_stream alert(type: 'success') { response[:success] }
+ end
+ end
+ end
end
def ontologies_report
@@ -161,6 +222,7 @@ def refresh_ontologies_report
render :json => response
end
+
def process_ontologies
_process_ontologies('enqued for processing', 'processing', :_process_ontology)
end
@@ -210,11 +272,6 @@ def delete_submission
end
- def users
- response = _users
- render :json => response
- end
-
private
@@ -301,18 +358,85 @@ def _process_ontologies(success_keyword, error_keyword, process_proc)
render :json => response
end
- def _users
- response = {users: Hash.new , errors: '', success: ''}
- start = Time.now
+
+ def user_visits_data
begin
- response[:users] = JSON.parse(LinkedData::Client::HTTP.get(USERS_URL, {include: 'all'}, raw: true))
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/users", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
- response[:success] = "users successfully retrieved in #{Time.now - start}s"
- LOG.add :debug, "Users - retrieved #{response[:users].length} users in #{Time.now - start}s"
- rescue Exception => e
- response[:errors] = "Problem retrieving users - #{e.message}"
+ return visits_data if analytics.empty?
+
+ analytics.each do |year, year_data|
+ year_data.each do |month, value|
+ visits_data[:visits] << value
+ visits_data[:labels] << DateTime.parse("#{year}/#{month}").strftime("%b %Y")
+ end
end
- response
+ visits_data
+ end
+
+ def ontology_visits_data
+ begin
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/ontologies", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
+ @new_ontologies_count = []
+ @ontologies_count = 0
+
+ return visits_data if analytics.empty?
+
+ aggregated_data = {}
+ analytics.each do |acronym, years_data|
+ current_year_count = 0
+ previous_year_count = 0
+ years_data.each do |year, months_data|
+ previous_year_count += current_year_count
+ current_year_count = 0
+ aggregated_data[year] ||= {}
+ months_data.each do |month, value|
+ if aggregated_data[year][month]
+ aggregated_data[year][month] += value
+ else
+ aggregated_data[year][month] = value
+ end
+ current_year_count += value
+ end
+ end
+ @ontologies_count += 1
+ if previous_year_count.zero? && current_year_count.positive?
+ @new_ontologies_count << [acronym]
+ end
+ end
+
+
+
+ aggregated_data.each do |year, year_data|
+ year_data.each do |month, value|
+ visits_data[:visits] << value
+ visits_data[:labels] << DateTime.parse("#{year}/#{month}").strftime("%b %Y")
+ end
+ end
+ visits_data
end
+ def page_visits_data
+ begin
+ analytics = JSON.parse(LinkedData::Client::HTTP.get("#{rest_url}/data/analytics/page_visits", {}, raw: true))
+ rescue
+ analytics = {}
+ end
+ visits_data = { visits: [], labels: [] }
+
+ return visits_data if analytics.empty?
+ analytics.each do |path, count|
+ visits_data[:labels] << path
+ visits_data[:visits] << count
+ end
+ visits_data
+ end
end
diff --git a/app/controllers/agents_controller.rb b/app/controllers/agents_controller.rb
index d7b6268e6..50c82c7af 100644
--- a/app/controllers/agents_controller.rb
+++ b/app/controllers/agents_controller.rb
@@ -56,7 +56,7 @@ def create
success_message = 'New Agent added successfully'
streams = [alert_success(id: alert_id) { success_message }]
- streams << prepend('agents_table_content', partial: 'agents/show_line', locals: { agent: new_agent })
+ streams << prepend('admin_agents_table_body', partial: 'agents/agent', locals: { agent: new_agent })
streams << replace_agent_form(new_agent, agent_id: nil, frame_id: params[:id],
parent_id: parent_id, name_prefix: name_prefix,
deletable: deletable
@@ -101,7 +101,7 @@ def update
table_line_id = agent_table_line_id(agent_id(agent))
agent = LinkedData::Client::Models::Agent.find(agent.id.split('/').last)
streams = [alert_success(id: alert_id) { success_message },
- replace(table_line_id, partial: 'agents/show_line', locals: { agent: agent })
+ replace(table_line_id, partial: 'agents/agent', locals: { agent: agent })
]
streams << replace_agent_form(agent, agent_id: agent_id(agent.id), name_prefix: params[:name_prefix] , parent_id: parent_id, deletable: deletable) if params[:parent_id]
@@ -137,7 +137,7 @@ def update_agent_usages
table_line_id = agent_table_line_id(agent_id(agent))
agent.usages = new_usages
streams = [alert_success(id: alert_id) { success_message },
- replace(table_line_id, partial: 'agents/show_line', locals: { agent: agent })
+ replace(table_line_id, partial: 'agents/agent', locals: { agent: agent })
]
render_turbo_stream(*streams)
@@ -171,7 +171,7 @@ def destroy
]
else
- render alert(type: 'danger') { error }
+ render_turbo_stream alert(type: 'danger') { error }
end
end
format.html { render json: { success: success_text, error: error } }
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 02ae47002..e50ff9a09 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -161,12 +161,6 @@ def to_param(name) # Paramaterizes URLs without encoding
end
end
- def undo_param(name) #Undo Paramaterization
- unless name.nil?
- name.to_s.gsub('_'," ")
- end
- end
-
def bp_config_json
# For config settings, see
# config/bioportal_config.rb
@@ -192,22 +186,6 @@ def bp_config_json
config.to_json
end
- def remote_file_exists?(url)
- begin
- url = URI.parse(url)
-
- if url.kind_of?(URI::FTP)
- check = check_ftp_file(url)
- else
- check = check_http_file(url)
- end
-
- rescue
- return false
- end
-
- check
- end
def rest_url
# Split the URL into protocol and path parts
@@ -312,15 +290,6 @@ def redirect_to_home # Redirect to Home Page
redirect_to "/"
end
- def redirect_to_history # Redirects to the correct tab through the history system
- if session[:redirect].nil?
- redirect_to_home
- else
- tab = find_tab(session[:redirect][:ontology])
- session[:redirect]=nil
- redirect_to uri_url(:ontology=>tab.ontology_id,:conceptid=>tab.concept)
- end
- end
def redirect_new_api(class_view = false)
# Hack to make ontologyid and conceptid work in addition to id and ontology params
@@ -377,24 +346,6 @@ def authorize_and_redirect
end
end
- # Verifies that a user owns an object
- def authorize_owner(id=nil)
- if id.nil?
- id = params[:id].to_i
- end
-
- id.map! {|i| i.to_i} if id.kind_of?(Array)
-
- if session[:user].nil?
- redirect_to_home
- else
- if id.kind_of?(Array)
- redirect_to_home if !session[:user].admin? && !id.include?(session[:user].id.to_i)
- else
- redirect_to_home if !session[:user].admin? && !session[:user].id.to_i.eql?(id)
- end
- end
- end
def authorize_admin
admin = session[:user] && session[:user].admin?
@@ -409,41 +360,7 @@ def ontology_restricted?(acronym)
restrict_downloads = $NOT_DOWNLOADABLE
restrict_downloads.include? acronym
end
- # updates the 'history' tab with the current selected concept
- def update_tab(ontology, concept)
- array = session[:ontologies] || []
- found = false
- for item in array
- if item.ontology_id.eql?(ontology.id)
- item.concept=concept
- found=true
- end
- end
-
- unless found
- array << History.new(ontology.id, ontology.name, ontology.acronym, concept)
- end
-
- session[:ontologies]=array
- end
-
- # Removes a 'history' tab
- def remove_tab(ontology_id)
- array = session[:ontologies]
- array.delete(find_tab(ontology_id))
- session[:ontologies]=array
- end
- # Returns a specific 'history' tab
- def find_tab(ontology_id)
- array = session[:ontologies]
- for item in array
- if item.ontology_id.eql?(ontology_id)
- return item
- end
- end
- return nil
- end
def check_delete_mapping_permission(mappings)
# ensure mappings is an Array of mappings (some calls may provide only a single mapping instance)
@@ -467,13 +384,13 @@ def using_captcha?
def get_class(params)
lang = request_lang
-
+
if @ontology.flat?
ignore_concept_param = params[:conceptid].nil? ||
- params[:conceptid].empty? ||
- params[:conceptid].eql?("root") ||
- params[:conceptid].eql?("bp_fake_root")
+ params[:conceptid].empty? ||
+ params[:conceptid].eql?("root") ||
+ params[:conceptid].eql?("bp_fake_root")
if ignore_concept_param
# Don't display any classes in the tree
@concept = LinkedData::Client::Models::Class.new
@@ -495,24 +412,25 @@ def get_class(params)
# not ignoring 'bp_fake_root' here
include = 'prefLabel,hasChildren,obsolete'
ignore_concept_param = params[:conceptid].nil? ||
- params[:conceptid].empty? ||
- params[:conceptid].eql?("root")
+ params[:conceptid].empty? ||
+ params[:conceptid].eql?("root")
if ignore_concept_param
# get the top level nodes for the root
# TODO_REV: Support views? Replace old view call: @ontology.top_level_classes(view)
- @roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes])
+ @roots = @ontology.explore.roots(concept_schemes: params[:concept_schemes])
if @roots.nil? || @roots.empty?
LOG.add :debug, "Missing @roots for #{@ontology.acronym}"
classes = @ontology.explore.classes.collection
@concept = classes.first.explore.self(full: true) if classes.first
return
end
-
+
@root = LinkedData::Client::Models::Class.new(read_only: true)
@root.children = @roots.sort{|x,y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase}
# get the initial concept to display
- root_child = @root.children.first
+ root_child = @root.children&.first
+ not_found("Missing roots #{@roots.id}") if root_child.nil?
@concept = root_child.explore.self(full: true, lang: lang)
# Some ontologies have "too many children" at their root. These will not process and are handled here.
@@ -573,17 +491,7 @@ def get_simplified_ontologies_hash()
return simple_ontologies
end
- def get_ontology_details(ont_uri)
- # Note the simplify_ontology_model will cache individual ontology data.
- begin
- ont_model = LinkedData::Client::Models::Ontology.find(ont_uri)
- ont = simplify_ontology_model(ont_model)
- rescue Exception => e
- LOG.add :error, e.message
- return nil
- end
- return ont
- end
+
def simplify_classes(classes)
# Simplify the classes batch service data for the UI
diff --git a/app/controllers/concepts_controller.rb b/app/controllers/concepts_controller.rb
index 79adb6e40..bcb1f3453 100644
--- a/app/controllers/concepts_controller.rb
+++ b/app/controllers/concepts_controller.rb
@@ -3,6 +3,8 @@
class ConceptsController < ApplicationController
include MappingsHelper
include ConceptsHelper
+ include TurboHelper
+
layout 'ontology'
def show_concept
@@ -23,7 +25,8 @@ def show_concept
@instances_concept_id = @concept.id
concept_not_found(params[:id]) if @concept.nil?
- gather_details
+ @notes = @concept.explore.notes
+
render :partial => 'show'
end
@@ -40,22 +43,22 @@ def show
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
@ob_instructions = helpers.ontolobridge_instructions_template(@ontology)
- if request.xhr?
- display = params[:callback].eql?('load') ? {full: true} : {display: "prefLabel"}
- @concept = @ontology.explore.single_class(display, params[:id])
- concept_not_found(params[:id]) if @concept.nil?
- @schemes = params[:concept_schemes]&.split(',')
- show_ajax_request # process an ajax call
- else
- # Get the latest 'ready' submission, or fallback to any latest submission
- # TODO: change the logic here if the fallback will crash the visualization
- @submission = get_ontology_submission_ready(@ontology) # application_controller
-
- @concept = @ontology.explore.single_class({full: true}, params[:id])
- concept_not_found(params[:id]) if @concept.nil?
- @schemes = params[:concept_schemes].split(',')
- show_ajax_request # process a full call
- end
+ # Get the latest 'ready' submission, or fallback to any latest submission
+ # TODO: change the logic here if the fallback will crash the visualization
+ @submission = get_ontology_submission_ready(@ontology) # application_controller
+
+ @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
+ helpers.concepts_tree_component(@concept, @concept, @ontology.acronym, Array(@schemes), request_lang, sub_tree: true)
+ end
+ ]
end
def show_label
@@ -92,11 +95,16 @@ def show_tree
return
end
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
- if @ontology.nil?
+ if @ontology.nil? || @ontology.errors
ontology_not_found(params[:ontology])
- else
+ else
get_class(params) #application_controller
- render partial: 'ontologies/treeview', locals: { autoCLick: params[:auto_click] || true }
+
+ not_found("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)
end
end
@@ -159,7 +167,8 @@ def details
@concept = @ontology.explore.single_class({full: true}, CGI.unescape(params[:conceptid]))
concept_not_found(CGI.unescape(params[:conceptid])) if @concept.nil?
-
+ @container_id = params[:modal] ? 'application_modal_content' : 'concept_details'
+
if params[:styled].eql?("true")
render :partial => "details", :layout => "partial"
else
@@ -178,35 +187,11 @@ def biomixer
render partial: "biomixer", layout: false
end
-# PRIVATE -----------------------------------------
-private
- def show_ajax_request
- case params[:callback]
- when 'children' # Children is called only for drawing the tree
- @children = @concept.explore.children(pagesize: 750, concept_schemes: Array(@schemes).join(','), language: request_lang, display: 'prefLabel,obsolete,hasChildren').collection || []
- @children.sort! { |x, y| (x.prefLabel || "").downcase <=> (y.prefLabel || "").downcase } unless @children.empty?
- render :partial => 'child_nodes'
- end
- end
+ private
- # gathers the full set of data for a node
- def show_uri_request
- gather_details
- build_tree
- end
- def gather_details
- @notes = @concept.explore.notes
- update_tab(@ontology, @concept.id) #updates the 'history' tab with the current node
- end
- def build_tree
- # find path to root
- rootNode = @concept.explore.tree(include: "prefLabel,hasChildren,obsolete,subClassOf")
- @root = LinkedData::Client::Models::Class.new(read_only: true)
- @root.children = rootNode unless rootNode.nil?
- end
def filter_concept_with_no_date(concepts)
concepts.filter { |c| !concept_date(c).nil?}
diff --git a/app/controllers/concerns/search_aggregator.rb b/app/controllers/concerns/search_aggregator.rb
new file mode 100644
index 000000000..443a07fdd
--- /dev/null
+++ b/app/controllers/concerns/search_aggregator.rb
@@ -0,0 +1,230 @@
+module SearchAggregator
+ extend ActiveSupport::Concern
+ BLACKLIST_FIX_STR = [
+ "https://",
+ "http://",
+ "bioportal.bioontology.org/ontologies/",
+ "purl.bioontology.org/ontology/",
+ "purl.obolibrary.org/obo/",
+ "swrl.stanford.edu/ontologies/",
+ "mesh.owl" # Avoids RH-MESH subordinate to MESH
+ ]
+
+ BLACKLIST_REGEX = [
+ /abnormalities/i,
+ /biological/i,
+ /biology/i,
+ /bioontology/i,
+ /clinical/i,
+ /extension/i,
+ /\.gov/i,
+ /ontology/i,
+ /ontologies/i,
+ /semanticweb/i
+ ]
+
+ def aggregate_results(query, results)
+ ontologies = aggregate_by_ontology(results)
+ grouped_results = add_subordinate_ontologies(query, ontologies)
+ all_ontologies = LinkedData::Client::Models::Ontology.all(include: 'acronym,name', include_views: true, display_links: false, display_context: false)
+
+ grouped_results.map do |group|
+ format_search_result(group, all_ontologies)
+ end
+ end
+
+ def format_search_result(result, ontologies)
+ same_ont = result[:same_ont]
+ same_cls = result[:sub_ont]
+ result = same_ont.shift
+ ontology = result.links['ontology'].split('/').last
+ {
+ root: search_result_elem(result, ontology, ontology_name_acronym(ontologies, ontology)),
+ descendants: same_ont.map { |x| search_result_elem(x, ontology, '') },
+ reuses: same_cls.map do |x|
+ format_search_result(x, ontologies)
+ end
+ }
+ end
+
+ private
+
+ def search_result_elem(class_object, ontology_acronym, title)
+ label = concept_label(class_object.prefLabel)
+ {
+ uri: class_object.id.to_s,
+ title: title.empty? ? label : "#{label} - #{title}",
+ ontology_acronym: ontology_acronym,
+ link: "/ontologies/#{ontology_acronym}?p=classes&conceptid=#{class_object.id}",
+ definition: Array(class_object.definition).join(' ')
+ }
+ end
+
+ def concept_label(pref_labels_list, obsolete = false, max_length = 60)
+ # select closest to query
+ selected = pref_labels_list.select do |pref_lab|
+ pref_lab.include?(@search_query) || @search_query.include?(pref_lab)
+ end.first
+
+ selected ||= (pref_labels_list&.first || '')
+
+ selected = selected[0..max_length] if selected.size > max_length
+ selected = "
#{selected}".html_safe if obsolete
+ selected
+ end
+
+ def ontology_name_acronym(ontologies, selected_acronym)
+ ontology = ontologies.select { |x| x.acronym.eql?(selected_acronym.split('/').last) }.first
+ binding.pry if ontology.nil?
+ "#{ontology.name} (#{ontology.acronym})"
+ end
+
+ def aggregate_by_ontology(results)
+ ontologies = {}
+
+ results.each do |res|
+ ont = res.links['ontology']
+ unless ontologies[ont]
+ ontologies[ont] = {
+ # classes with same URI
+ same_cls: [],
+ # other classes from the same ontology
+ same_ont: [],
+ # subordinate ontologies
+ sub_ont: []
+ }
+ end
+ ontologies[ont][:same_ont] << res
+ end
+ ontologies.values
+ end
+
+ def add_subordinate_ontologies(query, ontologies)
+ # get for each concept his main ontology parent
+ concepts_ontology_owner = extract_concepts_owners(ontologies, query)
+
+ # aggregate the subordinate results below the owner ontology results
+ subordinate_ontologies = []
+ ontologies.each_with_index do |ont, i|
+ cls_id = ont[:same_ont].first["@id"]
+
+ if concepts_ontology_owner.has_key?(cls_id)
+ # get the ontology that owns this class (if any)
+ ont_owner = concepts_ontology_owner[cls_id]
+ if ont_owner[:index].eql?(i)
+ # the current ontology is the owner of this primary result
+ subordinate_ontologies.push(ont)
+ else
+ # There is an owner, so put this ont result set into the sub_ont array of the owner
+ real_owner = ontologies[ont_owner[:index]]
+ real_owner[:sub_ont].push(ont)
+ end
+ else
+ # There is no ontology that owns this primary class result, just
+ # display this at the top level (it's not a subordinate)
+ subordinate_ontologies.push(ont)
+ end
+ end
+ subordinate_ontologies
+ end
+
+ def extract_concepts_owners(ontologies, query)
+ cls_ont_owner_tracker = {}
+ ontologies.each do |ont|
+ ont[:sub_ont] = [] # array for any subordinate ontology results regrouping the concept reuses
+
+ cls_id = ont[:same_ont].first["@id"]
+ next if cls_ont_owner_tracker.has_key?(cls_id)
+
+ # find the best match for the ontology owner (must iterate over all acronyms)
+ ont_owner = ontology_owner_of_class(cls_id, ontologies, query)
+
+ # This primary class result is owned by an ontology
+ cls_ont_owner_tracker[cls_id] = ont_owner if ont_owner[:index]
+ end
+ cls_ont_owner_tracker
+ end
+
+ def extract_back_list_words(acronyms, query)
+ blacklist_words = []
+ query.split(/\s+/).each_with_index do |search_word, i|
+ # Convert blacklist_search_words_arr to regex constructs so they are removed
+ # with case-insensitive matches in blacklist_cls_id_components
+ blacklist_words.push(Regexp.new(search_word, Regexp::IGNORECASE))
+
+ # Check for any substring matches against ontology acronyms, where the
+ # acronyms are assumed to be upper case strings.
+ # Note: We cannot use the ont_acronyms array .index method because it doesn't search for substring matches.
+ search_token = search_word
+ match = false
+
+ acronyms.each do |acronym|
+ match = acronym.include?(search_token)
+ break if match
+ end
+
+ # Remove this blacklisted search token because it matches or partially matches an ontology acronym.
+ blacklist_words.delete_at(i) if match
+ end
+ blacklist_words
+ end
+
+ def ontology_owner_of_class(cls_id, ontologies, query)
+ acronyms = ontologies.map { |ont| ont[:same_ont].first.links['ontology'].split('/').last }
+
+ # Remove any items in blacklistSearchWordsArr that match ontology acronyms.
+ # TODO make sure this is really useful
+ blacklist_words = extract_back_list_words(acronyms, query)
+
+ ont_owner = {
+ acronym: "",
+ index: nil,
+ weight: 0
+ }
+
+ acronyms.each_with_index do |acronym, i|
+ if ontology_own_class?(cls_id, acronym, blacklist_words)
+ weight = acronym.size * (cls_id.upcase.rindex(acronym) + 1)
+ if weight > ont_owner[:weight]
+ ont_owner = {
+ acronym: acronym,
+ index: i,
+ weight: weight
+ }
+ # Cannot break here, in case another acronym has greater weight.
+ end
+ end
+ end
+
+ ont_owner
+ end
+
+ def ontology_own_class?(cls_id, acronym, blacklist_words)
+ cls_id = blacklist_cls_id_components(cls_id.dup, blacklist_words)
+
+ cls_id.upcase.include?(acronym) rescue binding.pry
+ end
+
+ def blacklist_cls_id_components(cls_id, blacklist_words)
+
+ stripped_id = cls_id
+
+ # Remove fixed strings first
+ BLACKLIST_FIX_STR.each do |fixed_str|
+ stripped_id.gsub!(fixed_str, "")
+ end
+
+ # Cleanup with regex replacements
+ BLACKLIST_REGEX.each do |regex|
+ stripped_id.gsub!(regex, "")
+ end
+
+ # Remove search keywords (see perform_search and aggregate_results_with_subordinate_ontologies)
+ blacklist_words.each do |search_word_regex|
+ stripped_id.gsub!(search_word_regex, "")
+ end
+
+ stripped_id
+ end
+end
+
diff --git a/app/controllers/history_controller.rb b/app/controllers/history_controller.rb
deleted file mode 100644
index 687839df5..000000000
--- a/app/controllers/history_controller.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class HistoryController < ApplicationController
-
- def remove # removes a 'history' tab
- remove_tab(undo_param(params[:ontology]))
- render :text =>"success"
- end
-
- def update # updates the 'history' tab to point to the new node
- ontology = DataAccess.getOntology(params[:ontology])
- update_tab(ontology,params[:concept])
- render :text =>"success"
- end
-
-
-end
diff --git a/app/controllers/instances_controller.rb b/app/controllers/instances_controller.rb
index 5d346ef3b..8b170f5e2 100644
--- a/app/controllers/instances_controller.rb
+++ b/app/controllers/instances_controller.rb
@@ -2,18 +2,20 @@ class InstancesController < ApplicationController
include InstancesHelper
def index_by_ontology
get_ontology(params)
- custom_render get_instances_by_ontology_json(@ontology, get_query_parameters)
+ instances = get_instances_by_ontology_json(@ontology, get_query_parameters)
+ custom_render(instances, @ontology.acronym)
end
def index_by_class
get_ontology(params)
get_class(params)
- custom_render get_instances_by_class_json(@concept, get_query_parameters)
+ custom_render(get_instances_by_class_json(@concept, get_query_parameters), @ontology.acronym)
end
def show
- @instance = get_instance_details_json(params[:ontology_id], params[:instance_id], {include: 'all'})
- render partial: 'instances/instance_details'
+ @instance = get_instance_details_json(params[:ontology_id], params[:id] || params[:instance_id], {include: 'all'})
+
+ render partial: 'instances/instance_details', layout: nil
end
private
@@ -23,8 +25,8 @@ def get_ontology(params)
ontology_not_found(params[:ontology]) if @ontology.nil?
end
# json render + adding next and prev pages links
- def custom_render(instances)
- instances[:collection].map! { |i| add_labels_to_print(i, @ontology.acronym)}
+ def custom_render(instances, ontology_acronym)
+ instances[:collection].map! { |i| add_labels_to_print(i, ontology_acronym)}
if (instances.respond_to? :links) && (!instances.respond_to? :errors)
instances.links = {
nextPage: get_page_link(instances.nextPage),
diff --git a/app/controllers/mappings_controller.rb b/app/controllers/mappings_controller.rb
index b8baeda3a..269fafebe 100644
--- a/app/controllers/mappings_controller.rb
+++ b/app/controllers/mappings_controller.rb
@@ -117,7 +117,7 @@ def show_mappings
end
else
ontology_acronym = @ontology.acronym
- @ontology_name = @ontology.name
+ @ontology_name = ontology_acronym
end
if @target_ontology.nil?
if params[:target] == EXTERNAL_MAPPINGS_GRAPH
@@ -129,12 +129,13 @@ def show_mappings
end
else
target_acronym = @target_ontology.acronym
- @target_ontology_name = @target_ontology.name
+ @target_ontology_name = target_acronym
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
@delete_mapping_permission = check_delete_mapping_permission(@mappings)
@@ -248,7 +249,7 @@ def destroy
]
else
- render alert(type: 'danger') { error }
+ render_turbo_stream alert(type: 'danger') { error }
end
end
format.html { render json: { success: success_text, error: error } }
diff --git a/app/controllers/ontologies_controller.rb b/app/controllers/ontologies_controller.rb
index 31170cffd..f6469e280 100644
--- a/app/controllers/ontologies_controller.rb
+++ b/app/controllers/ontologies_controller.rb
@@ -10,6 +10,7 @@ class OntologiesController < ApplicationController
include MappingStatistics
include OntologyUpdater
include TurboHelper
+ include SparqlHelper
include SubmissionFilter
require 'multi_json'
@@ -22,7 +23,7 @@ class OntologiesController < ApplicationController
before_action :authorize_and_redirect, :only => [:edit, :update, :create, :new]
before_action :submission_metadata, only: [:show]
- KNOWN_PAGES = Set.new(["terms", "classes", "mappings", "notes", "widgets", "summary", "properties", "instances", "schemes", "collections"])
+ KNOWN_PAGES = Set.new(["terms", "classes", "mappings", "notes", "widgets", "summary", "properties", "instances", "schemes", "collections", "sparql"])
EXTERNAL_MAPPINGS_GRAPH = "http://data.bioontology.org/metadata/ExternalMappings"
INTERPORTAL_MAPPINGS_GRAPH = "http://data.bioontology.org/metadata/InterportalMappings"
@@ -208,6 +209,14 @@ def collections
end
end
+
+ def sparql
+ if request.xhr?
+ render partial: 'ontologies/sections/sparql', layout: false
+ else
+ render partial: 'ontologies/sections/sparql', layout: 'ontology_viewer'
+ end
+ end
# GET /ontologies/ACRONYM
# GET /ontologies/1.xml
def show
@@ -240,7 +249,7 @@ def show
# Note: find_by_acronym includes ontology views
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
- ontology_not_found(params[:ontology]) if @ontology.nil?
+ ontology_not_found(params[:ontology]) if @ontology.nil? || @ontology.errors
# Handle the case where an ontology is converted to summary only.
# See: https://github.com/ncbo/bioportal_web_ui/issues/133.
@@ -288,6 +297,8 @@ def show
self.schemes
when 'collections'
self.collections
+ when 'sparql'
+ self.sparql
else
self.summary
end
@@ -387,7 +398,6 @@ def widgets
end
end
-
def show_additional_metadata
@metadata = submission_metadata
@ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:id]).first
diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb
index 0363649c9..7784c5eb7 100644
--- a/app/controllers/properties_controller.rb
+++ b/app/controllers/properties_controller.rb
@@ -1,8 +1,56 @@
class PropertiesController < ApplicationController
- def show
- @property = LinkedData::Client::HTTP.get("/ontologies/#{params[:acronym]}/properties/#{helpers.encode_param(params[:id])}")
+ include TurboHelper
- @acronym = params[:acronym]
- render partial: 'show'
+ def show
+ @property = get_property(params[:id])
+ @acronym = params[:acronym]
+ render partial: 'show'
+ end
+
+ def show_tree
+ @ontology = LinkedData::Client::Models::Ontology.find_by_acronym(params[:ontology]).first
+ ontology_not_found(params[:ontology]) if @ontology.nil?
+ @root = OpenStruct.new({children: property_roots(params[:ontology])})
+ not_found(@root.children.errors.join) if @root.children.respond_to?(:errors)
+
+ if params[:propertyid]
+ @property = get_property(params[:propertyid])
+ else
+ @property ||= @root.children.first
end
+
+ render inline: helpers.property_tree_component(@root, @property,
+ @ontology.acronym, request_lang,
+ id: 'properties_tree_view', auto_click: true)
+ end
+
+
+ def show_children
+ acronym = params[:ontology]
+ id = params[:propertyid]
+ @property = get_property(id, acronym)
+ @property.children = property_children(id, acronym)
+
+ render turbo_stream: [
+ replace(helpers.child_id(@property) + '_open_link') { TreeLinkComponent.tree_close_icon },
+ replace(helpers.child_id(@property) + '_childs') do
+ helpers.property_tree_component(@property, @property, acronym, request_lang, sub_tree: true)
+ end
+ ]
+ end
+
+
+ private
+ def get_property(id, acronym = params[:acronym])
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/#{helpers.encode_param(id)}")
+ end
+
+ def property_roots(acronym = params[:acronym])
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/roots")
+ end
+
+ def property_children(id, acronym = params[:acronym])
+ LinkedData::Client::HTTP.get("/ontologies/#{acronym}/properties/#{helpers.encode_param(id)}/children?display=all")
+ end
+
end
diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb
deleted file mode 100644
index c36ef5b7b..000000000
--- a/app/controllers/reviews_controller.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-class ReviewsController < ApplicationController
-
- layout 'ontology_viewer'
-
- RATING_TYPES = [
- :usabilityRating,
- :coverageRating,
- :qualityRating,
- :formalityRating,
- :correctnessRating,
- :documentationRating
- ].freeze
-
- def new
- @rating_types = RATING_TYPES
- @ontology = LinkedData::Client::Models::Ontology.find(params[:ontology])
- @review = LinkedData::Client::Models::Review.new(values: {ontologyReviewed: @ontology.id, creator: session[:user].id})
-
- if request.xhr?
- render layout: false
- end
- end
-
- # GET /reviews/1/edit
- def edit
- @review = Review.find(params[:id])
- @rating_types = RatingType.all
-
- if request.xhr?
- render layout: false
- end
- end
-
- def create
- @review = LinkedData::Client::Models::Review.new(values: params[:review])
- @ontology = LinkedData::Client::Models::Ontology.find(@review.ontologyReviewed)
- @review_saved = @review.save
- if response_error?(@review_saved)
- @errors = response_errors(@review_saved)
- render :action => "new"
- else
- respond_to do |format|
- format.html do
- flash[:notice] = 'Review was successfully created'
- redirect_to "/ontologies/#{@ontology.acronym}?p=summary"
- end
- format.js do
- render json: {}
- end
- end
- end
- end
-
- # PUT /reviews/1
- # PUT /reviews/1.xml
- def update
- @review = Review.find(params[:id])
- ratings = Hash[*(@review.ratings.map{|rate| [rate.id.to_i, rate] }.flatten)]
- #puts ratings.inspect
- for rating_key in params.keys
- if rating_key.include?("star")
- #puts rating_key.split("_")[1].to_i
- ratings[rating_key.split("_")[1].to_i].value=params[rating_key].to_i
- ratings[rating_key.split("_")[1].to_i].save
- end
- end
- if @review.update_attributes(params[:review])
- @review.reload
- if request.xhr?
- render :action=>'show', :layout=>false
- else
- redirect_to reviews(:ontology=>review.ontology_id)
- end
- else
- render :action => "edit"
- end
- end
-
- # DELETE /reviews/1
- # DELETE /reviews/1.xml
- def destroy
- @review = Review.find(params[:id])
- @review.destroy
-
- respond_to do |format|
- format.html { redirect_to(reviews_url) }
- format.xml { head :ok }
- end
- end
-end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 6b35a2b26..8ba41c4a7 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,14 +1,25 @@
require 'uri'
class SearchController < ApplicationController
-
+ include SearchAggregator
skip_before_action :verify_authenticity_token
layout :determine_layout
def index
- @search_query = params[:query].nil? ? params[:q] : params[:query]
- @search_query ||= ""
+ @search_query = params[:query] || params[:q] || ''
+ params[:query] = nil
+ @advanced_options_open = false
+ @search_results = []
+
+ return if @search_query.empty?
+
+ params[:pagesize] = "150"
+ params[:ontologies] = params[:ontologies_list]&.join(",")
+ results = LinkedData::Client::Models::Class.search(@search_query, params).collection
+
+ @advanced_options_open = !search_params_empty?
+ @search_results = aggregate_results(@search_query, results)
end
def json_search
@@ -18,13 +29,18 @@ def json_search
end
check_params_query(params)
check_params_ontologies(params) # Filter on ontology_id
+ if params["id"]&.eql?('All')
+ params.delete("id")
+ params.delete("ontologies")
+ end
search_page = LinkedData::Client::Models::Class.search(params[:q], params)
@results = search_page.collection
response = ""
obsolete_response = ""
separator = (params[:separator].nil?) ? "~!~" : params[:separator]
- for result in @results
+
+ for result in Array(@results)
# TODO_REV: Format the response with type information, target information
# record_type = format_record_type(result[:recordType], result[:obsolete])
record_type = ""
@@ -32,20 +48,21 @@ def json_search
target_value = result.prefLabel.select{|x| x.include?( params[:q].delete('*'))}.first || result.prefLabel.first
case params[:target]
- when "name"
- target_value = result.prefLabel
- when "shortid"
- target_value = result.id
- when "uri"
- target_value = result.id
+ when "name"
+ target_value = result.prefLabel
+ when "shortid"
+ target_value = result.id
+ when "uri"
+ target_value = result.id
end
+ acronym = result.links["ontology"].split('/').last
json = []
json << "#{target_value}"
json << " [obsolete]" if result.obsolete? # used by JS in ontologies/visualize to markup obsolete classes
json << "|#{result.id}"
json << "|#{record_type}"
- json << "|#{result.explore.ontology.acronym}"
+ json << "|#{acronym}"
json << "|#{result.id}" # Duplicated because we used to have shortId and fullId
json << "|#{target_value}"
# This is nasty, but hard to workaround unless we rewrite everything (form_autocomplete, jump_to, crossdomain_autocomplete)
@@ -55,8 +72,8 @@ def json_search
if params[:id] && params[:id].split(",").length == 1
json << "|#{CGI.escape((result.definition || []).join(". "))}#{separator}"
else
- json << "|#{result.explore.ontology.name}"
- json << "|#{result.explore.ontology.acronym}"
+ json << "|#{acronym}"
+ json << "|#{acronym}"
json << "|#{CGI.escape((result.definition || []).join(". "))}#{separator}"
end
@@ -104,21 +121,17 @@ def check_params_ontologies(params)
end
end
- def format_record_type(record_type, obsolete = false)
- case record_type
- when "apreferredname"
- record_text = "Preferred Name"
- when "bconceptid"
- record_text = "Class ID"
- when "csynonym"
- record_text = "Synonym"
- when "dproperty"
- record_text = "Property"
- else
- record_text = ""
- end
- record_text = "Obsolete Class" if obsolete
- record_text
+ def search_params
+ [
+ :ontologies, :categories,
+ :also_search_properties, :also_search_obsolete, :also_search_views,
+ :require_exact_match, :require_definition
+ ]
+ end
+
+ def search_params_empty?
+ (params[:lang].nil? || params[:lang].eql?('all')) &&
+ search_params.all?{|key| params[key].nil? || params[key].empty?}
end
end
diff --git a/app/controllers/statistics_controller.rb b/app/controllers/statistics_controller.rb
new file mode 100644
index 000000000..ac3828f02
--- /dev/null
+++ b/app/controllers/statistics_controller.rb
@@ -0,0 +1,14 @@
+class StatisticsController < ApplicationController
+ include StatisticsHelper, ComponentsHelper
+
+ layout :determine_layout
+
+ def index
+ projects = LinkedData::Client::Models::Project.all({include: 'created'})
+ users = LinkedData::Client::Models::User.all({include: 'created'})
+ year_month_count, @year_month_visits = ontologies_by_year_month
+ @merged_data = merge_time_evolution_data([group_by_year_month(users),
+ group_by_year_month(projects),
+ year_month_count])
+ end
+end
diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb
index 3e3fc0972..92380888c 100644
--- a/app/controllers/submissions_controller.rb
+++ b/app/controllers/submissions_controller.rb
@@ -17,7 +17,7 @@ def index
.sort {|a,b| b.submissionId.to_i <=> a.submissionId.to_i } || []
LOG.add :error, "No submissions for ontology: #{@ontology.id}" if @submissions.empty?
-
+ render :index, layout: nil
end
# When getting "Add submission" form to display
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index dc6c75bdb..53b70ea16 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -5,6 +5,21 @@ class UsersController < ApplicationController
before_action :authorize_admin, only: [:index,:subscribe, :un_subscribe]
layout :determine_layout
+ include TurboHelper
+
+
+ def index
+
+ onts = LinkedData::Client::Models::Ontology.all(include: 'administeredBy')
+ projects = LinkedData::Client::Models::Project.all(include: 'creator')
+
+ @users = LinkedData::Client::Models::User.all(include: 'all')
+ @users.each do |user|
+ user.ontologies = onts.select {|o| o.administeredBy.include? user.id }
+ user.project = projects.select {|p| p.creator.include? user.id }
+ end
+
+ end
# GET /users/1
# GET /users/1.xml
@@ -112,7 +127,7 @@ def update
# DELETE /users/1
def destroy
- response = {errors: '', success: ''}
+ response = {errors: nil, success: ''}
@user = LinkedData::Client::Models::User.find(params[:id])
@user = LinkedData::Client::Models::User.find_by_username(params[:id]).first if @user.nil?
if(session[:user].admin?)
@@ -123,7 +138,18 @@ def destroy
response[:errors] << 'Not permitted '
end
- render json: response
+ respond_to do |format|
+ format.turbo_stream do
+ if response[:errors]
+ render_turbo_stream alert(type: 'danger') { response[:errors].to_s }
+ else
+ render turbo_stream: [
+ alert(type: 'success') { response[:success] },
+ turbo_stream.remove(params[:id])
+ ]
+ end
+ end
+ end
end
def custom_ontologies
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
index 7553a567d..17f172ff7 100644
--- a/app/helpers/admin_helper.rb
+++ b/app/helpers/admin_helper.rb
@@ -3,4 +3,23 @@ def selected_admin_section?(section_title)
current_section = params[:section] || 'site'
current_section.eql?(section_title)
end
+
+
+ def new_ontologies_created_title
+ content_tag(:div,
+ "The following ontologies: #{@new_ontologies_count.join(', ')} were created in this year",
+ style: 'width: 400px; max-height: 300px')
+ end
+
+ def visits_evolution
+ return 0 if @users_visits[:visits].empty?
+
+ @users_visits[:visits].last - @users_visits[:visits][-2]
+ end
+
+ def action_button(name, link, method: :post, class_style: 'btn btn-link mb-3')
+ button_to name, link, method: method, class: class_style,
+ form: {data: { turbo: true, turbo_confirm: "Are you sure you want to #{name}?", turbo_frame: '_top'}}
+
+ end
end
diff --git a/app/helpers/agent_helper.rb b/app/helpers/agent_helper.rb
index f583c2cf5..802dc1087 100644
--- a/app/helpers/agent_helper.rb
+++ b/app/helpers/agent_helper.rb
@@ -165,31 +165,45 @@ def agent_tooltip(agent)
email = agent.email
type = agent.agentType
identifiers = display_identifiers(agent.identifiers, link: false)
- #binding.pry
+ identifiers = orcid_number(identifiers)
if agent.affiliations && agent.affiliations != []
- affiliations = "affiliations: "
+ affiliations = ""
agent.affiliations.each do |affiliation|
- affiliations = affiliations + affiliation.name + ". "
+ affiliations = affiliations + affiliation.acronym + " "
end
end
person_icon = inline_svg_tag 'icons/person.svg' , class: 'agent-type-icon'
organization_icon = inline_svg_tag 'icons/organization.svg', class: 'agent-type-icon'
+ ror_icon = inline_svg_tag 'icons/ror.svg', class: 'agent-dependency-icon ror'
+ orcid_icon = inline_svg_tag 'icons/orcid.svg', class: 'agent-dependency-icon'
agent_icon = type == "organization" ? organization_icon : person_icon
- tooltip_html = generate_agent_tooltip(agent_icon, name, email, identifiers, affiliations)
+ identifiers_icon = type == "organization" ? ror_icon : orcid_icon
+ tooltip_html = generate_agent_tooltip(agent_icon, name, email, identifiers, affiliations, identifiers_icon)
return tooltip_html
end
- def generate_agent_tooltip(agent_icon, name, email = nil, identifiers = nil, affiliations = nil)
+ def generate_agent_tooltip(agent_icon, name, email = nil, identifiers = nil, affiliations = nil, identifiers_icon = nil)
content_tag(:div, class: 'agent-container') do
content_tag(:div, agent_icon, class: 'agent-circle') +
content_tag(:div) do
content_tag(:div, name, class: 'agent-name') +
content_tag(:div, email || '', class: 'agent-dependency') +
- content_tag(:div, identifiers || '', class: 'agent-dependency') +
- content_tag(:div, affiliations || '', class: 'agent-dependency')
+ unless identifiers.to_s.empty?
+ content_tag(:div, class: 'agent-dependency') do
+ identifiers_icon +
+ identifiers || ''
+ end
+ end +
+ unless affiliations.to_s.empty?
+ content_tag(:div, class: 'agent-dependency') do
+ inline_svg_tag('icons/organization.svg', class: 'agent-dependency-icon') +
+ affiliations || ''
+ end
+ end
end
end
end
+
def agent_chip_component(agent)
person_icon = inline_svg_tag 'icons/person.svg' , class: 'agent-type-icon'
@@ -217,6 +231,10 @@ def render_chip_component(title,agent_icon,name)
end
end
+ def orcid_number(orcid)
+ return orcid.split("/").last
+ end
+
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index c29cd7c35..507078a0e 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -25,11 +25,8 @@ module ApplicationHelper
def ontologies_analytics
- LinkedData::Client::Analytics.all.to_h.map do |key, ontology_analytics|
- next if key.eql?(:links) || key.eql?(:context)
-
- [key.to_s, ontology_analytics.to_h.values.map { |x| x&.values }.flatten.compact.sum]
- end.compact.to_h
+ data = LinkedData::Client::Analytics.last_month.onts
+ data.map{|x| [x[:ont].to_s, x[:views]]}.to_h
end
def get_apikey
@@ -63,6 +60,7 @@ def isOwner?(id)
end
end
end
+
def encode_param(string)
@@ -105,146 +103,9 @@ def current_user_admin?
session[:user] && session[:user].admin?
end
- def draw_note_tree(notes,key)
- output = ""
- draw_note_tree_leaves(notes,0,output,key)
- return output
- end
-
- def draw_note_tree_leaves(notes,level,output,key)
- for note in notes
- name="Anonymous"
- unless note.user.nil?
- name=note.user.username
- end
- headertext=""
- notetext=""
- if note.note_type.eql?(5)
- headertext<< "