iqvoc 4.15.0 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/Gemfile +10 -7
- data/app/aides/skos_exporter.rb +71 -43
- data/app/assets/builds/.keep +0 -0
- data/app/assets/images/.gitkeep +0 -0
- data/app/assets/stylesheets/_fontawesome.scss +4 -0
- data/app/assets/stylesheets/_framework.scss +1 -1
- data/app/assets/stylesheets/application.scss +1 -0
- data/app/assets/stylesheets/iqvoc/_bootstrap_overrides.scss +30 -1
- data/app/assets/stylesheets/iqvoc/components/_components.scss +2 -2
- data/app/assets/stylesheets/iqvoc/components/_onebox.scss +1 -1
- data/app/assets/stylesheets/iqvoc/components/_simplete.scss +5 -0
- data/app/assets/stylesheets/iqvoc/components/_treeview.scss +4 -4
- data/app/assets/stylesheets/iqvoc/hacks/_hacks.scss +1 -12
- data/app/assets/stylesheets/iqvoc/settings/_fonts.scss +33 -33
- data/app/assets/stylesheets/iqvoc/settings/_mixins.scss +0 -14
- data/app/controllers/concerns/controller_extensions.rb +11 -0
- data/app/controllers/exports_controller.rb +2 -4
- data/app/controllers/remote_labels_controller.rb +14 -2
- data/app/controllers/search_results_controller.rb +22 -11
- data/app/exceptions/service_unavailable_error.rb +8 -0
- data/app/helpers/application_helper.rb +2 -2
- data/app/helpers/link_helper.rb +4 -0
- data/app/helpers/navigation_helper.rb +1 -1
- data/app/helpers/rdf_helper.rb +9 -2
- data/app/javascript/application.js +4 -0
- data/app/{assets/javascripts → javascript}/iqvoc/concept_mapping_manager.js +2 -2
- data/app/{assets/javascripts → javascript}/iqvoc/entityselect.js +4 -6
- data/app/{assets/javascripts → javascript}/iqvoc/federated_concept_mapper.js +3 -4
- data/app/{assets/javascripts → javascript/iqvoc}/framework.js +0 -1
- data/app/javascript/iqvoc/globals.js +13 -0
- data/app/javascript/iqvoc/hover_menues.js +25 -0
- data/app/{assets/javascripts → javascript}/iqvoc/iqvoc.js +6 -2
- data/app/{assets/javascripts → javascript}/iqvoc/treeview.js +11 -10
- data/app/javascript/manifest.js +12 -0
- data/app/jobs/export_job.rb +1 -1
- data/app/jobs/reverse_match_job.rb +3 -3
- data/app/models/concept/base.rb +4 -3
- data/app/models/concerns/versioning.rb +6 -0
- data/app/models/dataset/adaptors/iqvoc/label_adaptor.rb +4 -2
- data/app/models/dataset/iqvoc_dataset.rb +6 -1
- data/app/models/export.rb +8 -1
- data/app/models/note/base.rb +6 -0
- data/app/models/note/skos/base.rb +1 -1
- data/app/models/note/skos/change_note.rb +1 -1
- data/app/views/collections/alphabetical/_search_result.html.erb +1 -1
- data/app/views/concepts/_form.html.erb +2 -4
- data/app/views/concepts/alphabetical/_search_result.html.erb +1 -1
- data/app/views/concepts/glance.html.erb +3 -6
- data/app/views/dashboard/_table.html.erb +2 -2
- data/app/views/dashboard/glance.html.erb +3 -6
- data/app/views/exports/index.html.erb +14 -5
- data/app/views/frontpage/index.html.erb +3 -3
- data/app/views/hierarchy/show.iqrdf +1 -1
- data/app/views/imports/index.html.erb +3 -4
- data/app/views/instance_configuration/index.html.erb +1 -1
- data/app/views/layouts/_controls.html.erb +2 -2
- data/app/views/layouts/_navigation.html.erb +1 -1
- data/app/views/layouts/_sections.html.erb +1 -1
- data/app/views/layouts/_user_navigation.html.erb +2 -2
- data/app/views/layouts/application.html.erb +2 -4
- data/app/views/pages/components.html.erb +5 -5
- data/app/views/partials/labeling/skos/_edit_base.html.erb +1 -3
- data/app/views/partials/labeling/skos/_search_result.html.erb +1 -1
- data/app/views/partials/match/_edit_base.html.erb +1 -1
- data/app/views/partials/notation/_edit_base.html.erb +1 -1
- data/app/views/partials/note/_edit_base.html.erb +1 -1
- data/app/views/partials/note/_search_result.html.erb +1 -1
- data/app/views/partials/note/skos/change_note/_search_result.html.erb +1 -1
- data/app/views/partials/note/skos/definition/_search_result.html.erb +1 -1
- data/app/views/search_results/_form.html.erb +4 -4
- data/app/views/search_results/sections/_change_note.html.erb +5 -11
- data/app/views/search_results/sections/_collection.html.erb +1 -1
- data/app/views/search_results/sections/_datasets.html.erb +1 -1
- data/app/views/search_results/sections/_klass.html.erb +1 -1
- data/app/views/search_results/sections/_languages.html.erb +4 -3
- data/app/views/search_results/sections/_mode.html.erb +1 -1
- data/app/views/search_results/sections/_options.html.erb +1 -1
- data/app/views/search_results/sections/_terms.html.erb +4 -3
- data/app/views/search_results/sections/_type.html.erb +3 -5
- data/app/views/users/_form.html.erb +1 -3
- data/config/application.rb +2 -3
- data/config/engine.rb +5 -2
- data/config/initializers/assets.rb +8 -0
- data/config/initializers/iqvoc.rb +1 -0
- data/config/initializers/linked_data.rb +13 -1
- data/config/locales/activerecord.de.yml +1 -0
- data/config/locales/activerecord.en.yml +1 -0
- data/config/locales/de.yml +3 -0
- data/config/locales/en.yml +3 -0
- data/db/migrate/20260723172701_add_zip_to_exports.rb +5 -0
- data/db/migrate/20260917120000_add_index_on_labelings_target_id.rb +5 -0
- data/iqvoc.gemspec +12 -9
- data/lib/generators/app/template.rb +1 -0
- data/lib/iqvoc/configuration/additional_associations.rb +54 -0
- data/lib/iqvoc/configuration/concept.rb +15 -3
- data/lib/iqvoc/configuration/core.rb +1 -0
- data/lib/iqvoc/configuration/instance_configuration.rb +2 -0
- data/lib/iqvoc/environments/production.rb +1 -1
- data/lib/iqvoc/environments/test.rb +1 -1
- data/lib/iqvoc/version.rb +1 -1
- data/lib/iqvoc.rb +1 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/exporter.rake +14 -4
- data/test/controllers/remote_labels_controller_test.rb +90 -0
- data/test/integration/reverse_match_job_test.rb +1 -1
- data/test/integration_test_helper.rb +2 -2
- data/test/models/additional_associations_test.rb +67 -0
- data/test/models/skos_export_link_test.rb +93 -0
- data/test/models/skos_export_test.rb +71 -0
- data/test/system/.keep +0 -0
- metadata +105 -42
- data/Gemfile.lock +0 -607
- data/app/assets/javascripts/iqvoc/hover_menues.js +0 -14
- data/app/assets/javascripts/manifest.js +0 -2
- data/config/database.yml +0 -20
- data/db/schema.rb +0 -305
- data/test/models/hygiene_test.rb +0 -35
- /data/app/assets/stylesheets/{manifest.scss → _manifest.scss} +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/autocomplete.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/create_note.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/debounce.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/entityselect_qualified.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/label_resolver.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/langselect.js +0 -0
- /data/app/{assets/javascripts → javascript}/iqvoc/manifest.js +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6f67e560f1aac50c13bd28d33a5929ac876f297bda3e023c3474f728c397bfba
|
|
4
|
+
data.tar.gz: '0818c7dfe12e3b7fd16fcf9098871d3fa1d50859c03f5264a4665ec8a8e840c7'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5d7c4b4a4a3c79a9add3e8e350cdb021ff72bdeb620fa31622dca5c1848c963a94f75cce7547df16076de497a0bde490d07db348cec3ba198b8e24740fd1e7d
|
|
7
|
+
data.tar.gz: 990188563110861ce3ad6a80095e772f003502e64bacf81a78c044ba4f7ac4a45648929ac01cc47e37b1372636bc2afbbaabb67069954939477293713fb577f5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
## [4.17.0]
|
|
2
|
+
|
|
3
|
+
* upgrade to Bootstrap v5 (and `bootstrap_form` v5)
|
|
4
|
+
* replace faucet-pipeline with Propshaft, `jsbundling-rails` (esbuild) and
|
|
5
|
+
`cssbundling-rails` (Sass); JavaScript moved to `app/javascript`
|
|
6
|
+
* upgrade to Font Awesome v7, replace `jquery-ujs` with `@rails/ujs`
|
|
7
|
+
* `bin/dev` now starts all processes from `Procfile.dev` via foreman
|
|
8
|
+
* add a `draft` relation to the `Versioning` concern
|
|
9
|
+
* add an index on `labelings.target_id` (requires migration)
|
|
10
|
+
* rename SKOS dumps to `<export_file_prefix>-<timestamp>.<type>` and default
|
|
11
|
+
`Iqvoc.export_file_prefix` to `iqvoc-data`
|
|
12
|
+
* drop some inline styles
|
|
13
|
+
* test against Ruby 4 on CI
|
|
14
|
+
|
|
15
|
+
## [4.16.0]
|
|
16
|
+
|
|
17
|
+
* export SKOS as a ZIP archive, via `rake iqvoc:export ZIP=true` and the web interface
|
|
18
|
+
* add `LINK` to `rake iqvoc:export`, keeping a symlink on the newest dump
|
|
19
|
+
* add `Iqvoc.export_file_prefix` to name dumps after the hosting application
|
|
20
|
+
* speed up the SKOS export on a large thesaurus
|
|
21
|
+
* restore preloading of concept associations, which had silently become a no-op
|
|
22
|
+
* let additional associations declare their `inverse_of`, so that rendering a
|
|
23
|
+
child no longer reloads the record it belongs to
|
|
24
|
+
* look up the concept scheme once per export instead of once per concept
|
|
25
|
+
* sort note annotations in Ruby, so that preloaded annotations are used
|
|
26
|
+
* no longer load ActiveStorage and ActionText, which were unused
|
|
27
|
+
* upgrade to Faraday v2
|
|
28
|
+
* render 503 when a remote label target is unreachable
|
|
29
|
+
* fix rendering the concept scheme
|
|
30
|
+
* fix i18n glitches in exports
|
|
31
|
+
|
|
1
32
|
## [4.15.0]
|
|
2
33
|
|
|
3
34
|
* upgrade to Rails v8.1
|
data/Gemfile
CHANGED
|
@@ -19,7 +19,7 @@ source 'https://rubygems.org'
|
|
|
19
19
|
# TODO: The following dependencies could be included by the "gemspec" command.
|
|
20
20
|
# There is only one problem: gemspec puts the dependencies automatically to a
|
|
21
21
|
# group (:development by default). This is not what we need.
|
|
22
|
-
gem 'rails', '
|
|
22
|
+
gem 'rails', '>= 8.1.2', '< 9'
|
|
23
23
|
gem 'puma', '>= 5.0'
|
|
24
24
|
gem 'kaminari'
|
|
25
25
|
gem 'authlogic'
|
|
@@ -27,23 +27,27 @@ gem 'scrypt'
|
|
|
27
27
|
gem 'cancancan'
|
|
28
28
|
gem 'iq_rdf'
|
|
29
29
|
gem 'iq_triplestorage'
|
|
30
|
-
|
|
30
|
+
# TODO: Remove once a Rails 8.1.x release with the fix shipped: https://github.com/rails/rails/pull/58601
|
|
31
|
+
gem 'json', '< 3'
|
|
31
32
|
gem 'csv'
|
|
32
33
|
gem 'rails_autolink'
|
|
33
|
-
gem 'faraday', '
|
|
34
|
-
gem '
|
|
34
|
+
gem 'faraday', '~> 2.0'
|
|
35
|
+
gem 'faraday-follow_redirects', '~> 0.5'
|
|
35
36
|
gem 'nokogiri'
|
|
36
37
|
gem 'linkeddata'
|
|
37
38
|
gem 'rdf-vocab'
|
|
38
39
|
gem "deep_cloneable"
|
|
39
|
-
gem "bootstrap_form", "~>
|
|
40
|
+
gem "bootstrap_form", "~> 5.0"
|
|
40
41
|
gem 'apipie-rails'
|
|
41
42
|
gem 'maruku', require: false # needed for apipie documentation
|
|
42
43
|
gem 'database_cleaner'
|
|
43
44
|
gem 'delayed_job_active_record'
|
|
45
|
+
gem 'rubyzip'
|
|
44
46
|
gem 'carrierwave'
|
|
45
47
|
gem 'carrierwave-i18n'
|
|
46
|
-
gem '
|
|
48
|
+
gem 'propshaft'
|
|
49
|
+
gem 'cssbundling-rails'
|
|
50
|
+
gem 'jsbundling-rails'
|
|
47
51
|
gem 'bootsnap', require: false
|
|
48
52
|
|
|
49
53
|
# database adapters
|
|
@@ -56,7 +60,6 @@ gem 'rack-mini-profiler'
|
|
|
56
60
|
|
|
57
61
|
group :development do
|
|
58
62
|
gem 'web-console', '>= 4.1.0'
|
|
59
|
-
gem 'listen', '~> 3.3'
|
|
60
63
|
end
|
|
61
64
|
|
|
62
65
|
group :development, :test do
|
data/app/aides/skos_exporter.rb
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
require 'iq_rdf'
|
|
2
2
|
require 'uri'
|
|
3
3
|
require 'fileutils'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'zip'
|
|
4
6
|
|
|
5
7
|
class SkosExporter
|
|
6
8
|
include RdfHelper # necessary to use render_concept helper
|
|
7
9
|
include RdfNamespacesHelper
|
|
8
10
|
include Rails.application.routes.url_helpers
|
|
9
11
|
|
|
10
|
-
def initialize(file_path, type, default_namespace_url, logger = Rails.logger)
|
|
12
|
+
def initialize(file_path, type, default_namespace_url, logger = Rails.logger, zip: false, entry_name: nil, link_path: nil, batch_size: 500)
|
|
11
13
|
default_url_options[:port] = URI.parse(default_namespace_url).port
|
|
12
14
|
default_url_options[:host] = URI.parse(default_namespace_url).to_s.gsub(/\/$/, '')
|
|
13
15
|
|
|
14
16
|
@file_path = file_path
|
|
15
17
|
@type = type
|
|
16
18
|
@logger = logger
|
|
19
|
+
@zip = zip
|
|
20
|
+
@entry_name = entry_name
|
|
21
|
+
@link_path = link_path
|
|
22
|
+
@batch_size = batch_size
|
|
17
23
|
@document = IqRdf::Document.new
|
|
18
24
|
|
|
19
25
|
unless ['ttl', 'nt', 'xml'].include? @type
|
|
@@ -48,6 +54,7 @@ class SkosExporter
|
|
|
48
54
|
|
|
49
55
|
# saving export to disk
|
|
50
56
|
save_file(@file_path, @type, @document)
|
|
57
|
+
update_link(@link_path, @file_path) if @link_path
|
|
51
58
|
|
|
52
59
|
done = Time.now
|
|
53
60
|
@logger.info "Export Job finished in #{(done - start).to_i} seconds."
|
|
@@ -69,67 +76,88 @@ class SkosExporter
|
|
|
69
76
|
def add_collections(document)
|
|
70
77
|
@logger.info 'Exporting collections...'
|
|
71
78
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
collections = Iqvoc::Collection.base_class.published.order('id').limit(100).offset(offset)
|
|
75
|
-
limit = collections.size < 100 ? collections.size : 100
|
|
76
|
-
break if collections.size == 0
|
|
77
|
-
|
|
79
|
+
total = 0
|
|
80
|
+
Iqvoc::Collection.base_class.published.find_in_batches(batch_size: @batch_size) do |collections|
|
|
78
81
|
# Todo: Preloading???
|
|
79
|
-
collections.each
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@logger.info "Collections #{offset+1}-#{offset+limit} exported."
|
|
84
|
-
offset += collections.size # Size is important!
|
|
82
|
+
collections.each { |collection| render_collection(document, collection) }
|
|
83
|
+
@logger.info "Collections #{total + 1}-#{total + collections.size} exported."
|
|
84
|
+
total += collections.size
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
@logger.info "Finished exporting collections (#{
|
|
87
|
+
@logger.info "Finished exporting collections (#{total} collections exported)."
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def add_concepts(document)
|
|
91
91
|
@logger.info 'Exporting concepts...'
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# one query. We don't want that! So let's do it manually :-)
|
|
101
|
-
Iqvoc::Concept.base_class.preload(concepts,
|
|
102
|
-
Iqvoc::Concept.base_class.default_includes + [
|
|
93
|
+
total = 0
|
|
94
|
+
Iqvoc::Concept.base_class.published.find_in_batches(batch_size: @batch_size) do |concepts|
|
|
95
|
+
# rendering touches every association below, so preload them per batch
|
|
96
|
+
# rather than letting each concept load them one by one. Note that this
|
|
97
|
+
# has to be the Preloader: Model.preload builds a relation and would
|
|
98
|
+
# leave the records passed to it untouched.
|
|
99
|
+
associations = Iqvoc::Concept.base_class.default_includes + [
|
|
103
100
|
:matches,
|
|
104
101
|
:collection_members,
|
|
105
102
|
:notations,
|
|
106
|
-
{ relations: :target, labelings: :target
|
|
107
|
-
]
|
|
103
|
+
{ relations: :target, labelings: :target }
|
|
104
|
+
] + Iqvoc::Concept.additional_association_preloads
|
|
105
|
+
# notes are rendered behind the same condition, see render_concept
|
|
106
|
+
associations << { notes: :annotations } if Iqvoc.rdf_show_change_notes
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
render_concept(document, concept, true)
|
|
111
|
-
end
|
|
108
|
+
ActiveRecord::Associations::Preloader.new(records: concepts, associations: associations).call
|
|
112
109
|
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
concepts.each { |concept| render_concept(document, concept, true) }
|
|
111
|
+
@logger.info "Concepts #{total + 1}-#{total + concepts.size} exported."
|
|
112
|
+
total += concepts.size
|
|
115
113
|
end
|
|
116
114
|
|
|
117
|
-
@logger.info "Finished exporting concepts (#{
|
|
115
|
+
@logger.info "Finished exporting concepts (#{total} concepts exported)."
|
|
118
116
|
end
|
|
119
117
|
|
|
120
118
|
def save_file(file_path, type, content)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
# e.g not writable
|
|
130
|
-
ensure
|
|
131
|
-
file.close unless file == nil
|
|
119
|
+
serialized = serialize_rdf(content, type)
|
|
120
|
+
create_directory(file_path)
|
|
121
|
+
|
|
122
|
+
@logger.info "Saving export to '#{file_path}'"
|
|
123
|
+
if @zip
|
|
124
|
+
save_zipped(file_path, serialized)
|
|
125
|
+
else
|
|
126
|
+
File.write(file_path, serialized)
|
|
132
127
|
end
|
|
128
|
+
rescue IOError, SystemCallError, Zip::Error => e
|
|
129
|
+
@logger.error "Failed to save export: #{e.message}"
|
|
130
|
+
raise
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def save_zipped(file_path, serialized)
|
|
134
|
+
entry_name = @entry_name || File.basename(file_path, '.zip')
|
|
135
|
+
Zip::OutputStream.open(file_path) do |zos|
|
|
136
|
+
zos.put_next_entry(entry_name)
|
|
137
|
+
zos.write(serialized)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# points the symlink at the file just written, so that a stable URL can serve
|
|
142
|
+
# the most recent export while its file name carries the creation date
|
|
143
|
+
def update_link(link_path, file_path)
|
|
144
|
+
link_dir = File.dirname(File.expand_path(link_path))
|
|
145
|
+
FileUtils.mkdir_p(link_dir)
|
|
146
|
+
|
|
147
|
+
# a relative target survives the export directory being moved
|
|
148
|
+
target = Pathname.new(File.expand_path(file_path)).
|
|
149
|
+
relative_path_from(Pathname.new(link_dir)).to_s
|
|
150
|
+
|
|
151
|
+
# symlink under a temporary name, then rename it into place: rename is
|
|
152
|
+
# atomic, so a concurrent download never sees a missing link
|
|
153
|
+
tmp_path = "#{link_path}.tmp#{Process.pid}"
|
|
154
|
+
File.symlink(target, tmp_path)
|
|
155
|
+
File.rename(tmp_path, link_path)
|
|
156
|
+
|
|
157
|
+
@logger.info "Updated symlink '#{link_path}' -> '#{target}'"
|
|
158
|
+
rescue IOError, SystemCallError => e
|
|
159
|
+
@logger.error "Failed to update symlink: #{e.message}"
|
|
160
|
+
raise
|
|
133
161
|
end
|
|
134
162
|
|
|
135
163
|
def create_directory(file_path)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import 'manifest';
|
|
@@ -1,7 +1,36 @@
|
|
|
1
|
+
// These placeholders live here (rather than in settings/_mixins.scss, which
|
|
2
|
+
// is imported before Bootstrap) so that Sass's @extend emits their merged
|
|
3
|
+
// selector at this position in the cascade. Bootstrap 5's own .btn rule
|
|
4
|
+
// sets font-family explicitly, so if the merged selector compiled in
|
|
5
|
+
// earlier (pre-Bootstrap), Bootstrap's later same-specificity rule would
|
|
6
|
+
// win and silently override it.
|
|
7
|
+
%font-interaction {
|
|
8
|
+
font-family: 'Fira Sans Light SC';
|
|
9
|
+
text-transform: lowercase;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
%font-bold {
|
|
13
|
+
font-family: 'Fira Sans Bold';
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
%font-light {
|
|
18
|
+
font-family: 'Fira Sans Light';
|
|
19
|
+
}
|
|
20
|
+
|
|
1
21
|
body > .container {
|
|
2
22
|
padding-top: 5rem;
|
|
3
23
|
}
|
|
4
24
|
|
|
25
|
+
// Bootstrap 5 floats <legend> (float: left; width: 100%) to work around a
|
|
26
|
+
// Firefox fieldset/flex bug, clearing it only on the very next sibling
|
|
27
|
+
// (`legend + *`). Fieldsets with more than one element after the legend
|
|
28
|
+
// (like ours) leave the float uncleared, which can squeeze later siblings
|
|
29
|
+
// to zero width. We don't need the Firefox fix here, so disable the float.
|
|
30
|
+
legend {
|
|
31
|
+
float: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
5
34
|
form#search {
|
|
6
35
|
.btn-group {
|
|
7
36
|
margin-top: 10px;
|
|
@@ -48,7 +77,7 @@ small {
|
|
|
48
77
|
margin-bottom: -0.5em;
|
|
49
78
|
}
|
|
50
79
|
|
|
51
|
-
> .close {
|
|
80
|
+
> .btn-close {
|
|
52
81
|
font-size: $h3-font-size;
|
|
53
82
|
}
|
|
54
83
|
}
|
|
@@ -7,7 +7,7 @@ ul.jqtree-tree {
|
|
|
7
7
|
margin-left: 0;
|
|
8
8
|
|
|
9
9
|
li {
|
|
10
|
-
background:
|
|
10
|
+
background: url('/treeview-default-line.gif') no-repeat;
|
|
11
11
|
background-position: 2px 0px;
|
|
12
12
|
line-height: 1.8em;
|
|
13
13
|
padding-left: 18px;
|
|
@@ -75,7 +75,7 @@ ul.jqtree-tree {
|
|
|
75
75
|
border-bottom: 0;
|
|
76
76
|
color: #333;
|
|
77
77
|
cursor: pointer;
|
|
78
|
-
margin-left: -
|
|
78
|
+
margin-left: -18px;
|
|
79
79
|
margin-right: .5em;
|
|
80
80
|
text-decoration: none;
|
|
81
81
|
|
|
@@ -96,10 +96,10 @@ ul.jqtree-tree {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
.
|
|
99
|
+
.drag { cursor: move;}
|
|
100
100
|
|
|
101
101
|
.jqtree-loading > div.jqtree-element.jqtree_common:after {
|
|
102
|
-
content:
|
|
102
|
+
content: url('/ajax-loader.gif');
|
|
103
103
|
margin-left: 8px;
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -1,79 +1,79 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: 'Fira Sans Light SC';
|
|
3
|
-
src:
|
|
4
|
-
src:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
src: url('/FiraSans-Light-SC.eot');
|
|
4
|
+
src: url('/FiraSans-Light-SC.eot') format('embedded-opentype'),
|
|
5
|
+
url('/FiraSans-Light-SC.woff2') format('woff2'),
|
|
6
|
+
url('/FiraSans-Light-SC.woff') format('woff'),
|
|
7
|
+
url('/FiraSans-Light-SC.ttf') format('truetype');
|
|
8
8
|
font-style: normal;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
@font-face {
|
|
12
12
|
font-family: 'Fira Sans ExtraLight';
|
|
13
|
-
src:
|
|
14
|
-
src:
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
src: url('/FiraSans-ExtraLight.eot');
|
|
14
|
+
src: url('/FiraSans-ExtraLight.eot') format('embedded-opentype'),
|
|
15
|
+
url('/FiraSans-ExtraLight.woff') format('woff'),
|
|
16
|
+
url('/FiraSans-ExtraLight.ttf') format('truetype');
|
|
17
17
|
font-style: normal;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
@font-face {
|
|
21
21
|
font-family: 'Fira Sans Regular';
|
|
22
|
-
src:
|
|
23
|
-
src:
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
src: url('/FiraSans-Regular.eot');
|
|
23
|
+
src: url('/FiraSans-Regular.eot') format('embedded-opentype'),
|
|
24
|
+
url('/FiraSans-Regular.woff') format('woff'),
|
|
25
|
+
url('/FiraSans-Regular.ttf') format('truetype');
|
|
26
26
|
font-weight: 400;
|
|
27
27
|
font-style: normal;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
@font-face {
|
|
31
31
|
font-family: 'Fira Sans Regular Italic';
|
|
32
|
-
src:
|
|
33
|
-
src:
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
src: url('/FiraSans-Italic.eot');
|
|
33
|
+
src: url('/FiraSans-Italic.eot') format('embedded-opentype'),
|
|
34
|
+
url('/FiraSans-Italic.woff') format('woff'),
|
|
35
|
+
url('/FiraSans-Italic.ttf') format('truetype');
|
|
36
36
|
font-weight: 400;
|
|
37
37
|
font-style: italic;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
@font-face {
|
|
41
41
|
font-family: 'Fira Sans Bold';
|
|
42
|
-
src:
|
|
43
|
-
src:
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
src: url('/FiraSans-Bold.eot');
|
|
43
|
+
src: url('/FiraSans-Bold.eot') format('embedded-opentype'),
|
|
44
|
+
url('/FiraSans-Bold.woff') format('woff'),
|
|
45
|
+
url('/FiraSans-Bold.ttf') format('truetype');
|
|
46
46
|
font-weight: 700;
|
|
47
47
|
font-style: normal;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
@font-face {
|
|
51
51
|
font-family: 'Fira Sans Bold Italic';
|
|
52
|
-
src:
|
|
53
|
-
src:
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
src: url('/FiraSans-BoldItalic.eot');
|
|
53
|
+
src: url('/FiraSans-BoldItalic.eot') format('embedded-opentype'),
|
|
54
|
+
url('/FiraSans-BoldItalic.woff') format('woff'),
|
|
55
|
+
url('/FiraSans-BoldItalic.ttf') format('truetype');
|
|
56
56
|
font-weight: 700;
|
|
57
57
|
font-style: italic;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
@font-face {
|
|
61
61
|
font-family: 'Fira Mono Regular';
|
|
62
|
-
src:
|
|
63
|
-
src:
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
src: url('/FiraMono-Regular.eot');
|
|
63
|
+
src: url('/FiraMono-Regular.eot') format('embedded-opentype'),
|
|
64
|
+
url('/FiraMono-Regular.woff') format('woff'),
|
|
65
|
+
url('/FiraMono-Regular.ttf') format('truetype');
|
|
66
66
|
font-weight: 400;
|
|
67
67
|
font-style: normal;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
@font-face {
|
|
71
71
|
font-family: 'Fira Sans Light';
|
|
72
|
-
src:
|
|
72
|
+
src: url('/FiraSans-Light.eot');
|
|
73
73
|
src: local('Fira Sans Light'),
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
url('/FiraSans-Light.eot') format('embedded-opentype'),
|
|
75
|
+
url('/FiraSans-Light.woff') format('woff'),
|
|
76
|
+
url('/FiraSans-Light.ttf') format('truetype');
|
|
77
77
|
font-weight: 300;
|
|
78
78
|
font-style: normal;
|
|
79
79
|
}
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
%font-interaction {
|
|
2
|
-
font-family: 'Fira Sans Light SC';
|
|
3
|
-
text-transform: lowercase;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
%font-bold {
|
|
7
|
-
font-family: 'Fira Sans Bold';
|
|
8
|
-
font-weight: 700;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
%font-light {
|
|
12
|
-
font-family: 'Fira Sans Light';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
1
|
@mixin transitional($property: all, $duration: .25s) {
|
|
16
2
|
transition: $property $duration ease-in-out;
|
|
17
3
|
}
|
|
@@ -56,6 +56,9 @@ module ControllerExtensions
|
|
|
56
56
|
@status = current_user ? 403 : 401
|
|
57
57
|
@user_session = UserSession.new if @status == 401
|
|
58
58
|
@return_url = request.fullpath
|
|
59
|
+
|
|
60
|
+
return if self.performed?
|
|
61
|
+
|
|
59
62
|
respond_to do |format|
|
|
60
63
|
format.html { render template: 'errors/access_denied', status: @status }
|
|
61
64
|
format.any { head @status }
|
|
@@ -66,6 +69,8 @@ module ControllerExtensions
|
|
|
66
69
|
@exception = exception
|
|
67
70
|
SearchResultsController.prepare_basic_variables(self)
|
|
68
71
|
|
|
72
|
+
return if self.performed?
|
|
73
|
+
|
|
69
74
|
respond_to do |format|
|
|
70
75
|
format.html { render template: 'errors/not_found', status: 404 }
|
|
71
76
|
format.any { head 404 }
|
|
@@ -75,6 +80,8 @@ module ControllerExtensions
|
|
|
75
80
|
def handle_bad_request(exception)
|
|
76
81
|
@exception = exception
|
|
77
82
|
|
|
83
|
+
return if self.performed?
|
|
84
|
+
|
|
78
85
|
respond_to do |format|
|
|
79
86
|
format.any { head 400 }
|
|
80
87
|
end
|
|
@@ -85,6 +92,8 @@ module ControllerExtensions
|
|
|
85
92
|
Rails.logger.error(exception.backtrace.join("\n"))
|
|
86
93
|
@exception = exception
|
|
87
94
|
|
|
95
|
+
return if self.performed?
|
|
96
|
+
|
|
88
97
|
respond_to do |format|
|
|
89
98
|
format.html { render template: 'errors/server_error', status: 500 }
|
|
90
99
|
format.any { head 500 }
|
|
@@ -94,6 +103,8 @@ module ControllerExtensions
|
|
|
94
103
|
def handle_unknown_format(exception)
|
|
95
104
|
@exception = exception
|
|
96
105
|
|
|
106
|
+
return if self.performed?
|
|
107
|
+
|
|
97
108
|
respond_to do |format|
|
|
98
109
|
format.any { head 406 }
|
|
99
110
|
end
|
|
@@ -58,10 +58,8 @@ class ExportsController < ApplicationController
|
|
|
58
58
|
|
|
59
59
|
def download
|
|
60
60
|
export = Export.find(params[:export_id])
|
|
61
|
-
time = export.finished_at&.strftime('%Y-%m-%d_%H-%M')
|
|
62
|
-
|
|
63
61
|
Rails.logger.debug("Try to serve export from: #{export.build_filename}")
|
|
64
|
-
send_file export.build_filename, filename:
|
|
62
|
+
send_file export.build_filename, filename: export.download_filename
|
|
65
63
|
rescue ::ActionController::MissingFile => e
|
|
66
64
|
flash[:error] = t('txt.views.export.missing_file')
|
|
67
65
|
redirect_to exports_path
|
|
@@ -70,6 +68,6 @@ class ExportsController < ApplicationController
|
|
|
70
68
|
private
|
|
71
69
|
|
|
72
70
|
def export_params
|
|
73
|
-
params.require(:export).permit(:file_type, :default_namespace)
|
|
71
|
+
params.require(:export).permit(:file_type, :default_namespace, :zip)
|
|
74
72
|
end
|
|
75
73
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
class RemoteLabelsController < ApplicationController
|
|
2
2
|
include DatasetInitialization
|
|
3
3
|
|
|
4
|
+
rescue_from ServiceUnavailableError, with: :handle_service_unavailable
|
|
5
|
+
|
|
4
6
|
def show
|
|
5
7
|
@datasets = init_datasets
|
|
6
8
|
|
|
@@ -9,13 +11,13 @@ class RemoteLabelsController < ApplicationController
|
|
|
9
11
|
# ensure known dataset
|
|
10
12
|
@dataset = @datasets.detect { |d| concept_url.to_s.start_with?(d.url.to_s) }
|
|
11
13
|
unless @dataset
|
|
12
|
-
head
|
|
14
|
+
head :unprocessable_entity
|
|
13
15
|
return
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
label = @dataset.find_label(concept_url)
|
|
17
19
|
unless label
|
|
18
|
-
head
|
|
20
|
+
head :not_found
|
|
19
21
|
return
|
|
20
22
|
end
|
|
21
23
|
|
|
@@ -25,4 +27,14 @@ class RemoteLabelsController < ApplicationController
|
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def handle_service_unavailable(exception)
|
|
34
|
+
Rails.logger.error("External dataset unavailable: #{exception.url} - #{exception.message}")
|
|
35
|
+
render json: {
|
|
36
|
+
error: 'External service unavailable',
|
|
37
|
+
dataset_url: exception.url.to_s
|
|
38
|
+
}, status: :service_unavailable
|
|
39
|
+
end
|
|
28
40
|
end
|