rbbt-rest 1.1.4 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/config.ru +3 -0
- data/lib/rbbt/rest/client.rb +9 -10
- data/lib/rbbt/rest/common/cache.rb +32 -7
- data/lib/rbbt/rest/common/forms.rb +33 -0
- data/lib/rbbt/rest/common/locate.rb +4 -0
- data/lib/rbbt/rest/common/misc.rb +24 -0
- data/lib/rbbt/rest/common/render.rb +26 -9
- data/lib/rbbt/rest/common/resources.rb +1 -1
- data/lib/rbbt/rest/common/table.rb +87 -26
- data/lib/rbbt/rest/common/users.rb +5 -1
- data/lib/rbbt/rest/entity.rb +300 -95
- data/lib/rbbt/rest/entity/action_controller.rb +6 -1
- data/lib/rbbt/rest/entity/entity_list_card.rb +1 -1
- data/lib/rbbt/rest/entity/entity_map_card.rb +15 -0
- data/lib/rbbt/rest/entity/favourites.rb +57 -1
- data/lib/rbbt/rest/entity/finder.rb +1 -1
- data/lib/rbbt/rest/entity/helpers.rb +40 -7
- data/lib/rbbt/rest/entity/list.rb +8 -0
- data/lib/rbbt/rest/entity/locate.rb +114 -0
- data/lib/rbbt/rest/entity/map.rb +99 -0
- data/lib/rbbt/rest/entity/render.rb +25 -0
- data/lib/rbbt/rest/entity/rest.rb +33 -4
- data/lib/rbbt/rest/main.rb +27 -4
- data/lib/rbbt/rest/workflow.rb +7 -1
- data/lib/rbbt/rest/workflow/jobs.rb +21 -1
- data/share/views/compass/app.sass +17 -9
- data/share/views/compass/entity_card.sass +16 -3
- data/share/views/compass/favourites.sass +44 -2
- data/share/views/compass/form.sass +11 -0
- data/share/views/compass/list_container.sass +1 -1
- data/share/views/compass/reveal.sass +31 -0
- data/share/views/compass/style.sass +29 -1
- data/share/views/compass/style_mixins.sass +18 -6
- data/share/views/compass/table.sass +19 -3
- data/share/views/compass/topbar.sass +8 -2
- data/share/views/entity_map/Default.haml +5 -0
- data/share/views/entity_partials/action_card.haml +2 -0
- data/share/views/entity_partials/action_controller.haml +8 -1
- data/share/views/entity_partials/entity_list_card.haml +8 -6
- data/share/views/entity_partials/entity_map_card.haml +63 -0
- data/share/views/entity_partials/list_container.haml +3 -2
- data/share/views/error.haml +14 -10
- data/share/views/help.haml +34 -0
- data/share/views/help/entity.haml +193 -0
- data/share/views/help/workflow.haml +77 -0
- data/share/views/job_result/tsv.haml +3 -2
- data/share/views/layout.haml +33 -3
- data/share/views/layout/favourites.haml +14 -4
- data/share/views/layout/header.haml +4 -0
- data/share/views/partials/form.haml +3 -1
- data/share/views/partials/table.haml +16 -52
- data/share/views/partials/table/column.haml +10 -0
- data/share/views/partials/table/files.haml +4 -0
- data/share/views/partials/table/filters.haml +11 -0
- data/share/views/partials/table/page.haml +37 -0
- data/share/views/public/favicon.gif +0 -0
- data/share/views/public/js/_ajax_replace.js +76 -4
- data/share/views/public/js/_fix_tablesorter_science.js +13 -0
- data/share/views/public/js/actions.js +8 -2
- data/share/views/public/js/base.js +12 -1
- data/share/views/public/js/entities.js +39 -7
- data/share/views/public/js/favourites.js +308 -77
- data/share/views/public/js/helpers.js +9 -5
- data/share/views/public/js/lists.js +12 -12
- data/share/views/public/js/maps.js +17 -0
- data/share/views/public/js/reveal.js +48 -0
- data/share/views/public/js/tables.js +110 -51
- data/share/views/public/js/workflow.js +4 -16
- data/share/views/public/plugins/underscore/js/underscore.js +1227 -0
- data/share/views/tasks.haml +12 -1
- data/share/views/wait.haml +7 -0
- metadata +17 -2
@@ -20,6 +20,7 @@ module EntityRESTHelpers
|
|
20
20
|
entity_annotations = {}
|
21
21
|
entity_class.annotations.each do |annotation|
|
22
22
|
value = consume_parameter annotation, params
|
23
|
+
value = Entity::REST.restore_element(value) if String === value
|
23
24
|
value = false if value == "false"
|
24
25
|
value = true if value == "true"
|
25
26
|
entity_annotations[annotation] = value
|
@@ -71,6 +72,30 @@ module EntityRESTHelpers
|
|
71
72
|
|
72
73
|
render(template_file, locals, layout_file, "Entity list #{ action }: #{ id }")
|
73
74
|
end
|
75
|
+
|
76
|
+
def entity_map_render(map_id, type, column)
|
77
|
+
template_file = locate_entity_map_template(type, column)
|
78
|
+
|
79
|
+
map = Entity::Map.load_map(type, column, map_id, user)
|
80
|
+
locals = {:map => map, :map_id => map_id}
|
81
|
+
|
82
|
+
layout_file = layout ? locate_template("layout") : nil
|
83
|
+
|
84
|
+
render(template_file, locals, layout_file, "Entity map: #{ map_id }")
|
85
|
+
end
|
86
|
+
|
87
|
+
def entity_map_action_render(map, action, id, params = {})
|
88
|
+
template_file = locate_entity_map_action_template(map, action)
|
89
|
+
|
90
|
+
locals = params.merge({:map => map, :map_id => id})
|
91
|
+
|
92
|
+
layout_file = layout ? locate_template("layout") : nil
|
93
|
+
|
94
|
+
render(template_file, locals, layout_file, "Entity map #{ action }: #{ id }")
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
|
74
99
|
end
|
75
100
|
|
76
101
|
|
@@ -14,15 +14,15 @@ module Entity
|
|
14
14
|
#{{{ MISC
|
15
15
|
|
16
16
|
def self.clean_element(elem)
|
17
|
-
elem.gsub('/', '--')
|
17
|
+
elem.gsub('/', '--').gsub('%', 'o-o')
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.restore_element(elem)
|
21
|
-
CGI.unescape(elem.gsub('--', '/'))
|
21
|
+
CGI.unescape(CGI.unescape(elem.gsub('--', '/').gsub('o-o', '%')))
|
22
22
|
end
|
23
23
|
|
24
24
|
def entity_link_params
|
25
|
-
info = self.info
|
25
|
+
info = self.info.dup
|
26
26
|
info.delete :format
|
27
27
|
info.delete :annotation_types
|
28
28
|
info.delete :annotated_array
|
@@ -65,7 +65,21 @@ module Entity
|
|
65
65
|
|
66
66
|
#{{{ URLS
|
67
67
|
|
68
|
-
def self.entity_url(entity, type, params =
|
68
|
+
def self.entity_url(entity, type = nil, params = nil)
|
69
|
+
if type.nil?
|
70
|
+
type = entity.annotation_types.last.to_s
|
71
|
+
type << ":" << entity.format if entity.respond_to? :format
|
72
|
+
end
|
73
|
+
|
74
|
+
if params.nil?
|
75
|
+
if entity.respond_to? :entity_link_params
|
76
|
+
params = entity.entity_link_params
|
77
|
+
else
|
78
|
+
params = {}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
params ||= entity.info if entity.respond_to? :info
|
69
83
|
url = File.join('/', 'entity', Entity::REST.clean_element(type.to_s), entity)
|
70
84
|
url << "?" << Misc.hash2GET_params(params) if params.any?
|
71
85
|
url
|
@@ -87,6 +101,20 @@ module Entity
|
|
87
101
|
url
|
88
102
|
end
|
89
103
|
|
104
|
+
def self.entity_map_url(map, type, column)
|
105
|
+
type = Entity::REST.clean_element(type.to_s)
|
106
|
+
column = Entity::REST.clean_element(column)
|
107
|
+
map = Entity::REST.clean_element(map)
|
108
|
+
File.join('/', 'entity_map', type, column, map)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.entity_map_action_url(map, type, column, action)
|
112
|
+
type = Entity::REST.clean_element(type.to_s)
|
113
|
+
column = Entity::REST.clean_element(column)
|
114
|
+
map = Entity::REST.clean_element(map)
|
115
|
+
File.join('/', 'entity_map_action', type, column, action, map)
|
116
|
+
end
|
117
|
+
|
90
118
|
|
91
119
|
#{{{ LINKS
|
92
120
|
|
@@ -101,6 +129,7 @@ module Entity
|
|
101
129
|
|
102
130
|
attributes[:class] << klasses
|
103
131
|
attributes[:href] = Entity::REST.entity_url(self, entity_type.to_s, link_params)
|
132
|
+
attributes["attr-entity_id"] = self.to_s
|
104
133
|
|
105
134
|
text = self.respond_to?(:name)? self.name || self : self if text.nil?
|
106
135
|
attributes[:title] = text if attributes[:title].nil?
|
data/lib/rbbt/rest/main.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rbbt/rest/common/users'
|
|
4
4
|
require 'ruby-prof'
|
5
5
|
|
6
6
|
require 'sinatra/base'
|
7
|
+
require 'sinatra/cross_origin'
|
7
8
|
require 'json'
|
8
9
|
|
9
10
|
module Sinatra
|
@@ -21,18 +22,25 @@ module Sinatra
|
|
21
22
|
|
22
23
|
set :cache_dir, Rbbt.var.sinatra.cache.find unless settings.respond_to? :cache_dir and settings.cache_dir != nil
|
23
24
|
set :file_dir, Rbbt.var.sinatra.files.find unless settings.respond_to? :file_dir and settings.file_dir != nil
|
25
|
+
set :permalink_dir, Rbbt.var.sinatra.permalink.find unless settings.respond_to? :permalink_dir and settings.permalink_dir != nil
|
24
26
|
|
25
27
|
set :public_folder, Rbbt.share.views.public.find
|
26
28
|
|
27
29
|
attr_accessor :ajax, :layout, :format, :size, :update, :cache_type, :_, :profile
|
28
30
|
|
29
|
-
set :haml, { :ugly => true }
|
30
31
|
if production?
|
31
32
|
set :haml, { :ugly => true }
|
32
33
|
set :clean_trace, true
|
33
34
|
set :static_cache_control , [:public, {:max_age => 360000}]
|
34
35
|
end
|
35
36
|
|
37
|
+
enable :cross_origin
|
38
|
+
set :allow_origin, :any
|
39
|
+
set :allow_methods, [:get, :post, :options]
|
40
|
+
set :allow_credentials, true
|
41
|
+
set :max_age, "1728000"
|
42
|
+
set :allow_headers, ['URI']
|
43
|
+
|
36
44
|
before do
|
37
45
|
Log.info("IP #{request.ip}: " << request.path_info << ". Params: " << Misc.remove_long_items(params).inspect)
|
38
46
|
process_common_parameters
|
@@ -52,8 +60,7 @@ module Sinatra
|
|
52
60
|
printer.print(:path => dir, :profile => 'profile')
|
53
61
|
Log.info("Profile saved at #{ dir }")
|
54
62
|
end
|
55
|
-
|
56
|
-
request
|
63
|
+
response.header["URI"] = request.env["REQUEST_URI"]
|
57
64
|
end
|
58
65
|
|
59
66
|
add_sass_load_path Rbbt.views.compass.find
|
@@ -92,9 +99,25 @@ module Sinatra
|
|
92
99
|
end
|
93
100
|
|
94
101
|
get '/' do
|
95
|
-
template_render('main', params)
|
102
|
+
template_render('main', params, 'main', :cache_type => :asynchronous)
|
96
103
|
end
|
97
104
|
|
105
|
+
get '/help/?:section?' do
|
106
|
+
if params[:section]
|
107
|
+
section = params[:section]
|
108
|
+
template_render('help/' << section, params, section, :cache_type => :asynchronous)
|
109
|
+
else
|
110
|
+
template_render('help', params, 'help', :cache_type => :asynchronous)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
get '/permalink/:id' do
|
115
|
+
content_type "text/html"
|
116
|
+
layout_file = locate_template('layout')
|
117
|
+
Haml::Engine.new(Open.read(layout_file), :filename => layout_file).render(self) do
|
118
|
+
Open.read(File.join(settings.permalink_dir, params[:id]))
|
119
|
+
end
|
120
|
+
end
|
98
121
|
end
|
99
122
|
end
|
100
123
|
end
|
data/lib/rbbt/rest/workflow.rb
CHANGED
@@ -16,6 +16,7 @@ require 'json'
|
|
16
16
|
|
17
17
|
module Sinatra
|
18
18
|
module RbbtRESTWorkflow
|
19
|
+
WORKFLOWS = []
|
19
20
|
|
20
21
|
def add_workflow_resource(workflow)
|
21
22
|
views_dir = workflow.libdir.www.views.find(:lib)
|
@@ -32,12 +33,13 @@ module Sinatra
|
|
32
33
|
|
33
34
|
def add_workflow(workflow, add_resource = false)
|
34
35
|
raise "Provided workflow is not of type Workflow" unless Workflow === workflow or WorkflowRESTClient === workflow
|
36
|
+
RbbtRESTWorkflow::WORKFLOWS.push workflow unless RbbtRESTWorkflow::WORKFLOWS.include? workflow
|
35
37
|
|
36
38
|
add_workflow_resource(workflow) if add_resource
|
37
39
|
|
38
40
|
Log.debug("Adding #{ workflow } to REST server")
|
39
41
|
|
40
|
-
self.instance_eval workflow.libdir.lib['sinatra.rb'].read if File.exists? workflow.libdir.lib['sinatra.rb']
|
42
|
+
self.instance_eval workflow.libdir.lib['sinatra.rb'].read, workflow.libdir.lib['sinatra.rb'].find if File.exists? workflow.libdir.lib['sinatra.rb']
|
41
43
|
|
42
44
|
get "/#{workflow.to_s}" do
|
43
45
|
case format
|
@@ -79,6 +81,10 @@ module Sinatra
|
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
get "/#{workflow.to_s}/description" do
|
85
|
+
halt 200, workflow.workflow_description
|
86
|
+
end
|
87
|
+
|
82
88
|
|
83
89
|
get "/#{workflow.to_s}/:task" do
|
84
90
|
task = consume_parameter(:task)
|
@@ -90,9 +90,29 @@ module WorkflowRESTHelpers
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def show_result(job, workflow, task)
|
93
|
-
case format
|
93
|
+
case format.to_sym
|
94
94
|
when :html
|
95
95
|
show_result_html job.load, workflow, task, job.name, job
|
96
|
+
when :table
|
97
|
+
halt 200, tsv2html(job.path, :url => "/" << [workflow.to_s, task, job.name] * "/")
|
98
|
+
when :entities
|
99
|
+
tsv = tsv_process(load_tsv(job.path).first)
|
100
|
+
list = tsv.values.flatten
|
101
|
+
if not AnnotatedArray === list and Annotated === list.first
|
102
|
+
list.first.annotate list
|
103
|
+
list.extend AnnotatedArray
|
104
|
+
end
|
105
|
+
type = list.annotation_types.last
|
106
|
+
list_id = "TMP #{type} in #{ [workflow.to_s, task, job.name] * " - " }"
|
107
|
+
Entity::List.save_list(type.to_s, list_id, list, user)
|
108
|
+
redirect to(Entity::REST.entity_list_url(list_id, type))
|
109
|
+
when :map
|
110
|
+
tsv = tsv_process(load_tsv(job.path).first)
|
111
|
+
type = tsv.keys.annotation_types.last
|
112
|
+
column = tsv.fields.first
|
113
|
+
map_id = "MAP #{type}-#{column} in #{ [workflow.to_s, task, job.name] * " - " }"
|
114
|
+
Entity::Map.save_map(type.to_s, column, map_id, tsv, user)
|
115
|
+
redirect to(Entity::REST.entity_map_url(map_id, type, column))
|
96
116
|
when :json
|
97
117
|
content_type "application/json"
|
98
118
|
halt 200, job.load.to_json
|
@@ -1,4 +1,6 @@
|
|
1
1
|
@import _foundation_setup
|
2
|
+
@import style_mixins
|
3
|
+
|
2
4
|
@import lists
|
3
5
|
@import list_container
|
4
6
|
@import dom
|
@@ -7,8 +9,6 @@
|
|
7
9
|
@import tabs
|
8
10
|
@import responsive_table
|
9
11
|
|
10
|
-
@import style_mixins
|
11
|
-
|
12
12
|
@import topbar
|
13
13
|
@import favourites
|
14
14
|
@import footer
|
@@ -17,6 +17,7 @@
|
|
17
17
|
@import offcanvas
|
18
18
|
@import fragment
|
19
19
|
@import workflow
|
20
|
+
@import reveal
|
20
21
|
@import style
|
21
22
|
|
22
23
|
body
|
@@ -26,13 +27,6 @@ body
|
|
26
27
|
#body
|
27
28
|
min-height: 900px
|
28
29
|
|
29
|
-
|
30
|
-
//.main
|
31
|
-
dl
|
32
|
-
@extend dl.details
|
33
|
-
@extend .column
|
34
|
-
@extend .large-4
|
35
|
-
|
36
30
|
ul.entities
|
37
31
|
@extend .inline-list
|
38
32
|
li
|
@@ -40,3 +34,17 @@ ul.entities
|
|
40
34
|
|
41
35
|
dl.details
|
42
36
|
@extend dl.indented
|
37
|
+
|
38
|
+
|
39
|
+
.filter_controls
|
40
|
+
@media #{$medium}
|
41
|
+
div.input
|
42
|
+
@include grid-column(4)
|
43
|
+
&.submit, &.submit > input
|
44
|
+
float: right
|
45
|
+
clear: both
|
46
|
+
label
|
47
|
+
@include ellipsis_text()
|
48
|
+
|
49
|
+
.map_management ul
|
50
|
+
@include button-group-list()
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// GRID LAYOUT
|
2
|
-
.entity_card, .entity_list_card, .action_card
|
2
|
+
.entity_card, .entity_list_card, .action_card, .entity_map_card
|
3
3
|
|
4
4
|
& > .title
|
5
5
|
@include grid-row(collapse)
|
@@ -49,9 +49,8 @@
|
|
49
49
|
clear: left
|
50
50
|
|
51
51
|
|
52
|
-
.entity_card, .entity_list_card, .action_card
|
52
|
+
.entity_card, .entity_list_card, .action_card, .entity_map_card
|
53
53
|
& > .title
|
54
|
-
padding-top: 1em
|
55
54
|
margin-bottom: 1em
|
56
55
|
|
57
56
|
.name
|
@@ -98,3 +97,17 @@
|
|
98
97
|
p
|
99
98
|
text-align: justify
|
100
99
|
max-width: 50em
|
100
|
+
|
101
|
+
|
102
|
+
@media #{$not-small}
|
103
|
+
.reveal-modal
|
104
|
+
.entity_card, .entity_list_card, .action_card, .entity_map_card
|
105
|
+
&> .card
|
106
|
+
&>.sidebar
|
107
|
+
width: 33%
|
108
|
+
&>.content
|
109
|
+
width: 67%
|
110
|
+
|
111
|
+
form.rename
|
112
|
+
input[name=rename]
|
113
|
+
width: 100%
|
@@ -1,5 +1,9 @@
|
|
1
|
-
a
|
2
|
-
|
1
|
+
.reveal-modal a.toggle_favourite
|
2
|
+
&:not(.active)
|
3
|
+
i
|
4
|
+
color: black !important
|
5
|
+
|
6
|
+
a#toggle_favourite, .reveal-modal a.toggle_favourite
|
3
7
|
&.inactive
|
4
8
|
span.remove
|
5
9
|
display: none !important
|
@@ -26,6 +30,44 @@ a#toggle_favourite
|
|
26
30
|
font-size: 0.5em
|
27
31
|
margin-left: 1em
|
28
32
|
|
33
|
+
ul.favourite_entity_lists
|
34
|
+
li
|
35
|
+
ul
|
36
|
+
li:not(.title)
|
37
|
+
+clearfix()
|
38
|
+
position: relative
|
39
|
+
width: 100%
|
40
|
+
padding-right: 3em
|
41
|
+
a
|
42
|
+
min-height: 1em
|
43
|
+
display: inline-block !important
|
44
|
+
&.highlight
|
45
|
+
width: 3em !important
|
46
|
+
position: absolute
|
47
|
+
left: 0
|
48
|
+
&.active
|
49
|
+
i
|
50
|
+
color: yellow
|
51
|
+
&:not(.highlight)
|
52
|
+
position: relative
|
53
|
+
margin-left: 3em
|
54
|
+
|
55
|
+
|
56
|
+
ul.favourite_entities, ul.favourite_entity_lists, ul.favourite_entity_maps
|
57
|
+
ul.dropdown
|
58
|
+
li
|
59
|
+
@media #{ $not-small }
|
60
|
+
background: none repeat scroll 0 0 #00434C
|
61
|
+
a
|
62
|
+
@media #{ $not-small }
|
63
|
+
+ellipsis_text()
|
64
|
+
max-width: 400px
|
65
|
+
z-index: 9
|
66
|
+
&:not(.highlight):hover
|
67
|
+
white-space: normal !important
|
68
|
+
z-index: 10
|
69
|
+
|
70
|
+
|
29
71
|
//@media only screen and (max-width: 767px)
|
30
72
|
#find_wrapper
|
31
73
|
top: 9em
|
@@ -18,6 +18,13 @@
|
|
18
18
|
margin-bottom: 2em
|
19
19
|
label
|
20
20
|
margin-bottom: 1em
|
21
|
+
&.inline
|
22
|
+
+ellipsis_text()
|
23
|
+
display: inline-block
|
24
|
+
clear: top
|
25
|
+
padding: 0
|
26
|
+
margin-bottom: 0
|
27
|
+
margin-left: 0.5em
|
21
28
|
|
22
29
|
.input.submit
|
23
30
|
clear: both
|
@@ -26,5 +33,9 @@
|
|
26
33
|
select.favourite_lists
|
27
34
|
width: 175px
|
28
35
|
|
36
|
+
span.choice
|
37
|
+
margin-right: 1em
|
38
|
+
white-space: nowrap
|
39
|
+
|
29
40
|
.action_parameters form
|
30
41
|
+clearfix()
|
@@ -0,0 +1,31 @@
|
|
1
|
+
.rbbt_reveal_content
|
2
|
+
display: none !important
|
3
|
+
|
4
|
+
.reveal-modal a.toggle_favourite
|
5
|
+
&.active
|
6
|
+
i
|
7
|
+
color: #dd1 !important
|
8
|
+
&:not(.active)
|
9
|
+
i
|
10
|
+
color: black !important
|
11
|
+
|
12
|
+
.reveal-modal .header
|
13
|
+
bottom-border: 1px solid grey
|
14
|
+
.close
|
15
|
+
float: right
|
16
|
+
.title
|
17
|
+
float: left
|
18
|
+
|
19
|
+
.reveal-modal
|
20
|
+
.controls
|
21
|
+
a.link-reveal-modal
|
22
|
+
@include reveal-close()
|
23
|
+
right: 3em
|
24
|
+
font-size: 1em
|
25
|
+
top: 1.1em
|
26
|
+
|
27
|
+
&:not(.url)
|
28
|
+
.controls
|
29
|
+
a.link-reveal-modal
|
30
|
+
display: none
|
31
|
+
|