diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 44ce2ea..e44ec67 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -39,6 +39,9 @@ @plan.data_contact = current_user.email @plan.funder_name = plan_params[:funder_name] + @plan_params.visibility = (plan_params[:visibility].blank? ? Rails.application.config.default_plan_visibility : + plan_params[:visibility]) + # If a template hasn't been identified look for the available templates if plan_params[:template_id].blank? template_options(plan_params[:org_id], plan_params[:funder_id]) @@ -160,8 +163,11 @@ @plan = Plan.find(params[:id]) authorize @plan + attrs = plan_params + attrs['visibility'] = Rails.application.config.default_plan_visibility if plan_params['visibility'].blank? + respond_to do |format| - if @plan.update_attributes(params[:plan]) + if @plan.update_attributes(attrs) format.html { redirect_to @plan, :editing => false, notice: _('Plan was successfully updated.') } format.json { head :no_content } else @@ -404,11 +410,25 @@ end end end + + # AJAX access to update the plan's visibility + # POST /plans/:id + def visibility + plan = Plan.find(params[:id]) + authorize plan + plan.visibility = "#{plan_params[:visibility]}" + if plan.save + render json: {code: 1, msg: ''} + else + render json: {code: 0, msg: _("Unable to change the plan's Test status")} + end + end + private def plan_params - params.require(:plan).permit(:org_id, :org_name, :funder_id, :funder_name, :template_id, :title) + params.require(:plan).permit(:org_id, :org_name, :funder_id, :funder_name, :template_id, :title, :visibility) end # different versions of the same template have the same dmptemplate_id diff --git a/app/helpers/plans_helper.rb b/app/helpers/plans_helper.rb index 3b9b21b..d14421a 100644 --- a/app/helpers/plans_helper.rb +++ b/app/helpers/plans_helper.rb @@ -1,74 +1,4 @@ module PlansHelper - - # Build variable column headings for the project list - # -------------------------------------------------------- - def plan_list_column_heading(column) - if column.kind_of?(Array) - heading = (column.first.kind_of?(String) ? column.first : _(' - ')) - - elsif column.kind_of?(String) - heading = column - - else - heading = _(' - ') - end - - klass = (['name', 'description'].include?(heading) ? :dmp_th_big : :dmp_th_small) - - content_tag(:th, t("helpers.project.columns.#{heading}"), class: klass) # parametrised YAML keys are no longer possible with gettext, TODO - end - - # Populate a variable column for the project list - # -------------------------------------------------------- - def plan_list_column_body(column, plan) - - col = (column.kind_of?(Array) ? column[0] : column) - - klass, content = case col - when 'name' - [ "dmp_td_big", link_to(plan.title, plan_path(plan), class: "dmp_table_link") ] - when 'owner' - user = plan.owner - text = if user.nil? - _(' - ') - elsif user == current_user - _('Me') - else - user.name - end - - [ "tmp_td_small", text ] - when 'shared' - shared_num = plan.users.count - 1 - text = shared_num > 0 ? (_('Yes') + " (with #{shared_num} people) ") : _('No') # Hardcoded strings are not internationalised - [ "dmp_td_small", text ] - when 'visibility' - text = if plan.visibility == 'organisationally_visible' - _('Organisational') - elsif plan.visibility == 'publicly_visible' - _('Public') - elsif plan.visibility == 'is_test' - _('Test/Practice') - elsif plan.visibility == 'privately_visible' - _('Private') - end - ["dmp_td_small", text ] - when 'last_edited' - [ "dmp_td_small", l(plan.latest_update.to_date, formats: :short) ] - when 'description' - [ "dmp_td_medium", (plan.try(col) || _(' - ')) ] - when 'non_link_name' - [ "dmp_td_big", plan.title ] - when 'template' - ["dmp_td_big", plan.template.title] - when 'organisation' - ["dmp_td_medium", plan.template.org.name] # This will trigger 2 queries for each function call, i.e. one for templates and another for orgs tables - else - [ "dmp_td_small", (plan.try(col) || _(' - ')) ] - end - content_tag(:td, content, class: klass) - end - # Shows whether the user has default, template-default or custom settings # for the given plan. # -------------------------------------------------------- @@ -87,16 +17,20 @@ content_tag(:small, t("helpers.settings.plans.#{key}")) end - # display the role of the user for a given plan def display_role(role) - case role.access_level - when 3 - access = 'Co-owner' - when 2 - access = 'Editor' - when 1 - access = 'Read only' + if role.creator? + access = _('Owner') + + else + case role.access_level + when 3 + access = _('Co-owner') + when 2 + access = _('Editor') + when 1 + access = _('Read only') + end end return access end @@ -104,12 +38,12 @@ # display the visibility of the plan def display_visibility(val) case val - when 0 - return 'My Org.' - when 1 - return 'Public' + when 'organisationally_visible' + return _('My Inst.') + when 'publicly_visible' + return _('Public') else - return 'Private' # Both Test and Private + return _('Private') # Both Test and Private end end diff --git a/app/models/plan.rb b/app/models/plan.rb index c13ffc0..b2691ff 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -1164,7 +1164,6 @@ # Only run this before_validation because rails fires this before save/create if self.id.nil? self.title = "My plan (#{self.template.title})" if self.title.nil? && !self.template.nil? - self.visibility = 1 end end diff --git a/app/policies/plan_policy.rb b/app/policies/plan_policy.rb index 8d05ac8..e6d6d15 100644 --- a/app/policies/plan_policy.rb +++ b/app/policies/plan_policy.rb @@ -51,6 +51,10 @@ def duplicate? @plan.editable_by?(@user.id) end + + def visibility? + @plan.administerable_by?(@user.id) + end # TODO: These routes are no lonmger used =begin diff --git a/app/views/branding b/app/views/branding new file mode 120000 index 0000000..dd1660a --- /dev/null +++ b/app/views/branding @@ -0,0 +1 @@ +/Users/briley/Documents/workspace/dmptool_config/app/views/branding/ \ No newline at end of file diff --git a/app/views/plans/_plan_details.html.erb b/app/views/plans/_plan_details.html.erb index ee420d1..64cd46f 100644 --- a/app/views/plans/_plan_details.html.erb +++ b/app/views/plans/_plan_details.html.erb @@ -1,3 +1,5 @@ +<% javascript 'plans/edit.js' %> +
@@ -23,6 +25,20 @@ 'title': _('If applying for funding, state the name exactly as in the grant proposal.') %>
+ + /> +
+
+ + +
+ /> <%= _('Public anyone can view') %>
+ /> <%= _('Limited: anyone in my institution can view') %>
+ /> <%= _('Private: restricted to me and people I invite') %>
+
+ <%= f.hidden_field :visibility %> +
+
<%= f.label :identifier, _('ID') %> <%= f.text_field :identifier, class: 'input-medium has-tooltip', 'data-toggle': "tooltip", 'title': _('A pertinent ID as determined by the funder and/or institution.') %> @@ -89,6 +105,28 @@ + <%= _('Test plan') %> + <%= @plan.visibility == 'is_test' ? _('Yes') : _('No') %> + + + <%= _('Visibility') %> + + <%= + case @plan.visibility + when 'publicly_visible' + _('Public: anyone can view') + when 'organisationally_visible' + _('Limited: anyone in my institution can view') + when 'is_test' + _('Not applicable: this is a test plan') + else + _('Private: restricted to me and people I invite') + end + %> + + + + <%= _('ID') %> <% if !@plan.identifier.nil? && @plan.identifier != "" then %> diff --git a/app/views/plans/_plan_title.html.erb b/app/views/plans/_plan_title.html.erb index d134aa1..8600196 100644 --- a/app/views/plans/_plan_title.html.erb +++ b/app/views/plans/_plan_title.html.erb @@ -6,3 +6,10 @@
+ +<% if @plan.visibility == 'is_test' %> +
+ + <%= _('This is a') %> <%= _('test plan') %>. +
+<% end %> \ No newline at end of file diff --git a/app/views/plans/index.html.erb b/app/views/plans/index.html.erb index 517b17f..9d77329 100644 --- a/app/views/plans/index.html.erb +++ b/app/views/plans/index.html.erb @@ -1,5 +1,7 @@ <%- model_class = Plan -%> <% javascript "toolbar.js" %> +<% javascript "plans/index.js" %> +

<%= _('My plans') %>

@@ -15,25 +17,25 @@ - - - - - - + + + + + + <% @plans.each do |plan| %> - - - - - + + + + -
<%= _('Plan') %><%= _('Template') %><%= _('Edited') %><%= _('Role') %><%= _('Visibility') %><%= _('Test') %><%= _('Select an Action') %><%= _('Template') %><%= _('Edited') %><%= _('Role') %><%= _('Visibility') %><%= _('Test') %><%= _('Select an Action') %>
<%= plan.title %><%= plan.template.title %><%= l(plan.latest_update.to_date, formats: :short) %><%= display_role(plan.roles.find_by(user: current_user)) %><%= display_visibility(plan.visibility) %> - /> + <%= plan.template.title %><%= l(plan.latest_update.to_date, formats: :short) %><%= display_role(plan.roles.find_by(user: current_user)) %><%= display_visibility(plan.visibility) %> + <%= plan.administerable_by?(current_user.id) ? '' : 'disabled="true"' %> /> + <% if plan.editable_by?(current_user.id) then %> <%= link_to _('Edit'), plan_path(plan), :class => "dmp_table_link"%> diff --git a/app/views/plans/new.html.erb b/app/views/plans/new.html.erb index 08d44a8..ba02a8f 100644 --- a/app/views/plans/new.html.erb +++ b/app/views/plans/new.html.erb @@ -1,8 +1,15 @@ -<% javascript "plans/new_plan.js" %> +<% javascript "plans/new.js" %>

<%= _('Create a new plan') %>

+ <% if @is_test %> +
+ + <%= _('This is a') %> <%= _('test plan') %>. +
+ <% end %> +

<%= _("Before you get started, we need to ask a few questions to set you up with the best DMP template for your needs.") %>

@@ -88,7 +95,7 @@
- + <%= render partial: 'shared/accessible_submit_button', locals: {id: 'create_plan_submit', diff --git a/config/application.rb b/config/application.rb index 4392d71..3b1c1d8 100644 --- a/config/application.rb +++ b/config/application.rb @@ -87,10 +87,12 @@ answers/status.js devise/passwords/new.js devise/registrations/edit.js - plans/new_plan.js contacts/new_contact.js home/index.js orgs/shibboleth_ds.js + plans/edit.js + plans/index.js + plans/new.js shared/login_form.js shared/register_form.js) @@ -125,10 +127,10 @@ config.branding = config_for(:branding).deep_symbolize_keys # The default visibility setting for new plans - # 0 = Institutional visibility - # 1 = Public visibility - (NOT advisable because plans will show up in Public DMPs page by default) - # 2 = Test - (NOT advisable because test plans are excluded from statistics) - # 3 = Private - config.default_plan_visibility = 3 + # organisationally_visible - Any member of the user's org can view, export and duplicate the plan + # publicly_visibile - (NOT advisable because plans will show up in Public DMPs page by default) + # is_test - (NOT advisable because test plans are excluded from statistics) + # privately_visible - Only the owner and people they invite can access the plan + config.default_plan_visibility = 'organisationally_visible' end end diff --git a/config/routes.rb b/config/routes.rb index cfb0a8c..9619b82 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -208,6 +208,7 @@ post 'duplicate' get 'export' post 'invite' + post 'visibility', constraints: {format: [:json]} end collection do diff --git a/lib/assets/javascripts/plans/edit.js b/lib/assets/javascripts/plans/edit.js new file mode 100644 index 0000000..492bc3a --- /dev/null +++ b/lib/assets/javascripts/plans/edit.js @@ -0,0 +1,24 @@ +$(document).ready(function(){ + + $("#is_test").on('click, change', function(e){ + toggleVisibility(); + // If the test box is checked then update the visibility to 'is_test' + if($("#is_test").is(':checked')){ + $('#plan_visibility').val('is_test'); + }else{ + $('#plan_visibility').val(''); + } + }); + + $("input[name='visibility']").on('change', function(e){ + $('#plan_visibility').val($("input[name='visibility']:checked").val()); + }); + + toggleVisibility(); + + function toggleVisibility(){ + let test = $("#is_test").is(':checked'); + // If the test checkbox is true then disable the visibility dropdown + $("input[name='visibility']").attr('aria-disabled', test).attr('disabled', test); + } +}); \ No newline at end of file diff --git a/lib/assets/javascripts/plans/index.js b/lib/assets/javascripts/plans/index.js new file mode 100644 index 0000000..df4b4d6 --- /dev/null +++ b/lib/assets/javascripts/plans/index.js @@ -0,0 +1,19 @@ +$(document).ready(function(){ + $("input[type='checkbox']").on('click, change', function(e){ + let self = this; + let id = $(this).attr("id").replace("is_test-", ""); + let params = {plan: {visibility: $(this).is(':checked') ? 'is_test' : 'privately_visible'}}; + + // Update the visbility to test or private + $.post("/plans/" + id + "/visibility", params, function(data){ + if(data['code'] === 1){ + // If the save was successful make sure the Visibility text gets updated to 'Private' + $(self).parent().siblings("#visibility-" + id).html(__('Private')); + }else{ + // Display an error message + $("#main-page-alert").show().html(data['msg']); + e.preventDefault(); + } + }); + }); +}); \ No newline at end of file diff --git a/lib/assets/javascripts/plans/new.js b/lib/assets/javascripts/plans/new.js new file mode 100644 index 0000000..7bf6e19 --- /dev/null +++ b/lib/assets/javascripts/plans/new.js @@ -0,0 +1,65 @@ +$(document).ready(function(){ + $("#available-templates").hide(); + + // retrieve the template options and toggle the submit button on page reload + handleComboboxChange(); + handleCheckboxClick("org", $("#plan_no_org").prop("checked")); + handleCheckboxClick("funder", $("#plan_no_funder").prop("checked")); + + // When the hidden org and funder id fields change toogle the submit button + $("#plan_org_id, #plan_funder_id").change(function(){ + handleComboboxChange(); + }); + + // Make sure the checkbox is unchecked if we're entering text + $(".js-combobox").keyup(function(){ + var whichOne = $(this).prop('id').split('_')[1]; + $("#plan_no_" + whichOne).prop("checked", false); + }); + + // If the user clicks the no Org/Funder checkbox disable the dropdown + // and hide clear button + $("#plan_no_org, #plan_no_funder").click(function(){ + var whichOne = $(this).prop('id').split('_')[2]; + handleCheckboxClick(whichOne, this.checked); + }); + + $("#plan_template_id").change(function(){ + $("#create_plan_submit").attr('aria-disabled', ($(this).val().trim().length <= 0)); + }); +}); + +// Only display the submit button if the user has made each decision +// ------------------------------------------------------------- +function handleComboboxChange(){ + // If the (no_org checkbox is checked OR an org was selected) AND + // (no_funder checkbox is checked OR a funder was selected) AND + // (the template selector is not visible OR a template has been selected) + var retrieve = ($("#plan_no_org").prop("checked") || + $("#plan_org_id").val().trim().length > 0) && + ($("#plan_no_funder").prop("checked") || + $("#plan_funder_id").val().trim().length > 0); + + if(retrieve){ + if($("#plan_template_id").val().trim().length <= 0){ + $("form").submit(); + } + + }else{ + $("#available-templates").fadeOut(); + $("#plan_template_id").val(""); + } +} + +// Clear the combobox and disable it if the box was checked +// ------------------------------------------------------------- +function handleCheckboxClick(name, checked){ + $("#plan_" + name + "_name").prop("disabled", checked); + $("#plan_template_id").val("").change(); + + if(checked){ + $("#plan_" + name + "_name").val(""); + $("#plan_" + name + "_id").val("").change(); + $("#plan_" + name + "_name").siblings(".combobox-clear-button").hide(); + } +} diff --git a/lib/assets/javascripts/plans/new_plan.js b/lib/assets/javascripts/plans/new_plan.js deleted file mode 100644 index 7bf6e19..0000000 --- a/lib/assets/javascripts/plans/new_plan.js +++ /dev/null @@ -1,65 +0,0 @@ -$(document).ready(function(){ - $("#available-templates").hide(); - - // retrieve the template options and toggle the submit button on page reload - handleComboboxChange(); - handleCheckboxClick("org", $("#plan_no_org").prop("checked")); - handleCheckboxClick("funder", $("#plan_no_funder").prop("checked")); - - // When the hidden org and funder id fields change toogle the submit button - $("#plan_org_id, #plan_funder_id").change(function(){ - handleComboboxChange(); - }); - - // Make sure the checkbox is unchecked if we're entering text - $(".js-combobox").keyup(function(){ - var whichOne = $(this).prop('id').split('_')[1]; - $("#plan_no_" + whichOne).prop("checked", false); - }); - - // If the user clicks the no Org/Funder checkbox disable the dropdown - // and hide clear button - $("#plan_no_org, #plan_no_funder").click(function(){ - var whichOne = $(this).prop('id').split('_')[2]; - handleCheckboxClick(whichOne, this.checked); - }); - - $("#plan_template_id").change(function(){ - $("#create_plan_submit").attr('aria-disabled', ($(this).val().trim().length <= 0)); - }); -}); - -// Only display the submit button if the user has made each decision -// ------------------------------------------------------------- -function handleComboboxChange(){ - // If the (no_org checkbox is checked OR an org was selected) AND - // (no_funder checkbox is checked OR a funder was selected) AND - // (the template selector is not visible OR a template has been selected) - var retrieve = ($("#plan_no_org").prop("checked") || - $("#plan_org_id").val().trim().length > 0) && - ($("#plan_no_funder").prop("checked") || - $("#plan_funder_id").val().trim().length > 0); - - if(retrieve){ - if($("#plan_template_id").val().trim().length <= 0){ - $("form").submit(); - } - - }else{ - $("#available-templates").fadeOut(); - $("#plan_template_id").val(""); - } -} - -// Clear the combobox and disable it if the box was checked -// ------------------------------------------------------------- -function handleCheckboxClick(name, checked){ - $("#plan_" + name + "_name").prop("disabled", checked); - $("#plan_template_id").val("").change(); - - if(checked){ - $("#plan_" + name + "_name").val(""); - $("#plan_" + name + "_id").val("").change(); - $("#plan_" + name + "_name").siblings(".combobox-clear-button").hide(); - } -} diff --git a/lib/assets/stylesheets/roadmap-form.scss b/lib/assets/stylesheets/roadmap-form.scss index c581767..5cfa3d8 100644 --- a/lib/assets/stylesheets/roadmap-form.scss +++ b/lib/assets/stylesheets/roadmap-form.scss @@ -127,6 +127,9 @@ .input-medium { width: 30%; } + select.input-medium { + width: 32%; + } .input-small { width: 10%; } @@ -495,3 +498,19 @@ } } } + +/* Edit plan details */ +/* ------------------------------------------------ */ +.edit-plan-details form.roadmap-form fieldset.side-by-side div { + label.radio-label { + vertical-align: top; + } + + .inline-radios { + margin-left: -5px; + } + + input[type='radio'] { + margin: 0 10px 5px -5px; + } +} \ No newline at end of file diff --git a/lib/assets/stylesheets/roadmap.scss b/lib/assets/stylesheets/roadmap.scss index df82101..a54c03e 100644 --- a/lib/assets/stylesheets/roadmap.scss +++ b/lib/assets/stylesheets/roadmap.scss @@ -78,6 +78,29 @@ margin-left: 15px; } +div.roadmap-info-box { + position: absolute; + float: right; + top: 200px; + right: 12%; + background-color: $white; + padding: 8px 20px; + border-radius: 5px; + vertical-align: middle; + + span { + padding-left: 30px; + } + .fa { + position: absolute; + top: 10px; + background: transparent; + color: $black; + font-size: 16pt; + margin-right: 15px; + } +} + table.dmp_table{ width: 100%; border-collapse: separate; @@ -86,17 +109,21 @@ margin-bottom: 20px; table-layout: fixed; + thead th, tbody td { + padding: 6px 15px 6px 6px; + overflow: hidden; + } + .col-tiny { - min-width: 50px; + width: 5%; } .col-small { - min-width: 100px; + width: 10%; } .col-medium { - min-width: 150px; + width: 20%; } th.col-large { - min-width: 200px; - width: 30%; + width: 35%; } } diff --git a/test/functional/plans_controller_test.rb b/test/functional/plans_controller_test.rb index 9756da0..8507036 100644 --- a/test/functional/plans_controller_test.rb +++ b/test/functional/plans_controller_test.rb @@ -74,6 +74,7 @@ assert assigns(:orgs) assert assigns(:funders) assert assigns(:default_org) + assert assigns(:is_test) end # POST /plans (plans_path) @@ -91,6 +92,9 @@ assert_response :success assert assigns(:plan) assert_equal "Testing Create", Plan.last.title, "expected the record to have been created" + + # assert that the default visibility is used when none is specified + assert_equal Rails.application.config.default_plan_visibility, Plan.last.visibility, "Expected the plan to have been assigned the default visibility" end # GET /plan/:id (plan_path)