Closes #4000.
end
end
- Job.filter([["uuid", "in", jobs.keys]]).each do |j|
- jobs[j[:uuid]] = j
- end
+ if jobs.keys.any?
+ Job.filter([["uuid", "in", jobs.keys]]).each do |j|
+ jobs[j[:uuid]] = j
+ end
- pi.each do |pl|
- pl.components.each do |k,v|
- if v.is_a? Hash and v[:job]
- v[:job] = jobs[v[:job][:uuid]]
+ pi.each do |pl|
+ pl.components.each do |k,v|
+ if v.is_a? Hash and v[:job]
+ v[:job] = jobs[v[:job][:uuid]]
+ end
end
end
end
if opts[:friendly_name]
if attrvalue.respond_to? :friendly_link_name
- link_name = attrvalue.friendly_link_name
+ link_name = attrvalue.friendly_link_name opts[:lookup]
else
begin
if resource_class.name == 'Collection'
self.class.to_s.underscore
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
(name if self.respond_to? :name) || default_name
end
end
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
if self.respond_to? :name
self.name
else
def self.creatable?
current_user and current_user.is_admin
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
(hostname && !hostname.empty?) ? hostname : uuid
end
end
true
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
pipeline_name = self.name
if pipeline_name.nil? or pipeline_name.empty?
- template = PipelineTemplate.where(uuid: self.pipeline_template_uuid).first
+ template = if lookup and lookup[self.pipeline_template_uuid]
+ lookup[self.pipeline_template_uuid]
+ else
+ PipelineTemplate.where(uuid: self.pipeline_template_uuid).first
+ end
if template
template.name
else
(not (self.uuid.andand.match(/000000000000000$/) and self.is_admin)) and super
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
[self.first_name, self.last_name].compact.join ' '
end
{current_user_logins: {column_heading: "logins", type: 'array'}},
super]
end
- def friendly_link_name
+ def friendly_link_name lookup=nil
(hostname && !hostname.empty?) ? hostname : uuid
end
end
<div class="row">
<div class="col-md-6">
- <div class="panel panel-default" style="min-height: 10em">
+ <div class="panel panel-default" style="min-height: 10.5em">
<div class="panel-heading"><span class="panel-title">Active pipelines</span>
<span class="pull-right">
<%= link_to(
</span>
</div>
+ <% _running_pipelines = running_pipelines %>
+ <% _finished_pipelines = finished_pipelines(8) %>
+ <% lookup = preload_objects_for_dataclass PipelineTemplate, (_running_pipelines.map(&:pipeline_template_uuid) + _finished_pipelines.map(&:pipeline_template_uuid)) %>
+
<div class="panel-body">
- <% if running_pipelines.empty? %>
+ <% if _running_pipelines.empty? %>
No pipelines are currently running.
- <% end %>
- <% running_pipelines.each do |p| %>
+ <% else %>
+ <% _running_pipelines.each do |p| %>
<div class="dashboard-panel-info-row">
<div class="clearfix">
- <%= link_to_if_arvados_object p, friendly_name: true %>
+ <%= link_to_if_arvados_object p, {friendly_name: true, lookup: lookup} %>
<div class="pull-right" style="width: 40%">
<div class="progress" style="margin-bottom: 0px">
</div>
</div>
<% end %>
+ <% end %>
</div>
</div>
<div class="panel panel-default">
- <div class="panel-heading"><span class="panel-title">Recently finished pipelines</span></div>
+ <div class="panel-heading"><span class="panel-title">Recently finished pipelines</span>
+ <span class="pull-right">
+ <%= link_to pipeline_instances_path, class: 'btn btn-default btn-xs' do %>
+ All pipelines <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% end %>
+ </span>
+ </div>
<div class="panel-body">
- <% finished_pipelines(8).each do |p| %>
+ <% _finished_pipelines.each do |p| %>
<div class="dashboard-panel-info-row">
<div class="row">
<div class="col-md-6 text-overflow-ellipsis">
- <%= link_to_if_arvados_object p, friendly_name: true %>
+ <%= link_to_if_arvados_object p, {friendly_name: true, lookup: lookup} %>
</div>
<div class="col-md-2">
<%= render partial: "pipeline_status_label", locals: {p: p}%>
<% end %>
</div>
</div>
- </div>
+ </div>
</div>
<% end %>
</div>
<div class="col-md-6">
<% nodes = Node.all %>
- <div class="panel panel-default" style="min-height: 10em">
- <div class="panel-heading"><span class="panel-title">Compute status</span></div>
+ <div class="panel panel-default" style="min-height: 10.5em">
+ <div class="panel-heading"><span class="panel-title">Compute and job status</span>
+ <span class="pull-right">
+ <%= link_to jobs_path, class: 'btn btn-default btn-xs' do %>
+ All jobs <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% end %>
+ </span>
+ </div>
<div class="panel-body">
<div>
<%= render partial: 'compute_node_summary', locals: {nodes: nodes} %>
</div>
</div>
<div class="panel panel-default">
- <div class="panel-heading"><span class="panel-title">Recent collections</span></div>
+ <div class="panel-heading"><span class="panel-title">Recent collections</span>
+ <span class="pull-right">
+ <%= link_to collections_path, class: 'btn btn-default btn-xs' do %>
+ All collections <i class="fa fa-fw fa-arrow-circle-right"></i>
+ <% end %>
+ </span>
+ </div>
<div class="panel-body">
<% r = recent_collections(8) %>
<% r[:collections].each do |p| %>
<i class="fa fa-fw fa-folder-o"></i><%= link_to_if_arvados_object r[:owners][p[:owner_uuid]], friendly_name: true %>/
<span class="pull-right"><%= render_localized_date(p[:modified_at], "noseconds") %></span>
</div>
- <div class="text-overflow-ellipsis" style="margin-left: 1em; width: 100%"><%= link_to_if_arvados_object p, friendly_name: true %>
+ <div class="text-overflow-ellipsis" style="margin-left: 1em; width: 100%"><%= link_to_if_arvados_object p, {friendly_name: true, no_tags: true} %>
</div>
</div>
<% end %>
assert_not page.has_text? 'Graph'
end
+ # Create a pipeline instance from within a project and run
+ test 'Run a pipeline from dashboard' do
+ visit page_with_token('active_trustedclient')
+
+ # create a pipeline instance
+ find('.btn', text: 'Run a pipeline').click
+ within('.modal-dialog') do
+ find('.selectable', text: 'Two Part Pipeline Template').click
+ find('.btn', text: 'Next: choose inputs').click
+ end
+
+ assert find('p', text: 'Provide a value')
+
+ find('div.form-group', text: 'Foo/bar pair').
+ find('.btn', text: 'Choose').
+ click
+
+ within('.modal-dialog') do
+ assert_selector 'button.dropdown-toggle', text: 'Home'
+ wait_for_ajax
+ click_button "Home"
+ click_link "A Project"
+ wait_for_ajax
+ first('span', text: 'foo_tag').click
+ find('button', text: 'OK').click
+ end
+ wait_for_ajax
+
+ # "Run" button present and enabled
+ page.assert_no_selector 'a.disabled,button.disabled', text: 'Run'
+ first('a,button', text: 'Run').click
+
+ # Pipeline is running. We have a "Pause" button instead now.
+ page.assert_no_selector 'a,button', text: 'Run'
+ page.assert_selector 'a,button', text: 'Pause'
+
+ # Since it is test env, no jobs are created to run. So, graph not visible
+ assert_not page.has_text? 'Graph'
+ end
+
+
test 'view pipeline with job and see graph' do
visit page_with_token('active_trustedclient')
assert page.has_link?('Jobs and pipelines'), 'Jobs and pipelines link not found in project'
end
+ [["jobs", "/jobs"],
+ ["pipelines", "/pipeline_instances"],
+ ["collections", "/collections"]
+ ].each do |target,path|
+ test "Test dashboard button all #{target}" do
+ visit page_with_token 'active', '/'
+ click_link "All #{target}"
+ assert_equal path, current_path
+ end
+ end
+
end
end
end
end
- elsif c[:job][:state] == "Running"
- # Job is still running
+ elsif ["Queued", "Running"].include? c[:job][:state]
+ # Job is running or queued to run, so indicate that pipeline
+ # should continue to run
moretodo = true
elsif c[:job][:state] == "Cancelled"
debuglog "component #{cname} job #{c[:job][:uuid]} cancelled."
end
end
- c_in_state = @components.values.group_by { |c|
+ c_in_state = @components.values.group_by { |c|
c[:job] and c[:job][:state]
}
- succeeded = c_in_state["Complete"].count
- failed = c_in_state["Failed"].count + c_in_state["Cancelled"].count
+ succeeded = c_in_state["Complete"].andand.count || 0
+ failed = (c_in_state["Failed"].andand.count || 0) + (c_in_state["Cancelled"].andand.count || 0)
ended = succeeded + failed
success = (succeeded == @components.length)
logger.error "params[:ensure_unique_name] is #{params[:ensure_unique_name]}"
if params[:ensure_unique_name]
counter += 1
+ @object.uuid = nil
@object.name = "#{name_stem} (#{counter})"
retry_save = true
end
incomplete_job = nil
@objects.each do |j|
if j.nondeterministic != true and
- ((j.success == true and j.output != nil) or j.running == true) and
+ ["Queued", "Running", "Complete"].include?(j.state) and
j.script_parameters == resource_attrs[:script_parameters]
- if j.running && j.owner_uuid == current_user.uuid
+ if j.state != "Complete" && j.owner_uuid == current_user.uuid
# We'll use this if we don't find a job that has completed
incomplete_job ||= j
else
manifest_text: ". 6a4ff0499484c6c79c95cd8c566bd25f+249025 0:249025:GNU_General_Public_License,_version_3.pdf\n"
name: user_agreement
+collection_owned_by_active:
+ uuid: zzzzz-4zz18-bv31uwvy3neko21
+ portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
+ owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ created_at: 2014-02-03T17:22:54Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2014-02-03T17:22:54Z
+ updated_at: 2014-02-03T17:22:54Z
+ manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
+ name: owned_by_active
+
foo_file:
uuid: zzzzz-4zz18-znfnqtbbv4spc3w
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
}
}
assert_response 422
+ response_errors = json_response['errors']
+ assert_not_nil response_errors, 'Expected error in response'
+ assert(response_errors.first.include?('duplicate key'),
+ "Expected 'duplicate key' error in #{response_errors.first}")
end
- test "create succeeds with with duplicate name with ensure_unique_name" do
+ test "create succeeds with duplicate name with ensure_unique_name" do
permit_unsigned_manifests
- authorize_with :admin
+ authorize_with :active
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
post :create, {
collection: {
- owner_uuid: 'zzzzz-tpzed-000000000000000',
+ owner_uuid: users(:active).uuid,
manifest_text: manifest_text,
portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47",
- name: "foo_file"
+ name: "owned_by_active"
},
ensure_unique_name: true
}
assert_response :success
- resp = JSON.parse(@response.body)
- assert_equal 'foo_file (2)', resp['name']
+ assert_equal 'owned_by_active (2)', json_response['name']
end
test "create with owner_uuid set to group i can_manage" do
users(:admin).uuid,
"Current user should be included in 'writable_by' field")
end
+
+ test 'creating subproject with duplicate name fails' do
+ authorize_with :active
+ post :create, {
+ group: {
+ name: 'A Project',
+ owner_uuid: users(:active).uuid,
+ group_class: 'project',
+ },
+ }
+ assert_response 422
+ response_errors = json_response['errors']
+ assert_not_nil response_errors, 'Expected error in response'
+ assert(response_errors.first.include?('duplicate key'),
+ "Expected 'duplicate key' error in #{response_errors.first}")
+ end
+
+ test 'creating duplicate named subproject succeeds with ensure_unique_name' do
+ authorize_with :active
+ post :create, {
+ group: {
+ name: 'A Project',
+ owner_uuid: users(:active).uuid,
+ group_class: 'project',
+ },
+ ensure_unique_name: true
+ }
+ assert_response :success
+ new_project = json_response
+ assert_not_equal(new_project['uuid'],
+ groups(:aproject).uuid,
+ "create returned same uuid as existing project")
+ assert_equal(new_project['name'],
+ 'A Project (2)',
+ "new project name '#{new_project['name']}' was expected to be 'A Project (2)'")
+ end
end
"Pipeline Template with Jobspec Components.pipelineTemplate",
"collection_expires_in_future",
"collection_with_same_name_in_aproject_and_home_project",
+ "owned_by_active",
"pipeline_to_merge_params.pipelineInstance",
"pipeline_with_job.pipelineInstance",
"pipeline_with_tagged_collection_input.pipelineInstance"