From: Tom Clegg in an alert div)
- $($btn.attr('data-on-error-write')).text(errorMessage);
- // Show some elements (e.g., an alert div)
- $($btn.attr('data-on-error-show')).show();
- // Hide some elements (e.g., a success/normal div)
- $($btn.attr('data-on-error-hide')).hide();
-}).on('ajax:success', function(e) {
- var $btn = $(e.target);
- $($btn.attr('data-on-success-show')).show();
- $($btn.attr('data-on-success-hide')).hide();
-});
diff --git a/apps/workbench/app/assets/javascripts/angular_shim.js b/apps/workbench/app/assets/javascripts/angular_shim.js
deleted file mode 100644
index 5da67285b1..0000000000
--- a/apps/workbench/app/assets/javascripts/angular_shim.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-// Compile any new HTML content that was loaded via jQuery.ajax().
-// Currently this only works for tabs, and only because they emit an
-// arv:pane:loaded event after updating the DOM.
-
-$(document).on('arv:pane:loaded', function(event, $updatedElement) {
- if (angular && $updatedElement && angular.element($updatedElement).injector()) {
- angular.element($updatedElement).injector().invoke([
- '$compile', function($compile) {
- var scope = angular.element($updatedElement).scope();
- $compile($updatedElement)(scope);
- }]);
- }
-});
diff --git a/apps/workbench/app/assets/javascripts/application.js b/apps/workbench/app/assets/javascripts/application.js
deleted file mode 100644
index 1898128133..0000000000
--- a/apps/workbench/app/assets/javascripts/application.js
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-//
-// This is a manifest file that'll be compiled into application.js, which will include all the files
-// listed below.
-//
-// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
-// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
-//
-// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// the compiled file.
-//
-// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
-// GO AFTER THE REQUIRES BELOW.
-//
-//= require jquery
-//= require jquery_ujs
-//= require bootstrap
-//= require bootstrap/dropdown
-//= require bootstrap/tab
-//= require bootstrap/tooltip
-//= require bootstrap/popover
-//= require bootstrap/collapse
-//= require bootstrap/modal
-//= require bootstrap/button
-//= require bootstrap3-editable/bootstrap-editable
-//= require bootstrap-tab-history
-//= require angular
-//= require raphael
-//= require morris
-//= require jquery.number.min
-//= require npm-dependencies
-//= require mithril/stream/stream
-//= require awesomplete
-//= require jssha
-//= require_tree .
-
-Es6ObjectAssign.polyfill()
-window.m = Object.assign(window.Mithril, {stream: window.m.stream})
-
-jQuery(function($){
- $(document).ajaxStart(function(){
- $('.modal-with-loading-spinner .spinner').show();
- }).ajaxStop(function(){
- $('.modal-with-loading-spinner .spinner').hide();
- });
-
- $('[data-toggle=tooltip]').tooltip();
-
- $('.expand-collapse-row').on('click', function(event) {
- var targets = $('#' + $(this).attr('data-id'));
- if (targets.css('display') == 'none') {
- $(this).addClass('icon-minus-sign');
- $(this).removeClass('icon-plus-sign');
- } else {
- $(this).addClass('icon-plus-sign');
- $(this).removeClass('icon-minus-sign');
- }
- targets.fadeToggle(200);
- });
-
- var ajaxCount = 0;
-
- $(document).
- on('ajax:send', function(e, xhr) {
- ajaxCount += 1;
- if (ajaxCount == 1) {
- $('.loading').fadeTo('fast', 1);
- }
- }).
- on('ajax:complete', function(e, status) {
- ajaxCount -= 1;
- if (ajaxCount == 0) {
- $('.loading').fadeOut('fast', 0);
- }
- }).
- on('ajaxSend', function(e, xhr) {
- // jQuery triggers 'ajaxSend' event when starting an ajax call, but
- // rails-generated ajax triggers generate 'ajax:send'. Workbench
- // event listeners currently expect 'ajax:send', so trigger the
- // rails event in response to the jQuery one.
- $(document).trigger('ajax:send');
- }).
- on('ajaxComplete', function(e, xhr) {
- // See comment above about ajaxSend/ajax:send
- $(document).trigger('ajax:complete');
- }).
- on('click', '.removable-tag a', function(e) {
- var tag_span = $(this).parents('[data-tag-link-uuid]').eq(0)
- tag_span.fadeTo('fast', 0.2);
- $.ajax('/links/' + tag_span.attr('data-tag-link-uuid'),
- {dataType: 'json',
- type: 'POST',
- data: { '_method': 'DELETE' },
- context: tag_span}).
- done(function(data, status, jqxhr) {
- this.remove();
- }).
- fail(function(jqxhr, status, error) {
- this.addClass('label-danger').fadeTo('fast', '1');
- });
- return false;
- }).
- on('click', 'a.add-tag-button', function(e) {
- var jqxhr;
- var new_tag_uuid = 'new-tag-' + Math.random();
- var tag_head_uuid = $(this).parents('tr').attr('data-object-uuid');
- var new_tag = window.prompt("Add tag for collection "+
- tag_head_uuid,
- "");
- if (new_tag == null)
- return false;
- var new_tag_span =
- $('').
- attr('data-tag-link-uuid', new_tag_uuid).
- text(new_tag).
- css('opacity', '0.2').
- append(' ');
- $(this).
- parent().
- find('>span').
- append(new_tag_span).
- append(' ');
- $.ajax($(this).attr('data-remote-href'),
- {dataType: 'json',
- type: $(this).attr('data-remote-method'),
- data: {
- 'link[head_uuid]': tag_head_uuid,
- 'link[link_class]': 'tag',
- 'link[name]': new_tag
- },
- context: new_tag_span}).
- done(function(data, status, jqxhr) {
- this.attr('data-tag-link-uuid', data.uuid).
- fadeTo('fast', '1');
- }).
- fail(function(jqxhr, status, error) {
- this.addClass('label-danger').fadeTo('fast', '1');
- });
- return false;
- }).
- on('click focusin', 'input.select-on-focus', function(event) {
- event.target.select();
- });
-
- $(document).
- on('ajax:complete ready', function() {
- // See http://getbootstrap.com/javascript/#buttons
- $('.btn').button();
- }).
- on('ready ajax:complete', function() {
- $('[data-toggle~=tooltip]').tooltip({container:'body'});
- }).
- on('ready ajax:complete', function() {
- // This makes the dialog close on Esc key, obviously.
- $('.modal').attr('tabindex', '-1')
- }).
- on('ready', function() {
- // Need this to trigger input validation/synchronization callbacks because some browsers
- // auto-fill form fields (e.g., when navigating "back" to a page where some text
- // had been entered in a search box) without triggering a change or input event.
- $('input').each(function(el) {
- $(el).trigger($.Event('input', {currentTarget: el}));
- });
- });
-
- HeaderRowFixer = function(selector) {
- this.duplicateTheadTr = function() {
- $(selector).each(function() {
- var the_table = this;
- if ($('>tbody>tr:first>th', the_table).length > 0)
- return;
- $('>tbody', the_table).
- prepend($('>thead>tr', the_table).
- clone().
- css('opacity', 0));
- });
- }
- this.fixThead = function() {
- $(selector).each(function() {
- var widths = [];
- $('> tbody > tr:eq(1) > td', this).each( function(i,v){
- widths.push($(v).width());
- });
- for(i=0;i ";
- html += "Started at " + first.values().timestamp + ". ";
- html += "Ran " + dumbPluralize(tcount, " task") + " over ";
- if (hours > 0) {
- html += dumbPluralize(hours, " hour");
- }
- if (minutes > 0) {
- html += " " + dumbPluralize(minutes, " minute");
- }
- if (seconds > 0) {
- html += " " + dumbPluralize(seconds, " second");
- }
-
- html += " using " + dumbPluralize(taskState.nodes.length, " node");
-
- html += ". " + dumbPluralize(taskState.complete_count, "task") + " completed";
- html += ", " + dumbPluralize(taskState.incomplete_count, "task") + " incomplete";
- html += " (" + dumbPluralize(taskState.failure_count, " failure") + ")";
-
- html += ". Finished at " + last.values().timestamp + ".";
- html += " Job log is empty or failed to load. ' +
- '' +
- ' ' +
- 'Reload tab Sorry, request failed.
-$ sudo apt-get install iceweasel xvfb
-
-
-If you install the Workbench Bundle in deployment mode, you must also install the API server Bundle in deployment mode, and vice versa. If your Bundle installs have mismatched modes, the integration tests will fail with "Gem not found" errors.
-
-h2. Writing tests
-
-Integration tests are written with Capybara, which drives a fully-featured Web browser to interact with Workbench exactly as a user would.
-
-If your test requires JavaScript support, your test method should start with the line @Capybara.current_driver = Capybara.javascript_driver@. Otherwise, Capybara defaults to a simpler browser for speed.
-
-In most tests, you can directly call "Capybara's Session methods":http://rubydoc.info/github/jnicklas/capybara/Capybara/Session to drive the browser and check its state. If you need finer-grained control, refer to the "full Capybara documentation":http://rubydoc.info/github/jnicklas/capybara/Capybara.
diff --git a/apps/workbench/Rakefile b/apps/workbench/Rakefile
deleted file mode 100644
index 037f9013ac..0000000000
--- a/apps/workbench/Rakefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env rake
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-# Add your own tasks in files placed in lib/tasks ending in .rake,
-# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
-
-require File.expand_path('../config/application', __FILE__)
-
-ArvadosWorkbench::Application.load_tasks
diff --git a/apps/workbench/app/assets/images/dax.png b/apps/workbench/app/assets/images/dax.png
deleted file mode 100644
index c511f0ec51..0000000000
Binary files a/apps/workbench/app/assets/images/dax.png and /dev/null differ
diff --git a/apps/workbench/app/assets/images/mouse-move.gif b/apps/workbench/app/assets/images/mouse-move.gif
deleted file mode 100644
index 497b1596dc..0000000000
Binary files a/apps/workbench/app/assets/images/mouse-move.gif and /dev/null differ
diff --git a/apps/workbench/app/assets/images/pipeline-running.gif b/apps/workbench/app/assets/images/pipeline-running.gif
deleted file mode 100644
index 64e9009133..0000000000
Binary files a/apps/workbench/app/assets/images/pipeline-running.gif and /dev/null differ
diff --git a/apps/workbench/app/assets/images/rails.png b/apps/workbench/app/assets/images/rails.png
deleted file mode 100644
index d5edc04e65..0000000000
Binary files a/apps/workbench/app/assets/images/rails.png and /dev/null differ
diff --git a/apps/workbench/app/assets/images/spinner_32px.gif b/apps/workbench/app/assets/images/spinner_32px.gif
deleted file mode 100644
index 3288d1035d..0000000000
Binary files a/apps/workbench/app/assets/images/spinner_32px.gif and /dev/null differ
diff --git a/apps/workbench/app/assets/images/trash-icon.png b/apps/workbench/app/assets/images/trash-icon.png
deleted file mode 100644
index 5c26c2450d..0000000000
Binary files a/apps/workbench/app/assets/images/trash-icon.png and /dev/null differ
diff --git a/apps/workbench/app/assets/javascripts/add_group.js b/apps/workbench/app/assets/javascripts/add_group.js
deleted file mode 100644
index 23de53d408..0000000000
--- a/apps/workbench/app/assets/javascripts/add_group.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-$(document).on('shown.bs.modal', '#add-group-modal', function(event) {
- // Disable the submit button on modal loading
- $submit = $('#add-group-submit');
- $submit.prop('disabled', true);
-
- $('input[type=text]', event.target).val('');
- $('#add-group-error', event.target).hide();
-}).on('input propertychange', '#group_name_input', function(event) {
- group_name = $(event.target).val();
- $submit = $('#add-group-submit');
- $submit.prop('disabled', (group_name === null || group_name === ""));
-}).on('submit', '#add-group-form', function(event) {
- var $form = $(event.target),
- $submit = $(':submit', $form),
- $error = $('#add-group-error', $form),
- group_name = $('input[name="group_name_input"]', $form).val();
-
- $submit.prop('disabled', true);
-
- $error.hide();
- $.ajax('/groups',
- {method: 'POST',
- dataType: 'json',
- data: {group: {name: group_name, group_class: 'role'}},
- context: $form}).
- done(function(data, status, jqxhr) {
- location.reload();
- }).
- fail(function(jqxhr, status, error) {
- var errlist = jqxhr.responseJSON.errors;
- var errmsg;
- if (Array.isArray(errlist)) {
- errmsg = errlist.join();
- } else {
- errmsg = ("The server returned an error when creating " +
- "this group (status " + jqxhr.status +
- ": " + errlist + ").");
- }
- $error.text(errmsg);
- $error.show();
- $submit.prop('disabled', false);
- });
- return false;
-});
diff --git a/apps/workbench/app/assets/javascripts/add_repository.js b/apps/workbench/app/assets/javascripts/add_repository.js
deleted file mode 100644
index efcd19d32a..0000000000
--- a/apps/workbench/app/assets/javascripts/add_repository.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-$(document).on('shown.bs.modal', '#add-repository-modal', function(event) {
- $('input[type=text]', event.target).val('');
- $('#add-repository-error', event.target).hide();
-}).on('submit', '#add-repository-form', function(event) {
- var $form = $(event.target),
- $submit = $(':submit', $form),
- $error = $('#add-repository-error', $form),
- repo_owner_uuid = $('input[name="add_repo_owner_uuid"]', $form).val(),
- repo_prefix = $('input[name="add_repo_prefix"]', $form).val(),
- repo_basename = $('input[name="add_repo_basename"]', $form).val();
-
- $submit.prop('disabled', true);
- $error.hide();
- $.ajax('/repositories',
- {method: 'POST',
- dataType: 'json',
- data: {repository: {owner_uuid: repo_owner_uuid,
- name: repo_prefix + repo_basename}},
- context: $form}).
- done(function(data, status, jqxhr) {
- location.reload();
- }).
- fail(function(jqxhr, status, error) {
- var errlist = jqxhr.responseJSON.errors;
- var errmsg;
- if (Array.isArray(errlist)) {
- errmsg = errlist.join();
- } else {
- errmsg = ("The server returned an error when making " +
- "this repository (status " + jqxhr.status +
- ": " + errlist + ").");
- }
- $error.text(errmsg);
- $error.show();
- $submit.prop('disabled', false);
- });
- return false;
-});
diff --git a/apps/workbench/app/assets/javascripts/ajax_error.js b/apps/workbench/app/assets/javascripts/ajax_error.js
deleted file mode 100644
index dd31cc6dbc..0000000000
--- a/apps/workbench/app/assets/javascripts/ajax_error.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-$(document).on('ajax:error', function(e, xhr, status, error) {
- var errorMessage = '' + status + ': ' + error;
- // $btn is the element (button/link) that initiated the failed request.
- var $btn = $(e.target);
- // Populate some elements with the error text (e.g., a ');
- }
- $container.find(".spinner").detach();
- $container.append(spinner);
- $container.data('data-infinite-serial', serial);
-
- if (src == $container.attr('data-infinite-content-href0')) {
- // If we're loading the first page, collect filters from
- // various sources.
- params = mergeInfiniteContentParams($container);
- $.each(params, function(k,v) {
- if (v instanceof Object) {
- params[k] = JSON.stringify(v);
- }
- });
- } else {
- // If we're loading page >1, ignore other filtering
- // mechanisms and just use the "next page" URI from the
- // previous page's response. Aside from avoiding race
- // conditions (where page 2 could have different filters
- // than page 1), this allows the server to use filters in
- // the "next page" URI to achieve paging. (To apply any
- // new filters effectively, we need to load page 1 again
- // anyway.)
- params = {};
- }
-
- $.ajax(src,
- {dataType: 'json',
- type: 'GET',
- data: params,
- context: {container: $container, src: src, serial: serial}}).
- fail(function(jqxhr, status, error) {
- var $faildiv;
- var $container = this.container;
- if ($container.data('data-infinite-serial') != this.serial) {
- // A newer request is already in progress.
- return;
- }
- if (jqxhr.readyState == 0 || jqxhr.status == 0) {
- message = "Cancelled.";
- } else if (jqxhr.responseJSON && jqxhr.responseJSON.errors) {
- message = jqxhr.responseJSON.errors.join("; ");
- } else {
- message = "Request failed.";
- }
- // TODO: report the message to the user.
- console.log(message);
- $faildiv = $('').
- attr('data-infinite-content-href', this.src).
- addClass('infinite-retry').
- append(' Oops, request failed. ');
- $container.find('div.spinner').replaceWith($faildiv);
- }).
- done(function(data, status, jqxhr) {
- if ($container.data('data-infinite-serial') != this.serial) {
- // A newer request is already in progress.
- return;
- }
- $container.find(".spinner").detach();
- $container.append(data.content);
- $container.attr('data-infinite-content-href', data.next_page_href);
- ping_all_scrollers();
- });
- }
-}
-
-function ping_all_scrollers() {
- // Send a scroll event to all scroll listeners that might need
- // updating. Adding infinite-scroller class to the window element
- // doesn't work, so we add it explicitly here.
- $('.infinite-scroller').add(window).trigger('scroll');
-}
-
-function mergeInfiniteContentParams($container) {
- var params = {};
- // Combine infiniteContentParams from multiple sources. This
- // mechanism allows each of several components to set and
- // update its own set of filters, without having to worry
- // about stomping on some other component's filters.
- //
- // For example, filterable.js writes filters in
- // infiniteContentParamsFilterable ("search for text foo")
- // without worrying about clobbering the filters set up by the
- // tab pane ("only show container requests and pipeline instances
- // in this tab").
- $.each($container.data(), function(datakey, datavalue) {
- // Note: We attach these data to DOM elements using
- // ' +
- spinner +
- '
') + span_tag
- else
- span_tag + ' ' + edit_button
- end
- end
-
- def render_pipeline_component_attribute(object, attr, subattr, value_info, htmloptions={})
- datatype = nil
- required = true
- attrvalue = value_info
-
- if value_info.is_a? Hash
- if value_info[:output_of]
- return raw("#{value_info[:output_of]}")
- end
- if value_info[:dataclass]
- dataclass = value_info[:dataclass]
- end
- if value_info[:optional] != nil
- required = (value_info[:optional] != "true")
- end
- if value_info[:required] != nil
- required = value_info[:required]
- end
-
- # Pick a suitable attrvalue to show as the current value (i.e.,
- # the one that would be used if we ran the pipeline right now).
- if value_info[:value]
- attrvalue = value_info[:value]
- elsif value_info[:default]
- attrvalue = value_info[:default]
- else
- attrvalue = ''
- end
- preconfigured_search_str = value_info[:search_for]
- end
-
- if not object.andand.attribute_editable?(attr)
- return link_to_arvados_object_if_readable(attrvalue, attrvalue, {friendly_name: true, required: required})
- end
-
- if dataclass
- begin
- dataclass = dataclass.constantize
- rescue NameError
- end
- else
- dataclass = ArvadosBase.resource_class_for_uuid(attrvalue)
- end
-
- id = "#{object.uuid}-#{subattr.join('-')}"
- dn = "[#{attr}]"
- subattr.each do |a|
- dn += "[#{a}]"
- end
- if value_info.is_a? Hash
- dn += '[value]'
- end
-
- if (dataclass == Collection) or (dataclass == File)
- selection_param = object.class.to_s.underscore + dn
- display_value = attrvalue
- if value_info.is_a?(Hash)
- if (link = Link.find? value_info[:link_uuid])
- display_value = link.name
- elsif value_info[:link_name]
- display_value = value_info[:link_name]
- elsif (sn = value_info[:selection_name]) && sn != ""
- display_value = sn
- end
- end
- if (attr == :components) and (subattr.size > 2)
- chooser_title = "Choose a #{dataclass == Collection ? 'dataset' : 'file'} for #{object.component_input_title(subattr[0], subattr[2])}:"
- else
- chooser_title = "Choose a #{dataclass == Collection ? 'dataset' : 'file'}:"
- end
- modal_path = choose_collections_path \
- ({ title: chooser_title,
- filters: [['owner_uuid', '=', object.owner_uuid]].to_json,
- action_name: 'OK',
- action_href: pipeline_instance_path(id: object.uuid),
- action_method: 'patch',
- preconfigured_search_str: (preconfigured_search_str || ""),
- action_data: {
- merge: true,
- use_preview_selection: dataclass == File ? true : nil,
- selection_param: selection_param,
- success: 'page-refresh'
- }.to_json,
- })
-
- return content_tag('div', :class => 'input-group') do
- html = text_field_tag(dn, display_value,
- :class =>
- "form-control #{'required' if required} #{'unreadable-input' if attrvalue.present? and !object_readable(attrvalue, Collection)}")
- html + content_tag('span', :class => 'input-group-btn') do
- link_to('Choose',
- modal_path,
- { :class => "btn btn-primary",
- :remote => true,
- :method => 'get',
- })
- end
- end
- end
-
- if attrvalue.is_a? String
- datatype = 'text'
- elsif attrvalue.is_a?(Array) or dataclass.andand.is_a?(Class)
- # TODO: find a way to edit with x-editable
- return attrvalue
- end
-
- # When datatype is a String or Fixnum, link_to the attrvalue
- lt = link_to attrvalue, '#', {
- "data-emptytext" => "none",
- "data-placement" => "bottom",
- "data-type" => datatype,
- "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
- "data-title" => "Set value for #{subattr[-1].to_s}",
- "data-name" => dn,
- "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
- "data-value" => attrvalue,
- # "clear" button interferes with form-control's up/down arrows
- "data-clear" => false,
- :class => "editable #{'required' if required} form-control",
- :id => id
- }.merge(htmloptions)
-
- lt
- end
-
- def get_cwl_main(workflow)
- if workflow[:"$graph"].nil?
- return workflow
- else
- workflow[:"$graph"].each do |tool|
- if tool[:id] == "#main"
- return tool
- end
- end
- end
- end
-
- def get_cwl_inputs(workflow)
- get_cwl_main(workflow)[:inputs]
- end
-
-
- def cwl_shortname(id)
- if id[0] == "#"
- id = id[1..-1]
- end
- return id.split("/")[-1]
- end
-
- def cwl_input_info(input_schema)
- required = !(input_schema[:type].include? "null")
- if input_schema[:type].is_a? Array
- primary_type = input_schema[:type].select { |n| n != "null" }[0]
- elsif input_schema[:type].is_a? String
- primary_type = input_schema[:type]
- elsif input_schema[:type].is_a? Hash
- primary_type = input_schema[:type]
- end
- param_id = cwl_shortname(input_schema[:id])
- return required, primary_type, param_id
- end
-
- def cwl_input_value(object, input_schema, set_attr_path)
- dn = ""
- attrvalue = object
- set_attr_path.each do |a|
- dn += "[#{a}]"
- attrvalue = attrvalue[a.to_sym]
- end
- return dn, attrvalue
- end
-
- def cwl_inputs_required(object, inputs_schema, set_attr_path)
- r = 0
- inputs_schema.each do |input|
- required, _, param_id = cwl_input_info(input)
- _, attrvalue = cwl_input_value(object, input, set_attr_path + [param_id])
- r += 1 if required and attrvalue.nil?
- end
- r
- end
-
- def render_cwl_input(object, input_schema, set_attr_path, htmloptions={})
- required, primary_type, param_id = cwl_input_info(input_schema)
-
- dn, attrvalue = cwl_input_value(object, input_schema, set_attr_path + [param_id])
- attrvalue = if attrvalue.nil? then "" else attrvalue end
-
- id = "#{object.uuid}-#{param_id}"
-
- opt_empty_selection = if required then [] else [{value: "", text: ""}] end
-
- if ["Directory", "File"].include? primary_type
- chooser_title = "Choose a #{primary_type == 'Directory' ? 'dataset' : 'file'}:"
- selection_param = object.class.to_s.underscore + dn
- if attrvalue.is_a? Hash
- display_value = attrvalue[:"http://arvados.org/cwl#collectionUUID"] || attrvalue[:"arv:collection"] || attrvalue[:location]
- re = CollectionsHelper.match_uuid_with_optional_filepath(display_value)
- locationre = CollectionsHelper.match(attrvalue[:location][5..-1])
- if re
- if locationre and locationre[4]
- display_value = "#{Collection.find(re[1]).name} / #{locationre[4][1..-1]}"
- else
- display_value = Collection.find(re[1]).name
- end
- end
- end
- modal_path = choose_collections_path \
- ({ title: chooser_title,
- filters: [['owner_uuid', '=', object.owner_uuid]].to_json,
- action_name: 'OK',
- action_href: container_request_path(id: object.uuid),
- action_method: 'patch',
- preconfigured_search_str: "",
- action_data: {
- merge: true,
- use_preview_selection: primary_type == 'File' ? true : nil,
- selection_param: selection_param,
- success: 'page-refresh'
- }.to_json,
- })
-
- return content_tag('div', :class => 'input-group') do
- html = text_field_tag(dn, display_value,
- :class =>
- "form-control #{'required' if required}")
- html + content_tag('span', :class => 'input-group-btn') do
- link_to('Choose',
- modal_path,
- { :class => "btn btn-primary",
- :remote => true,
- :method => 'get',
- })
- end
- end
- elsif "boolean" == primary_type
- return link_to attrvalue.to_s, '#', {
- "data-emptytext" => "none",
- "data-placement" => "bottom",
- "data-type" => "select",
- "data-source" => (opt_empty_selection + [{value: "true", text: "true"}, {value: "false", text: "false"}]).to_json,
- "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
- "data-title" => "Set value for #{cwl_shortname(input_schema[:id])}",
- "data-name" => dn,
- "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
- "data-value" => attrvalue.to_s,
- # "clear" button interferes with form-control's up/down arrows
- "data-clear" => false,
- :class => "editable #{'required' if required} form-control",
- :id => id
- }.merge(htmloptions)
- elsif primary_type.is_a? Hash and primary_type[:type] == "enum"
- return link_to attrvalue, '#', {
- "data-emptytext" => "none",
- "data-placement" => "bottom",
- "data-type" => "select",
- "data-source" => (opt_empty_selection + primary_type[:symbols].map {|i| {:value => cwl_shortname(i), :text => cwl_shortname(i)} }).to_json,
- "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
- "data-title" => "Set value for #{cwl_shortname(input_schema[:id])}",
- "data-name" => dn,
- "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
- "data-value" => attrvalue,
- # "clear" button interferes with form-control's up/down arrows
- "data-clear" => false,
- :class => "editable #{'required' if required} form-control",
- :id => id
- }.merge(htmloptions)
- elsif primary_type.is_a? String
- if ["int", "long"].include? primary_type
- datatype = "number"
- else
- datatype = "text"
- end
-
- return link_to attrvalue, '#', {
- "data-emptytext" => "none",
- "data-placement" => "bottom",
- "data-type" => datatype,
- "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
- "data-title" => "Set value for #{cwl_shortname(input_schema[:id])}",
- "data-name" => dn,
- "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
- "data-value" => attrvalue,
- # "clear" button interferes with form-control's up/down arrows
- "data-clear" => false,
- :class => "editable #{'required' if required} form-control",
- :id => id
- }.merge(htmloptions)
- else
- return "Unable to render editing control for parameter type #{primary_type}"
- end
- end
-
- def render_arvados_object_list_start(list, button_text, button_href,
- params={}, *rest, &block)
- show_max = params.delete(:show_max) || 3
- params[:class] ||= 'btn btn-xs btn-default'
- list[0...show_max].each { |item| yield item }
- unless list[show_max].nil?
- link_to(h(button_text) +
- raw(' '),
- button_href, params, *rest)
- end
- end
-
- def render_controller_partial partial, opts
- cname = opts.delete :controller_name
- begin
- render opts.merge(partial: "#{cname}/#{partial}")
- rescue ActionView::MissingTemplate
- render opts.merge(partial: "application/#{partial}")
- end
- end
-
- RESOURCE_CLASS_ICONS = {
- "Collection" => "fa-archive",
- "ContainerRequest" => "fa-gears",
- "Group" => "fa-users",
- "Human" => "fa-male", # FIXME: Use a more inclusive icon.
- "Job" => "fa-gears",
- "KeepDisk" => "fa-hdd-o",
- "KeepService" => "fa-exchange",
- "Link" => "fa-arrows-h",
- "Node" => "fa-cloud",
- "PipelineInstance" => "fa-gears",
- "PipelineTemplate" => "fa-gears",
- "Repository" => "fa-code-fork",
- "Specimen" => "fa-flask",
- "Trait" => "fa-clipboard",
- "User" => "fa-user",
- "VirtualMachine" => "fa-terminal",
- "Workflow" => "fa-gears",
- }
- DEFAULT_ICON_CLASS = "fa-cube"
-
- def fa_icon_class_for_class(resource_class, default=DEFAULT_ICON_CLASS)
- RESOURCE_CLASS_ICONS.fetch(resource_class.to_s, default)
- end
-
- def fa_icon_class_for_uuid(uuid, default=DEFAULT_ICON_CLASS)
- fa_icon_class_for_class(resource_class_for_uuid(uuid), default)
- end
-
- def fa_icon_class_for_object(object, default=DEFAULT_ICON_CLASS)
- case class_name = object.class.to_s
- when "Group"
- object.group_class ? 'fa-folder' : 'fa-users'
- else
- RESOURCE_CLASS_ICONS.fetch(class_name, default)
- end
- end
-
- def chooser_preview_url_for object, use_preview_selection=false
- case object.class.to_s
- when 'Collection'
- polymorphic_path(object, tab_pane: 'chooser_preview', use_preview_selection: use_preview_selection)
- else
- nil
- end
- end
-
- def render_attribute_as_textile( object, attr, attrvalue, truncate )
- if attrvalue && (is_textile? object, attr)
- markup = render_markup attrvalue
- markup = markup[0,markup.index('
One or more inputs provided are not readable by you. ' + - 'Please correct these before you can run the pipeline.