diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index caac402..43e0982 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -38,9 +38,13 @@ def create @plan = Plan.new authorize @plan - + @plan.principal_investigator = current_user.surname.blank? ? nil : "#{current_user.firstname} #{current_user.surname}" - @plan.data_contact = current_user.email + @plan.principal_investigator_email = current_user.email + + orcid = current_user.identifier_for(IdentifierScheme.find_by(name: 'orcid')) + @plan.principal_investigator_identifier = orcid.identifier unless orcid.nil? + @plan.funder_name = plan_params[:funder_name] @plan.visibility = (plan_params['visibility'].blank? ? Rails.application.config.default_plan_visibility : @@ -81,15 +85,15 @@ if !default.nil? && default == @plan.template # We used the generic/default template - msg += _('This plan is based on the default template.') + msg += " #{_('This plan is based on the default template.')}" elsif !@plan.template.customization_of.nil? # We used a customized version of the the funder template - msg += "#{_('This plan is based on the')} #{plan_params[:funder_name]} #{_('template with customisations by the')} #{plan_params[:org_name]}" + msg += " #{_('This plan is based on the')} #{plan_params[:funder_name]} #{_('template with customisations by the')} #{plan_params[:org_name]}" else # We used the specified org's or funder's template - msg += "#{_('This plan is based on the')} #{@plan.template.org.name} template." + msg += " #{_('This plan is based on the')} #{@plan.template.org.name} template." end flash[:notice] = msg @@ -122,7 +126,8 @@ # Get all Guidance Groups applicable for the plan and group them by org @all_guidance_groups = @plan.get_guidance_group_options @all_ggs_grouped_by_org = @all_guidance_groups.sort.group_by(&:org) - + @selected_guidance_groups = @plan.guidance_groups + # Important ones come first on the page - we grab the user's org's GGs and "Organisation" org type GGs @important_ggs = [] @important_ggs << [current_user.org, @all_ggs_grouped_by_org.delete(current_user.org)] @@ -131,65 +136,24 @@ @important_ggs << [org,ggs] @all_ggs_grouped_by_org.delete(org) end - end - - # Sort the rest by org name for the accordion - @all_ggs_grouped_by_org = @all_ggs_grouped_by_org.sort_by {|org,gg| org.name} - - @selected_guidance_groups = @plan.guidance_groups.pluck(:id) - @based_on = (@plan.template.customization_of.nil? ? @plan.template : Template.where(dmptemplate: @plan.template.customization_of).first) - - respond_to :html - end - - - # we can go into this with the user able to edit or not able to edit - # the same edit form gets rendered but then different partials get used - # to render the answers depending on whether it is readonly or not - # - # we may or may not have a phase param. - # if we have none then we are editing/displaying the plan details - # if we have a phase then we are editing that phase. - # - # GET /plans/1/edit - def edit - @plan = Plan.find(params[:id]) - authorize @plan - - @visibility = @plan.visibility.present? ? @plan.visibility.to_s : Rails.application.config.default_plan_visibility - - # If there was no phase specified use the template's 1st phase - @phase = (params[:phase].nil? ? @plan.template.phases.first : Phase.find(params[:phase])) - @show_phase_tab = params[:phase] - @readonly = !@plan.editable_by?(current_user.id) - - # Get all Guidance Groups applicable for the plan and group them by org - @all_guidance_groups = @plan.get_guidance_group_options - @all_ggs_grouped_by_org = @all_guidance_groups.sort.group_by(&:org) - - # Important ones come first on the page - we grab the user's org's GGs and "Organisation" org type GGs - @important_ggs = [] - @important_ggs << [current_user.org, @all_ggs_grouped_by_org.delete(current_user.org)] - @all_ggs_grouped_by_org.each do |org, ggs| - if org.organisation? - @important_ggs << [org,ggs] + + # If this is one of the already selected guidance groups its important! + if !(ggs & @selected_guidance_groups).empty? + @important_ggs << [org,ggs] unless @important_ggs.include?([org,ggs]) @all_ggs_grouped_by_org.delete(org) end end # Sort the rest by org name for the accordion - @all_ggs_grouped_by_org = @all_ggs_grouped_by_org.sort_by {|org,gg| org.name} - - @selected_guidance_groups = @plan.guidance_groups.pluck(:id) + @important_ggs = @important_ggs.sort_by{|org,gg| (org.nil? ? '' : org.name)} + @all_ggs_grouped_by_org = @all_ggs_grouped_by_org.sort_by {|org,gg| (org.nil? ? '' : org.name)} + @selected_guidance_groups = @selected_guidance_groups.collect{|gg| gg.id} + @based_on = (@plan.template.customization_of.nil? ? @plan.template : Template.where(dmptemplate: @plan.template.customization_of).first) - flash[:notice] = "#{_('This is a')} #{_('test plan')}" if params[:test] - @is_test = params[:test] ||= false - respond_to :html end - # PUT /plans/1 # PUT /plans/1.json def update @@ -197,6 +161,10 @@ authorize @plan attrs = plan_params + # Save the guidance group selections + guidance_group_ids = params[:guidance_group_ids].blank? ? [] : params[:guidance_group_ids].map(&:to_i) + save_guidance_selections(guidance_group_ids) + respond_to do |format| if @plan.update_attributes(attrs) format.html { redirect_to @plan, :editing => false, notice: success_message(_('plan'), _('saved')) } @@ -207,37 +175,12 @@ end end end - - - - def update_guidance_choices - @plan = Plan.find(params[:id]) - authorize @plan - guidance_group_ids = params[:guidance_group_ids].blank? ? [] : params[:guidance_group_ids].map(&:to_i) - all_guidance_groups = @plan.get_guidance_group_options - plan_groups = @plan.guidance_groups - guidance_groups = GuidanceGroup.where( id: guidance_group_ids) - all_guidance_groups.each do |group| - # case where plan group exists but not in selection - if plan_groups.include?(group) && ! guidance_groups.include?(group) - # remove from plan groups - @plan.guidance_groups.delete(group) - end - # case where plan group dosent exist and in selection - if !plan_groups.include?(group) && guidance_groups.include?(group) - # add to plan groups - @plan.guidance_groups << group - end - end - @plan.save - flash[:notice] = success_message(_('guidance choices'), _('saved')) - redirect_to action: "show" - end - + def share @plan = Plan.find(params[:id]) authorize @plan - #@plan_data = @plan.to_hash + @visibility = @plan.visibility.present? ? @plan.visibility.to_s : Rails.application.config.default_plan_visibility + @allow_visibility = (@plan.num_answered_questions >= 1 && !@plan.is_test?) end @@ -413,9 +356,20 @@ authorize plan plan.visibility = "#{plan_params[:visibility]}" if plan.save - render json: {code: 1, msg: ''} + render json: {msg: success_message(_('plan\'s visibility'), _('changed'))} else - render json: {code: 0, msg: _("Unable to change the plan's Test status")} + render status: :bad_request, json: {msg: _("Unable to change the plan's status")} + end + end + + def set_test + plan = Plan.find(params[:id]) + authorize plan + plan.visibility = "#{plan_params[:visibility]}" + if plan.save + render json: {msg: (plan.is_test? ? _('Your project is now a test.') : _('Your project is no longer a test.') )} + else + render status: :bad_request, json: {msg: _("Unable to change the plan's test status")} end end @@ -423,9 +377,32 @@ private def plan_params - params.require(:plan).permit(:org_id, :org_name, :funder_id, :funder_name, :template_id, :title, :visibility) + params.require(:plan).permit(:org_id, :org_name, :funder_id, :funder_name, :template_id, :title, :visibility, + :grant_number, :description, :identifier, :principal_investigator, + :principal_investigator_email, :principal_investigator_identifier, + :data_contact, :data_contact_email, :guidance_group_ids) end + def save_guidance_selections(guidance_group_ids) + all_guidance_groups = @plan.get_guidance_group_options + plan_groups = @plan.guidance_groups + guidance_groups = GuidanceGroup.where(id: guidance_group_ids) + all_guidance_groups.each do |group| + # case where plan group exists but not in selection + if plan_groups.include?(group) && ! guidance_groups.include?(group) + # remove from plan groups + @plan.guidance_groups.delete(group) + end + # case where plan group dosent exist and in selection + if !plan_groups.include?(group) && guidance_groups.include?(group) + # add to plan groups + @plan.guidance_groups << group + end + end + @plan.save + end + + # different versions of the same template have the same dmptemplate_id # but different version numbers so for each set of templates with the # same dmptemplate_id choose the highest version number. diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index ef91cca..abe77f2 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -6,6 +6,7 @@ registered = true @role = Role.new(role_params) authorize @role + access_level = params[:role][:access_level].to_i set_access_level(access_level) if params[:user].present? @@ -45,12 +46,12 @@ access_level = params[:role][:access_level].to_i set_access_level(access_level) if @role.update_attributes(role_params) - flash[:notice] = success_message(_('sharing details'), _('saved')) UserMailer.permissions_change_notification(@role, current_user).deliver_now - redirect_to controller: 'plans', action: 'share', id: @role.plan.id + render json: {code: 1, msg: "Successfully changed the permissions for #{@role.user.email}. They have been notified via email."} else - flash[:alert] = failed_create_error(@role, _('role')) - render action: "edit" +# flash[:alert] = failed_create_error(@role, _('role')) + #format.html{ render action: "edit" } + render json: {code: 1, msg: flash[:alert]} end end diff --git a/app/helpers/plans_helper.rb b/app/helpers/plans_helper.rb index c4f3af4..d61258d 100644 --- a/app/helpers/plans_helper.rb +++ b/app/helpers/plans_helper.rb @@ -42,8 +42,10 @@ return "#{_('Institution')}" when 'publicly_visible' return "#{_('Public')}" + when 'privately_visible' + return "#{_('Private')}" else - return "#{_('Private')}" # Both Test and Private + return "#{_('N/A')}" # Test Plans end end diff --git a/app/models/plan.rb b/app/models/plan.rb index ab84aca..6579f97 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -32,7 +32,7 @@ :exported_plans, :project, :title, :template, :grant_number, :identifier, :principal_investigator, :principal_investigator_identifier, :description, :data_contact, :funder_name, :visibility, :exported_plans, - :roles, :users, :org, :data_contact_email, :data_contact_phone, + :roles, :users, :org, :data_contact_email, :principal_investigator_email, :as => [:default, :admin] accepts_nested_attributes_for :roles diff --git a/app/policies/plan_policy.rb b/app/policies/plan_policy.rb index e6d6d15..3f8388c 100644 --- a/app/policies/plan_policy.rb +++ b/app/policies/plan_policy.rb @@ -12,14 +12,6 @@ @plan.readable_by?(@user.id) end - def edit? - @plan.readable_by?(@user.id) - end - - def update_guidance_choices? - @plan.editable_by?(@user.id) - end - def share? @plan.readable_by?(@user.id) end @@ -56,6 +48,10 @@ @plan.administerable_by?(@user.id) end + def set_test? + @plan.administerable_by?(@user.id) + end + # TODO: These routes are no lonmger used =begin def section_answers? diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index db53c0d..86bdedf 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -63,14 +63,17 @@ <%= render "layouts/header" %> -
> - - <%= _('Notice:') %> - <%= raw notice %> -
-
> - - <%= raw alert %> + <% + has_alert = (alert || flash[:alert] || flash[:error]) + has_notice = (notice || flash[:notice]) + %> + +
> + + <%= has_alert ? _('Error:') : _('Notice:') %> + <%= raw (has_alert ? alert : notice) %>
diff --git a/app/views/phases/edit.html.erb b/app/views/phases/edit.html.erb index a218c63..1652259 100644 --- a/app/views/phases/edit.html.erb +++ b/app/views/phases/edit.html.erb @@ -8,7 +8,7 @@ --> -<%= render :partial => "/plans/plan_title", locals: {plan: @plan} %> +

<%= @plan.title %>

diff --git a/app/views/plans/_edit_details.html.erb b/app/views/plans/_edit_details.html.erb index 9f964b4..fb852a3 100644 --- a/app/views/plans/_edit_details.html.erb +++ b/app/views/plans/_edit_details.html.erb @@ -1,95 +1,128 @@ -<% javascript('views/plans/edit.js') %> +<% javascript('views/plans/show.js') %> <%= form_for plan, html: {method: :put, class: "roadmap-form"} do |f| %>
-
+
- <%= f.label "#{_('Project Title')} #{_('(required)')}", for: :title %> - <%= f.text_field :title, class: "input-large has-tooltip", 'data-toggle': "tooltip", - 'title': _('If applying for funding, state the name exactly as in the grant proposal.') %> + <%= f.label "#{_('Project Title')}", for: :title, class: 'required' %> + <%= f.text_field :title, class: "input-extra-large left-indent required", 'data-toggle': "tooltip", + 'data-content': _('If applying for funding, state the name exactly as in the grant proposal.') %> + +
+ <%= f.hidden_field :visibility %> + /> + +
- + +
+ <%= f.label "#{_('Funder')}", for: :funder_name %> + <%= f.text_field :funder_name, class: "input-extra-large left-indent" %> +
+
<%= f.label :grant_number %> - <%= f.text_field :grant_number, class: 'input-small has-tooltip', 'data-toggle': "tooltip", - 'title': _('Grant reference number if applicable [POST-AWARD DMPs ONLY]') %> -
- -
- <%= f.label :principal_investigator %> - <%= f.text_field :principal_investigator, class: 'input-medium has-tooltip', 'data-toggle': "tooltip", - 'title': _('Name of Principal Investigator(s) or main researcher(s) on the project.') %> + <%= f.text_field :grant_number, class: 'input-small left-indent', 'data-toggle': "tooltip", + 'data-content': _('Grant reference number if applicable [POST-AWARD DMPs ONLY]') %>
<%= f.label _('Project Abstract'), for: :description %> - <%= f.text_area :description, { rows: 7, class: 'input-large has-tooltip', - 'data-toggle': "tooltip", 'data-html': "true", - 'title': _("

Questions to consider:

  • - What is the nature of your research project?
  • - What research questions are you addressing?
  • - For what purpose are the data being collected or created?

Guidance:

Briefly summarise the type of study (or studies) to help others understand the purposes for which the data are being collected or created.

")} %> + <%= f.text_area :description, class: "left-indent" %> + <%= tinymce(selector: "#plan_description", content_css: asset_path('application.css')) %> +
-
-
- <%= f.label _('Plan ID'), for: :identifier %> - <%= f.text_field :identifier, class: 'input-medium has-tooltip', 'data-toggle': "tooltip", - 'title': _('A pertinent ID as determined by the funder and/or institution.') %> + <%= f.label _('ID'), for: :identifier %> + <%= f.text_field :identifier, class: 'input-medium left-indent', 'data-toggle': "tooltip", + 'data-content': _('A pertinent ID as determined by the funder and/or institution.') %>
+
+ +
+ +
+ +
+ <%= f.label _('Name'), for: :principal_investigator, 'aria-label': _('Principal Investigator Name') %> + <%= f.text_field :principal_investigator, class: 'input-medium left-indent' %> +
+ +
+ <%= f.label _('ORCID ID'), for: :principal_investigator_identifier, 'aria-label': _('Principal Investigator ORCID ID') %> + <%= f.text_field :principal_investigator_identifier, class: 'input-medium left-indent' %> +
+ +
+ <%= f.label _('Email'), for: :principal_investigator_email, 'aria-label': _('Principal Investigator Email') %> + <%= f.email_field :principal_investigator_email, class: 'input-large left-indent' %> + +
+
<%= f.label(:data_contact, raw("#{_('Data Contact Person')}"), class: 'no-colon') %>
-
- <%= f.label _('Name'), for: :data_contact %> - <%= f.text_field :data_contact, class: 'input-medium has-tooltip', 'data-toggle': "tooltip", - 'title': _('Name (if different to above), telephone and email contact details') %> +
+ /> + +
+
+ <%= f.label _('Name'), for: :data_contact, 'aria-label': _('Data Contact Name') %> + <%= f.text_field :data_contact, class: 'input-medium left-indent' %> +
+ +
+ <%= f.label _('Email'), for: :data_contact_email, 'aria-label': _('Data Contact Email') %> + <%= f.email_field :data_contact_email, class: 'input-large left-indent' %> +


-
 
- <%= submit_tag(_('Save'), class: 'form-submit') %> + <%= render partial: 'shared/accessible_submit_button', + locals: {id: 'save-details-button', + val: _('Save'), + disabled_initially: true, + classes: 'small-input-button left-indent', + tooltip: _('You must provide a project title and any email addresses must be valid.')} %>
-
- <%= f.hidden_field(:visibility, value: visibility) %> - -
- <%= f.label(:visibility, _('Plan Visibility')) %> -
(<%= _('Limited to finished plans') %>)
-
-
- <%= radio_button_tag(:vis, 0, !['publicly_visible', 'organisationally_visible'].include?(visibility), - class: 'right-indent', - id:'privately_visible') %> - <%= raw display_visibility('privately_visible') %> -
-
- <%= radio_button_tag(:vis, 0, 'organisationally_visible' == visibility, - class: 'right-indent', - id: 'organisationally_visible') %> - <%= raw display_visibility('organisationally_visible') %> -
-
- <%= radio_button_tag(:vis, 0, 'publicly_visible' == visibility, - class: 'right-indent', - id: 'publicly_visible') %> - <%= raw display_visibility('publicly_visible') %> -
-
-
-
-
<%= _('Plan Guidance Configuration') %>
+

<%= _('Plan Guidance Configuration') %>

<%= _('To help you write your plan, %{application_name} can show you guidance from a variety of organisations.') % {application_name: Rails.configuration.branding[:application][:name]} %>

-
-

<% _('Select up to 3 organisations to see their guidance.') %>

- <% #@important_ggs.inspect %> +

<%= _('Select up to 6 organisations to see their guidance.') %>

+ +
    + <%= render partial: "guidance_choices", + locals: {choices: @important_ggs, form: f, + current_selections: @selected_guidance_groups} %> +
+ + <%= _('See guidance from additional organisations') %> + +
-<% end %> \ No newline at end of file +<% end %> + +<%= tinymce :content_css => asset_path('application.css') %> \ No newline at end of file diff --git a/app/views/plans/_guidance_choices.html.erb b/app/views/plans/_guidance_choices.html.erb new file mode 100644 index 0000000..cd18f90 --- /dev/null +++ b/app/views/plans/_guidance_choices.html.erb @@ -0,0 +1,26 @@ +<% choices.each do |org, groups| %> + <% if groups && groups.size == 1 %> +
  • + <%= check_box_tag "guidance_group_ids[]", groups[0].id, + current_selections.include?(groups[0].id), class: 'guidance-choice' %> + <%= form.label org.name, for: groups[0].id, + class: 'inline checkbox-label regular-text guidance-group-label' %> +
  • + <% elsif groups %> +
  • + + +
  • + <% groups.each do |group| %> +
  • + └─ + <%= check_box_tag "guidance_group_ids[]", group.id, + current_selections.include?(group.id), class: 'guidance-choice' %> + <%= form.label group.name, for: group.id, + class: "left-indent checkbox-label regular-text guidance-group-label" %> +
  • + <% end %> + <% end%> +<% end %> \ No newline at end of file diff --git a/app/views/plans/_plan_title.html.erb b/app/views/plans/_plan_title.html.erb deleted file mode 100644 index 93b7c28..0000000 --- a/app/views/plans/_plan_title.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -

    <%= plan.title %>

    - -<% if plan.visibility == 'is_test' %> -
    - - <%= _('This is a') %> <%= _('test plan') %>. -
    -<% end %> diff --git a/app/views/plans/_show_details.html.erb b/app/views/plans/_show_details.html.erb index 67195d0..0919c84 100644 --- a/app/views/plans/_show_details.html.erb +++ b/app/views/plans/_show_details.html.erb @@ -1,19 +1,32 @@ -
    +
    <%= _('Project Title') %>
    <%= plan.title %>
    +
    <%= _('Funder') %>
    +
    <%= plan.funder_name %>
    <%= _('Grant Number') %>
    <%= plan.grant_number %>
    -
    <%= _('Principal Investigator') %>
    -
    <%= plan.principal_investigator %>
    <%= _('Project Abstract') %>
    <%= raw plan.description %>
    +
    <%= _('Id') %>
    +
    <%= plan.identifier %>
    +
    +
    +
    +
    <%= _('Principal Investigator') %>
    +
    +
    <%= _('Name') %>
    +
    <%= plan.principal_investigator %>
    +
    <%= _('ORCID') %>
    +
    <%= plan.principal_investigator_identifier %>
    +
    <%= _('Email') %>
    +
    <%= plan.principal_investigator_email %>

    -
    <%= _('Plan ID') %>
    -
    <%= plan.identifier %>
    <%= _('Data Contact Person') %>
    <%= _('Name') %>
    <%= plan.data_contact %>
    +
    <%= _('Email') %>
    +
    <%= plan.data_contact_email %>
    diff --git a/app/views/plans/index.html.erb b/app/views/plans/index.html.erb index 1c265c4..6cd0dd6 100644 --- a/app/views/plans/index.html.erb +++ b/app/views/plans/index.html.erb @@ -52,7 +52,11 @@ <%= l(plan.latest_update.to_date, formats: :short) %> <%= display_role(plan.roles.find_by(user: current_user)) %> - <%= plan.administerable_by?(current_user.id) ? '' : 'disabled="true"' %> /> + <% if plan.administerable_by?(current_user.id) then %> + <%= plan.administerable_by?(current_user.id) ? '' : 'disabled="true"' %> /> + <% else %> + <%= plan.visibility === 'is_test' ? _('Yes') : _('No') %> + <% end %> <%= raw display_visibility(plan.visibility) %> diff --git a/app/views/plans/share.html.erb b/app/views/plans/share.html.erb index 22b513a..b331136 100644 --- a/app/views/plans/share.html.erb +++ b/app/views/plans/share.html.erb @@ -1,7 +1,7 @@ -<%- model_class = Plan -%> <% javascript('views/plans/share.js') %> + -<%= render :partial => "plan_title", locals: {plan: @plan} %> +

    <%= @plan.title %>

    @@ -29,18 +29,35 @@
    -

    <%= _('Collaborators')%>

    + +

    <%= _('Set plan visibility') %>

    +

    <%= _('Public or organisational visibility is intended for finished plans. You must answer at least one question to enable these options.') %>

    + + <%= form_for @plan, html: {method: :put, class: "roadmap-form"} do |f| %> +
    + <%= f.hidden_field :id %> +
    + <%= f.radio_button :visibility, :privately_visible, disabled: !@allow_visibility %> + <%= f.label :visibility, _('Private: restricted to me and my collaborators'), + class: "checkbox-label regular-text#{(@allow_visibility ? '' : ' disabled')}" %> +
    +
    + <%= f.radio_button :visibility, :organisationally_visible, disabled: !@allow_visibility %> + <%= f.label :visibility, _('Organisation: anyone at my organisation can view'), + class: "checkbox-label regular-text#{(@allow_visibility ? '' : ' disabled')}" %> +
    +
    + <%= f.radio_button :visibility, :publicly_visible, disabled: !@allow_visibility %> + <%= f.label :visibility, _('Public: anyone can view'), + class: "checkbox-label regular-text#{(@allow_visibility ? '' : ' disabled')}" %> +
    +
    + <% end %> + +

    <%= _('Manage collaborators')%>

    -

    <%= _('You can give other people access to your plan here. There are three permission levels.') %> -

      -
    • <%= _('Users with "read only" access can only read the plan.') %>
    • -
    • <%= _('Editors can contribute to the plan.') %>
    • -
    • <%= _('Co-owners can also contribute to the plan, but additionally can edit the plan details and control access to the plan.') %>
    • -
    -

    -

    <%= _('Add each collaborator in turn by entering their email address below, choosing a permission level and clicking "Add collaborator".') %>

    -

    <%= _('Those you invite will receive an email notification that they have access to this plan, inviting them to register with %{application_name} if they don\'t already have an account. A notification is also issued when a user\'s permission level is changed.') % { application_name: Rails.configuration.branding[:application][:name] } %>

    +

    <%= _('Invite specific people to read, edit, or administer your plan. Invitees will receive an email notification that they have access to this plan.') %>

    <% if @plan.roles.any? then %> @@ -48,7 +65,7 @@ - + @@ -58,12 +75,13 @@ @@ -80,22 +98,42 @@
    <%= _('Email address')%> <%= _('Permissions')%><%= _('Action') %>
    <%= role.user.name %> <% if role.creator? %> - <%= 'Owner' %> + <%= 'Owner' %> <% elsif !role.creator? && role.user == current_user %> - <%= display_role(role) %> + <%= display_role(role) %> <% elsif !role.creator? && role.user != current_user %> <%= form_for role, url: {controller: :roles, action: :update, id: role.id }, html: {method: :put} do |f| %>
    + <%= f.hidden_field :id %> <%= f.select :access_level, {"#{_('Co-owner')}": 3, "#{_('Editor')}": 2, "#{_('Read only')}": 1}, {}, {id: "#{role.id}-can-edit", class: "toggle-existing-user-access has-tooltip", 'data-toggle': "tooltip", 'title': _('Editors can contribute to plans. Co-owners have additional rights to edit plan details and control access.') } %>
    <% end %> @@ -71,7 +89,7 @@
    <% unless role.creator? || role.user == current_user then %> - <%= link_to _('Remove user access'), role, method: :delete, data: { confirm: _('Are you sure?') }, :class => "a-orange" %> + <%= link_to _('Remove'), role, method: :delete, data: { confirm: _('Are you sure?') }, :class => "a-orange" %> <% end %>
    <% end %> -

    <%= _('Add collaborator') %>

    +

    <%= _('Invite collaborators') %>

    <% new_role = Role.new %> <% new_role.plan = @plan %> <%= form_for new_role, url: {controller: :roles, action: :create }, - html: {method: :post, class: 'roadmap-form'} do |f| %>

    -
    + html: {method: :post, class: 'roadmap-form'} do |f| %> +
    <%= f.hidden_field :plan_id %> <%= f.fields_for :user do |user| %> <%= user.label :email, _('Email') %> - <%= user.email_field :email, for: :user, name: "user", class: "left-indent" %> + <%= user.email_field :email, for: :user, name: "user", class: "left-indent input-medium" %> + <% end %> - <%= f.label :access_level, _('Permissions') %> - <%= f.select :access_level, [[_('Co-owner'), 3], [ _('Editor') , 2], [ _('Read only'), 1]], {}, {class: 'has-tooltip left-indent', 'data-toggle': "tooltip", 'title': _('Editors can contribute to plans. Co-owners have additional rights to edit plan details and control access.') } %> - + +

    +
    + <%= f.radio_button :access_level, 1 %> + <%= f.label :access_level, _('Read Only: can view but not make changes'), class: 'checkbox-label regular-text' %> +
    +
    + <%= f.radio_button :access_level, 2 %> + <%= f.label :access_level, _('Editor: can comment and make changes'), class: 'checkbox-label regular-text' %> +
    +
    + <%= f.radio_button :access_level, 3 %> + <%= f.label :access_level, _('Co-owner: can edit project details, change visibility, and add collaborators'), class: 'checkbox-label regular-text' %> +
    +
    + <%= render partial: 'shared/accessible_submit_button', + locals: {id: 'add-collaborator-button', + val: _('Add collaborator'), + disabled_initially: true, + classes: 'small-input-button left-indent', + tooltip: _('Enter a valid email and permission level.')} %> +
    <% end %>

    diff --git a/app/views/plans/show.html.erb b/app/views/plans/show.html.erb index 1fda9ce..d9d3809 100644 --- a/app/views/plans/show.html.erb +++ b/app/views/plans/show.html.erb @@ -1,5 +1,5 @@ -<%= render :partial => "plan_title", locals: {plan: @plan} %> +

    <%= @plan.title %>

    @@ -11,7 +11,9 @@ <% @plan.template.phases.each do |phase| %> <% end %> diff --git a/app/views/plans/show_export.html.erb b/app/views/plans/show_export.html.erb index baf78ed..ccf202b 100644 --- a/app/views/plans/show_export.html.erb +++ b/app/views/plans/show_export.html.erb @@ -2,7 +2,7 @@ <% javascript('views/plans/export_configure.js') %> -<%= render :partial => "plan_title", locals: {plan: @plan} %> +

    <%= @plan.title %>

    diff --git a/app/views/shared/_accessible_submit_button.html.erb b/app/views/shared/_accessible_submit_button.html.erb index 497c1e8..7d53835 100644 --- a/app/views/shared/_accessible_submit_button.html.erb +++ b/app/views/shared/_accessible_submit_button.html.erb @@ -14,7 +14,7 @@ $("#<%= id %>").on('click focus', function(e){ if($(this).attr('aria-disabled') == 'true'){ e.preventDefault(); - $(this).siblings(".error-tooltip-right").attr('role', 'tooltip'); + $(this).siblings(".error-tooltip-right").attr('role', 'alert'); }else{ $(this).siblings(".error-tooltip-right").attr('role', ''); } diff --git a/app/views/templates/_edit_template.html.erb b/app/views/templates/_edit_template.html.erb index d3a8366..d68a9cc 100644 --- a/app/views/templates/_edit_template.html.erb +++ b/app/views/templates/_edit_template.html.erb @@ -12,7 +12,7 @@ <%= f.label _('Description'), for: template.description %> <%= text_area_tag("template-desc", template.description, class: "input-large tinymce") %>
    -
    diff --git a/config/application.rb b/config/application.rb index ba95598..020d725 100644 --- a/config/application.rb +++ b/config/application.rb @@ -97,11 +97,11 @@ views/notes/index.js views/orgs/admin_edit.js views/orgs/shibboleth_ds.js - views/plans/edit.js views/plans/export_configure.js views/plans/index.js views/plans/new.js views/plans/share.js + views/plans/show.js views/shared/login_form.js views/shared/register_form.js views/static_pages/utils.js) diff --git a/config/routes.rb b/config/routes.rb index 9d0e26f..3343ab9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -215,6 +215,7 @@ get 'export' post 'invite' post 'visibility', constraints: {format: [:json]} + post 'set_test', constraints: {format: [:json]} end collection do diff --git a/db/migrate/20170710182442_add_principal_investigator_email_to_plans.rb b/db/migrate/20170710182442_add_principal_investigator_email_to_plans.rb new file mode 100644 index 0000000..2690d54 --- /dev/null +++ b/db/migrate/20170710182442_add_principal_investigator_email_to_plans.rb @@ -0,0 +1,5 @@ +class AddPrincipalInvestigatorEmailToPlans < ActiveRecord::Migration + def change + add_column :plans, :principal_investigator_email, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 791d0d7..e975ca7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,441 +13,426 @@ ActiveRecord::Schema.define(version: 20170712084314) do - # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - create_table "annotations", force: :cascade do |t| - t.integer "question_id" - t.integer "org_id" - t.text "text" - t.integer "type", default: 0, null: false + t.integer "question_id", limit: 4 + t.integer "org_id", limit: 4 + t.text "text", limit: 65535 + t.integer "type", limit: 4, default: 0, null: false t.datetime "created_at" t.datetime "updated_at" end - add_index "annotations", ["question_id"], name: "index_annotations_on_question_id", using: :btree + add_index "annotations", ["org_id"], name: "fk_rails_aca7521f72" + add_index "annotations", ["question_id"], name: "fk_rails_0e08e753b6" create_table "answers", force: :cascade do |t| - t.text "text" - t.integer "plan_id" - t.integer "user_id" - t.integer "question_id" + t.text "text", limit: 65535 + t.integer "plan_id", limit: 4 + t.integer "user_id", limit: 4 + t.integer "question_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" - t.integer "lock_version", default: 0 + t.integer "lock_version", limit: 4, default: 0 end + add_index "answers", ["plan_id"], name: "fk_rails_84a6005a3e" + add_index "answers", ["question_id"], name: "fk_rails_3d5ed4418f" + add_index "answers", ["user_id"], name: "fk_rails_584be190c2" + create_table "answers_question_options", id: false, force: :cascade do |t| - t.integer "answer_id", null: false - t.integer "question_option_id", null: false + t.integer "answer_id", limit: 4, null: false + t.integer "question_option_id", limit: 4, null: false end - add_index "answers_question_options", ["answer_id"], name: "index_answers_question_options_on_answer_id", using: :btree + add_index "answers_question_options", ["answer_id", "question_option_id"], name: "answer_question_option_index" + add_index "answers_question_options", ["question_option_id", "answer_id"], name: "question_option_answer_index" create_table "exported_plans", force: :cascade do |t| - t.integer "plan_id" - t.integer "user_id" - t.string "format" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "phase_id" + t.integer "plan_id", limit: 4 + t.integer "user_id", limit: 4 + t.string "format", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "phase_id", limit: 4 end create_table "file_types", force: :cascade do |t| - t.string "name" - t.string "icon_name" - t.integer "icon_size" - t.string "icon_location" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name", limit: 255 + t.string "icon_name", limit: 255 + t.integer "icon_size", limit: 4 + t.string "icon_location", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "file_uploads", force: :cascade do |t| - t.string "name" - t.string "title" - t.text "description" - t.integer "size" + t.string "name", limit: 255 + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.integer "size", limit: 4 t.boolean "published" - t.string "location" - t.integer "file_type_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "location", limit: 255 + t.integer "file_type_id", limit: 4 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "friendly_id_slugs", force: :cascade do |t| - t.string "slug", null: false - t.integer "sluggable_id", null: false + t.string "slug", limit: 255, null: false + t.integer "sluggable_id", limit: 4, null: false t.string "sluggable_type", limit: 40 t.datetime "created_at" end - add_index "friendly_id_slugs", ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type", unique: true, using: :btree - add_index "friendly_id_slugs", ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id", using: :btree - add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type", using: :btree + add_index "friendly_id_slugs", ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type", unique: true + add_index "friendly_id_slugs", ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id" + add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type" create_table "guidance_groups", force: :cascade do |t| - t.string "name" - t.integer "org_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name", limit: 255 + t.integer "org_id", limit: 4 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "optional_subset" t.boolean "published" end - add_index "guidance_groups", ["org_id"], name: "index_guidance_groups_on_org_id", using: :btree + add_index "guidance_groups", ["org_id"], name: "fk_rails_819c1dbbc7" create_table "guidances", force: :cascade do |t| - t.text "text" - t.integer "guidance_group_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "question_id" + t.text "text", limit: 65535 + t.integer "guidance_group_id", limit: 4 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "question_id", limit: 4 t.boolean "published" end - add_index "guidances", ["guidance_group_id"], name: "index_guidances_on_guidance_group_id", using: :btree + add_index "guidances", ["guidance_group_id"], name: "fk_rails_20d29da787" create_table "identifier_schemes", force: :cascade do |t| - t.string "name" - t.string "description" + t.string "name", limit: 255 + t.string "description", limit: 255 t.boolean "active" t.datetime "created_at" t.datetime "updated_at" - t.string "logo_url" - t.string "user_landing_url" + t.string "logo_url", limit: 255 + t.string "user_landing_url", limit: 255 end create_table "languages", force: :cascade do |t| - t.string "abbreviation" - t.string "description" - t.string "name" + t.string "abbreviation", limit: 255 + t.string "description", limit: 255 + t.string "name", limit: 255 t.boolean "default_language" end create_table "notes", force: :cascade do |t| - t.integer "user_id" - t.text "text" + t.integer "user_id", limit: 4 + t.text "text", limit: 65535 t.boolean "archived" - t.integer "answer_id" - t.integer "archived_by" + t.integer "answer_id", limit: 4 + t.integer "archived_by", limit: 4 t.datetime "created_at" t.datetime "updated_at" end - add_index "notes", ["answer_id"], name: "index_notes_on_answer_id", using: :btree + add_index "notes", ["answer_id"], name: "fk_rails_907f8d48bf" + add_index "notes", ["user_id"], name: "fk_rails_7f2323ad43" create_table "org_identifiers", force: :cascade do |t| - t.string "identifier" - t.string "attrs" + t.string "identifier", limit: 255 + t.string "attrs", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.integer "org_id" - t.integer "identifier_scheme_id" + t.integer "org_id", limit: 4 + t.integer "identifier_scheme_id", limit: 4 end + add_index "org_identifiers", ["identifier_scheme_id"], name: "fk_rails_189ad2e573" + add_index "org_identifiers", ["org_id"], name: "fk_rails_36323c0674" + create_table "org_token_permissions", force: :cascade do |t| - t.integer "org_id" - t.integer "token_permission_type_id" + t.integer "org_id", limit: 4 + t.integer "token_permission_type_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" end - add_index "org_token_permissions", ["org_id"], name: "index_org_token_permissions_on_org_id", using: :btree + add_index "org_token_permissions", ["org_id"], name: "fk_rails_e1db1b22c5" + add_index "org_token_permissions", ["token_permission_type_id"], name: "fk_rails_2aa265f538" create_table "orgs", force: :cascade do |t| - t.string "name" - t.string "abbreviation" - t.string "target_url" - t.string "wayfless_entity" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "parent_id" + t.string "name", limit: 255 + t.string "abbreviation", limit: 255 + t.string "target_url", limit: 255 + t.string "wayfless_entity", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "parent_id", limit: 4 t.boolean "is_other" - t.string "sort_name" - t.text "banner_text" - t.string "logo_file_name" - t.integer "region_id" - t.integer "language_id" - t.string "logo_uid" - t.string "logo_name" - t.string "contact_email" - t.integer "org_type", default: 0, null: false + t.string "sort_name", limit: 255 + t.text "banner_text", limit: 65535 + t.string "logo_file_name", limit: 255 + t.integer "region_id", limit: 4 + t.integer "language_id", limit: 4 + t.string "logo_uid", limit: 255 + t.string "logo_name", limit: 255 + t.string "contact_email", limit: 255 + t.integer "org_type", limit: 4, default: 0, null: false end + add_index "orgs", ["language_id"], name: "fk_rails_5640112cab" + add_index "orgs", ["region_id"], name: "fk_rails_5a6adf6bab" + create_table "perms", force: :cascade do |t| - t.string "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - add_index "perms", ["name"], name: "index_perms_on_name", using: :btree - add_index "perms", ["name"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree + add_index "perms", ["name"], name: "index_perms_on_name" + add_index "perms", ["name"], name: "index_roles_on_name_and_resource_type_and_resource_id" create_table "phases", force: :cascade do |t| - t.string "title" - t.text "description" - t.integer "number" - t.integer "template_id" + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.integer "number", limit: 4 + t.integer "template_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" - t.string "slug" + t.string "slug", limit: 255 t.boolean "modifiable" end - add_index "phases", ["template_id"], name: "index_phases_on_template_id", using: :btree + add_index "phases", ["template_id"], name: "index_phases_on_template_id" create_table "plans", force: :cascade do |t| - t.string "title" - t.integer "template_id" + t.string "title", limit: 255 + t.integer "template_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" - t.string "slug" - t.string "grant_number" - t.string "identifier" - t.text "description" - t.string "principal_investigator" - t.string "principal_investigator_identifier" - t.string "data_contact" - t.string "funder_name" - t.integer "visibility", default: 0, null: false - t.string "data_contact_email" - t.string "data_contact_phone" + t.string "slug", limit: 255 + t.string "grant_number", limit: 255 + t.string "identifier", limit: 255 + t.text "description", limit: 65535 + t.string "principal_investigator", limit: 255 + t.string "principal_investigator_identifier", limit: 255 + t.string "data_contact", limit: 255 + t.string "funder_name", limit: 255 + t.integer "visibility", limit: 4, default: 0, null: false + t.string "data_contact_email", limit: 255 + t.string "data_contact_phone", limit: 255 + t.string "principal_investigator_email" end - add_index "plans", ["template_id"], name: "index_plans_on_template_id", using: :btree + add_index "plans", ["template_id"], name: "index_plans_on_template_id" create_table "plans_guidance_groups", force: :cascade do |t| - t.integer "guidance_group_id" - t.integer "plan_id" + t.integer "guidance_group_id", limit: 4 + t.integer "plan_id", limit: 4 end + add_index "plans_guidance_groups", ["guidance_group_id"], name: "fk_rails_ec1c5524d7" + add_index "plans_guidance_groups", ["plan_id"], name: "fk_rails_13d0671430" + create_table "prefs", force: :cascade do |t| t.string "settings" t.integer "user_id" end create_table "question_formats", force: :cascade do |t| - t.string "title" - t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "option_based", default: false - t.integer "formattype", default: 0 + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "option_based", default: false + t.integer "formattype", limit: 4, default: 0 end create_table "question_options", force: :cascade do |t| - t.integer "question_id" - t.string "text" - t.integer "number" + t.integer "question_id", limit: 4 + t.string "text", limit: 255 + t.integer "number", limit: 4 t.boolean "is_default" t.datetime "created_at" t.datetime "updated_at" end - add_index "question_options", ["question_id"], name: "index_question_options_on_question_id", using: :btree + add_index "question_options", ["question_id"], name: "fk_rails_b9c5f61cf9" create_table "questions", force: :cascade do |t| - t.text "text" - t.text "default_value" - t.integer "number" - t.integer "section_id" + t.text "text", limit: 65535 + t.text "default_value", limit: 65535 + t.integer "number", limit: 4 + t.integer "section_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" - t.integer "question_format_id" - t.boolean "option_comment_display", default: true + t.integer "question_format_id", limit: 4 + t.boolean "option_comment_display", default: true t.boolean "modifiable" end - add_index "questions", ["section_id"], name: "index_questions_on_section_id", using: :btree + add_index "questions", ["question_format_id"], name: "fk_rails_4fbc38c8c7" + add_index "questions", ["section_id"], name: "index_questions_on_section_id" create_table "questions_themes", id: false, force: :cascade do |t| - t.integer "question_id", null: false - t.integer "theme_id", null: false + t.integer "question_id", limit: 4, null: false + t.integer "theme_id", limit: 4, null: false end - add_index "questions_themes", ["question_id"], name: "index_questions_themes_on_question_id", using: :btree + add_index "questions_themes", ["question_id", "theme_id"], name: "question_theme_index" + add_index "questions_themes", ["theme_id", "question_id"], name: "theme_question_index" create_table "regions", force: :cascade do |t| - t.string "abbreviation" - t.string "description" - t.string "name" - t.integer "super_region_id" + t.string "abbreviation", limit: 255 + t.string "description", limit: 255 + t.string "name", limit: 255 + t.integer "super_region_id", limit: 4 end create_table "roles", force: :cascade do |t| - t.integer "user_id" - t.integer "plan_id" + t.integer "user_id", limit: 4 + t.integer "plan_id", limit: 4 t.datetime "created_at" t.datetime "updated_at" - t.integer "access", default: 0, null: false + t.integer "access", limit: 4, default: 0, null: false end - add_index "roles", ["plan_id"], name: "index_roles_on_plan_id", using: :btree - add_index "roles", ["user_id"], name: "index_roles_on_user_id", using: :btree + add_index "roles", ["plan_id"], name: "fk_rails_a1ce6c2772" + add_index "roles", ["user_id"], name: "fk_rails_ab35d699f0" create_table "sections", force: :cascade do |t| - t.string "title" - t.text "description" - t.integer "number" + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.integer "number", limit: 4 t.datetime "created_at" t.datetime "updated_at" t.boolean "published" - t.integer "phase_id" + t.integer "phase_id", limit: 4 t.boolean "modifiable" end - add_index "sections", ["phase_id"], name: "index_sections_on_phase_id", using: :btree + add_index "sections", ["phase_id"], name: "index_sections_on_phase_id" create_table "settings", force: :cascade do |t| - t.string "var", null: false - t.text "value" - t.integer "target_id", null: false - t.string "target_type", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "var", limit: 255, null: false + t.text "value", limit: 65535 + t.integer "target_id", limit: 4, null: false + t.string "target_type", limit: 255, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - add_index "settings", ["target_type", "target_id", "var"], name: "index_settings_on_target_type_and_target_id_and_var", unique: true, using: :btree + add_index "settings", ["target_type", "target_id", "var"], name: "index_settings_on_target_type_and_target_id_and_var", unique: true create_table "splash_logs", force: :cascade do |t| - t.string "destination" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "destination", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "templates", force: :cascade do |t| - t.string "title" - t.text "description" + t.string "title", limit: 255 + t.text "description", limit: 65535 t.boolean "published" - t.integer "org_id" - t.string "locale" + t.integer "org_id", limit: 4 + t.string "locale", limit: 255 t.boolean "is_default" t.datetime "created_at" t.datetime "updated_at" - t.integer "version" - t.integer "visibility" - t.integer "customization_of" - t.integer "dmptemplate_id" + t.integer "version", limit: 4 + t.integer "visibility", limit: 4 + t.integer "customization_of", limit: 4 + t.integer "dmptemplate_id", limit: 4 t.boolean "migrated" - t.boolean "dirty", default: false + t.boolean "dirty", default: false end - add_index "templates", ["org_id", "dmptemplate_id"], name: "template_organisation_dmptemplate_index", using: :btree - add_index "templates", ["org_id"], name: "index_templates_on_org_id", using: :btree + add_index "templates", ["org_id", "dmptemplate_id"], name: "template_organisation_dmptemplate_index" + add_index "templates", ["org_id"], name: "index_templates_on_org_id" create_table "themes", force: :cascade do |t| - t.string "title" - t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "locale" + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "locale", limit: 255 end create_table "themes_in_guidance", id: false, force: :cascade do |t| - t.integer "theme_id" - t.integer "guidance_id" + t.integer "theme_id", limit: 4 + t.integer "guidance_id", limit: 4 end - add_index "themes_in_guidance", ["guidance_id"], name: "index_themes_in_guidance_on_guidance_id", using: :btree - add_index "themes_in_guidance", ["theme_id"], name: "index_themes_in_guidance_on_theme_id", using: :btree + add_index "themes_in_guidance", ["guidance_id"], name: "fk_rails_a5ab9402df" + add_index "themes_in_guidance", ["theme_id"], name: "fk_rails_7d708f6f1e" create_table "token_permission_types", force: :cascade do |t| - t.string "token_type" - t.text "text_description" + t.string "token_type", limit: 255 + t.text "text_description", limit: 65535 t.datetime "created_at" t.datetime "updated_at" end create_table "user_identifiers", force: :cascade do |t| - t.string "identifier" + t.string "identifier", limit: 255 t.datetime "created_at" t.datetime "updated_at" - t.integer "user_id" - t.integer "identifier_scheme_id" + t.integer "user_id", limit: 4 + t.integer "identifier_scheme_id", limit: 4 end - add_index "user_identifiers", ["user_id"], name: "index_user_identifiers_on_user_id", using: :btree + add_index "user_identifiers", ["identifier_scheme_id"], name: "fk_rails_fe95df7db0" + add_index "user_identifiers", ["user_id"], name: "fk_rails_65c9a98cdb" create_table "users", force: :cascade do |t| - t.string "firstname" - t.string "surname" - t.string "email", default: "", null: false - t.string "orcid_id" - t.string "shibboleth_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "encrypted_password", default: "" - t.string "reset_password_token" + t.string "firstname", limit: 255 + t.string "surname", limit: 255 + t.string "email", limit: 255, default: "", null: false + t.string "orcid_id", limit: 255 + t.string "shibboleth_id", limit: 255 + t.datetime "created_at" + t.datetime "updated_at" + t.string "encrypted_password", limit: 255, default: "" + t.string "reset_password_token", limit: 255 t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 + t.integer "sign_in_count", limit: 4, default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.string "confirmation_token" + t.string "current_sign_in_ip", limit: 255 + t.string "last_sign_in_ip", limit: 255 + t.string "confirmation_token", limit: 255 t.datetime "confirmed_at" t.datetime "confirmation_sent_at" - t.string "invitation_token" + t.string "invitation_token", limit: 255 t.datetime "invitation_created_at" t.datetime "invitation_sent_at" t.datetime "invitation_accepted_at" - t.string "other_organisation" + t.string "other_organisation", limit: 255 t.boolean "accept_terms" - t.integer "org_id" - t.string "api_token" - t.integer "invited_by_id" - t.string "invited_by_type" - t.integer "language_id" - t.string "recovery_email" + t.integer "org_id", limit: 4 + t.string "api_token", limit: 255 + t.integer "invited_by_id", limit: 4 + t.string "invited_by_type", limit: 255 + t.integer "language_id", limit: 4 + t.string "recovery_email", limit: 255 end - add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "users", ["org_id"], name: "index_users_on_org_id", using: :btree + add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true + add_index "users", ["email"], name: "index_users_on_email", unique: true + add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true + add_index "users", ["language_id"], name: "fk_rails_45f4f12508" + add_index "users", ["org_id"], name: "fk_rails_e73753bccb" + add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true create_table "users_perms", id: false, force: :cascade do |t| - t.integer "user_id" - t.integer "perm_id" + t.integer "user_id", limit: 4 + t.integer "perm_id", limit: 4 end - add_index "users_perms", ["user_id"], name: "index_users_perms_on_user_id", using: :btree + add_index "users_perms", ["perm_id"], name: "fk_rails_457217c31c" + add_index "users_perms", ["user_id", "perm_id"], name: "index_users_perms_on_user_id_and_perm_id" - add_foreign_key "annotations", "orgs" - add_foreign_key "annotations", "questions" - add_foreign_key "answers", "plans" - add_foreign_key "answers", "questions" - add_foreign_key "answers", "users" - add_foreign_key "answers_question_options", "answers" - add_foreign_key "answers_question_options", "question_options" - add_foreign_key "guidance_groups", "orgs" - add_foreign_key "guidances", "guidance_groups" - add_foreign_key "notes", "answers" - add_foreign_key "notes", "users" - add_foreign_key "org_identifiers", "identifier_schemes" - add_foreign_key "org_identifiers", "orgs" - add_foreign_key "org_token_permissions", "orgs" - add_foreign_key "org_token_permissions", "token_permission_types" - add_foreign_key "orgs", "languages" - add_foreign_key "orgs", "regions" - add_foreign_key "phases", "templates" - add_foreign_key "plans", "templates" - add_foreign_key "plans_guidance_groups", "guidance_groups" - add_foreign_key "plans_guidance_groups", "plans" - add_foreign_key "question_options", "questions" - add_foreign_key "questions", "question_formats" - add_foreign_key "questions", "sections" - add_foreign_key "questions_themes", "questions" - add_foreign_key "questions_themes", "themes" - add_foreign_key "roles", "plans" - add_foreign_key "roles", "users" - add_foreign_key "sections", "phases" - add_foreign_key "templates", "orgs" - add_foreign_key "themes_in_guidance", "guidances" - add_foreign_key "themes_in_guidance", "themes" - add_foreign_key "user_identifiers", "identifier_schemes" - add_foreign_key "user_identifiers", "users" - add_foreign_key "users", "languages" - add_foreign_key "users", "orgs" - add_foreign_key "users_perms", "perms" - add_foreign_key "users_perms", "users" end diff --git a/lib/assets/javascripts/dmproadmap/forms.js b/lib/assets/javascripts/dmproadmap/forms.js index 4cfa730..c344e98 100644 --- a/lib/assets/javascripts/dmproadmap/forms.js +++ b/lib/assets/javascripts/dmproadmap/forms.js @@ -1,43 +1,97 @@ // --------------------------------------------------------------------------- -function toggleAutocompleteError(autocomplete, idbox, errorMessage){ - if(autocomplete.length > 0 && idbox.length > 0){ - var err = $(idbox).siblings("span.error-tooltip"); - if(err.length <= 0){ - err = $(idbox).siblings("span.error-tooltip-right"); - } +function asyncRequest(params, callbacks){ + if(params['url']){ + var defaults = {type: 'GET', + contentType: 'application/json', + accepts: 'application/json'}; - // If an error element is available and the error message is not empty and the field - // is not empty - if(err.length > 0 && (errorMessage === '' || $(autocomplete).val().trim().length <= 0)){ - err.html('').attr('role', ''); - $(autocomplete).removeClass('red-border'); - }else{ - err.html(errorMessage).attr('role', 'tooltip'); - $(autocomplete).addClass('red-border'); - } - } + // Make sure the incoming params are enough to make the call + for(var key in defaults){ + if(!params[key]){ + params[key] = defaults[key]; + } + } + + if(!callbacks){ + callbacks = {}; + } + + // Submit the request + $.ajax(params).then( + // Success + function(data, msg, xhr){ + animateNotification(data['msg'], false); + if(callbacks['success']){ + callbacks['success'](data); + } + }, + + // Failure + function(xhr, status, err){ + var json = JSON.parse(xhr.responseText); + var msg = json['msg'] ? json['msg'] : __('Unable to process your request.'); + animateNotification(msg, true); + if(callbacks['failure']){ + callbacks['failure'](err); + } + } + ); + } } // --------------------------------------------------------------------------- -function toggleInputError(input, errorMessage){ +function toggleAutocompleteError(autocomplete, idbox, errorMessage){ + if(autocomplete.length > 0 && idbox.length > 0){ + var err = $(idbox).siblings("span.error-tooltip"); + if(err.length <= 0){ + err = $(idbox).siblings("span.error-tooltip-right"); + } + + // If an error element is available and the error message is not empty and the field + // is not empty + if(err.length > 0 && (errorMessage === '' || $(autocomplete).val().trim().length <= 0)){ + err.html('').attr('role', ''); + $(autocomplete).removeClass('red-border'); + }else{ + err.html(errorMessage).attr('role', 'tooltip'); + $(autocomplete).addClass('red-border'); + } + } +} + +// --------------------------------------------------------------------------- +function toggleInputError(input, errorMessage, blankAsError){ var err = $(input).siblings("span.error-tooltip"); if(err.length <= 0){ err = $(input).siblings("span.error-tooltip-right"); } -console.log(err.length + ' - ' + errorMessage + ' - ' + $(input).val().trim().length); - // If an error element is available and the error message is not empty and the field - // is not empty - if(err.length > 0 && (errorMessage === '' || $(input).val().trim().length <= 0)){ + // is not empty (unless its a required field!) + if(err.length > 0 && (errorMessage === '' || (!blankAsError && $(input).val().trim().length <= 0))){ err.html('').attr('role', ''); $(input).removeClass('red-border'); }else{ - err.html(errorMessage).attr('role', 'tooltip'); + err.html(errorMessage).attr('role', 'alert'); $(input).addClass('red-border'); } } +// Animate the Notification message section at the top of the page +// --------------------------------------------------------------------------- +function animateNotification(message, isAlert){ + if(message){ + $("#notification-area span:not(.aria-only)").html(message).css('width', 'auto') + .attr('role', (isAlert ? 'alert' : 'status')) + .parent().attr('class', (isAlert ? 'roadmap-alert-box' : 'roadmap-info-box')) + .css('visibility', 'visible').fadeIn(); + + }else{ + $("#notification-area span:not(.aria-only)").html('') + .parent().css('visibility', 'hidden').fadeOut(); + } +} + // --------------------------------------------------------------------------- function validatePassword(sPassword) { if(sPassword.trim().length >= 8 && sPassword.trim().length <= 128){ @@ -53,6 +107,6 @@ if(filter.test(sEmail)){ return ''; }else{ - return __('Invalid Email'); + return __('Invalid email address'); } } \ No newline at end of file diff --git a/lib/assets/javascripts/dmproadmap/utils.js b/lib/assets/javascripts/dmproadmap/utils.js index 8aff27d..170962a 100644 --- a/lib/assets/javascripts/dmproadmap/utils.js +++ b/lib/assets/javascripts/dmproadmap/utils.js @@ -20,28 +20,29 @@ }); // Display tooltips when the item has focus or hover - $("[data-toggle='tooltip']").on('focus', function(e){ - if($(this).attr('data-content') != undefined){ + $("[data-toggle='tooltip']").on('click', function(e){ + e.preventDefault(); + }); + $("[data-toggle='tooltip']").on('focus mouseenter', function(e){ + e.preventDefault(); + if($(this).attr('data-content') !== undefined){ var y = $(this).width() + 35; - $(this).parent().append('
    ' + $(this).attr('data-content') + '
    '); + $(this).after('
    ' + $(this).attr('data-content') + '
    '); } - }).on('blur', function(e){ + }).on('blur mouseleave', function(e){ $(this).parent().find('div.tooltip-message').remove(); }); - - // Display tooltips when the item has focus or hover + // Display popover when the item has focus or hover $("[data-toggle='popover']").on('click', function(e){ e.preventDefault(); - - if($(this).attr('data-content') != undefined){ - if($(this).parent().find(".popover-message").length > 0){ - $(this).parent().find(".popover-message").remove(); - }else{ - var y = $(this).width() + 35; - $(this).parent().append('
    ' + $(this).attr('data-content') + '
    '); - } + }); + $("[data-toggle='popover']").on('focus mouseenter', function(e){ + e.preventDefault(); + if($(this).attr('data-content') !== undefined){ + var y = $(this).width() + 35; + $(this).after('
    ' + $(this).attr('data-content') + '
    '); } - }).on('blur', function(e){ + }).on('blur mouseleave', function(){ $(this).parent().find('div.popover-message').remove(); }); }); diff --git a/lib/assets/javascripts/views/plans/index.js b/lib/assets/javascripts/views/plans/index.js index d6261b5..4877949 100644 --- a/lib/assets/javascripts/views/plans/index.js +++ b/lib/assets/javascripts/views/plans/index.js @@ -1,23 +1,20 @@ $(document).ready(function(){ + // Update the plan's test status via ajax when the checkbox is clicked $("input[type='checkbox']").on('click, change', function(e){ var self = this; var id = $(this).attr("id").replace("is_test-", ""); var 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){ - var msg = ($(self).is(':checked') ? __('The plan is now a test.') : __('The plan is no longer a test.')); - // If the save was successful make sure the Visibility text gets updated to 'Private' - $("div.roadmap-info-box span:not(.aria-only)").html(msg).attr('role', 'status') - .css('width', 'auto').parent().css('visibility', 'visible'); - $(self).parent().siblings("#visibility-" + id).html(__('Private')); - }else{ - // Display an error message - $("div.roadmap-alert-box span:not(.aria-only)").show().html(data['msg']) - .attr('role', 'alert').css('width', 'auto').css('visibility', 'visible'); - e.preventDefault(); - } - }); + asyncRequest( + {url: "/plans/" + id + "/set_test", + type: 'POST', + data: JSON.stringify(params)}, + {success: function(data){ + if($(self).is(':checked')){ + $("#visibility-" + id + " span").html(__('N/A')).attr('title', ''); + }else{ + $("#visibility-" + id + " span").html(__('Private')) + } + }}); }); }); \ No newline at end of file diff --git a/lib/assets/javascripts/views/plans/share.js b/lib/assets/javascripts/views/plans/share.js index 3ea4591..9d645fc 100644 --- a/lib/assets/javascripts/views/plans/share.js +++ b/lib/assets/javascripts/views/plans/share.js @@ -1,9 +1,43 @@ $(document).ready(function(){ - /*---------------- - Listener for changes in access-level for a plan shared with a user - TODO partial update instead of forcing a page reload - ------------------*/ - $(".toggle-access-level").change(function(){ - $(this).closest('form').submit(); + /*---------------- + Listener for changes in access-level for a plan shared with a user + TODO partial update instead of forcing a page reload + ------------------*/ + $(".toggle-existing-user-access").change(function(){ + var params = {role: {access_level: $(this).find("option:checked").val()}}; + asyncRequest({ + url: "/roles/" + $(this).closest("form").find("#role_id").val(), + type: 'PUT', + data: JSON.stringify(params) }); + }); + + // Run the input validations when the focus changes + $("#role_user_email").on('blur', function(){ + toggleInputError(this, validateEmail($(this).val().trim())); + }); + + // See if we should enable the add collaborator button + $("#role_user_email").on('change keyup', function(){ + toggleAddCollaboratorSubmit(); + }); + $("input[name='role[access_level]']").on('click', function(){ + toggleAddCollaboratorSubmit(); + }); + + $("input[name='plan[visibility]']").on('click, change', function(e){ + var params = {plan: {visibility: $("input[name='plan[visibility]']:checked").val()}}; + asyncRequest({ + url: "/plans/" + $("#plan_id").val() + "/visibility", + type: 'POST', + data: JSON.stringify(params) + }); + }); + + // Display the submit button only if there is a valid email and password + function toggleAddCollaboratorSubmit(){ + var disabled = (validateEmail($("#role_user_email").val()) != '' || + $("input[name='role[access_level]']:checked").val() == undefined); + $("#add-collaborator-button").attr('aria-disabled', disabled); + } }); \ No newline at end of file diff --git a/lib/assets/javascripts/views/plans/show.js b/lib/assets/javascripts/views/plans/show.js new file mode 100644 index 0000000..32e065f --- /dev/null +++ b/lib/assets/javascripts/views/plans/show.js @@ -0,0 +1,73 @@ +$(document).ready(function(){ + // Run the input validations when the focus changes + $("input[type='email']").on('blur', function(){ + toggleInputError(this, validateEmail($(this).val().trim())); + }).on('change keyup', function(){ + toggleProjectDetailsSubmit(); + }); + + $("#plan_title").on('blur', function(){ + toggleInputError(this, ($(this).val().trim().length <= 0 ? __('The title cannot be blank') : ''), true); + }); + + $("#show-data-contact").click(function(){ + toggleDataContact(); + }) + + $("#is_test").click(function(){ + $("#plan_visibility").val($(this).is(":checked") ? 'is_test' : 'privately_visible'); + }); + + $("#show-other-guidance-orgs").click(function(){ + if($("#other-guidance-orgs").css('display') === 'block'){ + $("#other-guidance-orgs").hide(); + $(this).html($(this).html().replace('Hide', __('See'))); + }else{ + $("#other-guidance-orgs").show(); + $(this).html($(this).html().replace('See', __('Hide'))); + } + }); + + $(".guidance-choice").click(function(){ + toggleGuidanceChoices(); + }); + + toggleProjectDetailsSubmit(); + toggleDataContact(); + toggleGuidanceChoices(); + + function toggleDataContact(){ + if($("#show-data-contact").is(':checked')){ + $(".data-contact-info").hide(); + $(".data-contact-info input").val(''); + }else{ + $(".data-contact-info").show(); + } + } + + function toggleProjectDetailsSubmit(){ + var piEmail = $("#plan_principal_investigator_email").val(); + var dcEmail = $("#plan_data_contact_email").val(); + var disabled = $("#plan_title").val() == undefined; + + if(piEmail.trim() != '' && !disabled){ + disabled = validateEmail(piEmail) != ''; + } + if(dcEmail.trim() != '' && !disabled){ + disabled = validateEmail(dcEmail) != ''; + } + + $("#save-details-button").attr('aria-disabled', disabled); + } + + // Only allow up to 3 guidance groups to be selected + function toggleGuidanceChoices(){ + if($(".guidance-choice:checked").length <= 6){ + $(".guidance-choice").removeAttr('disabled'); + $(".guidance-group-label").removeClass('disabled'); + }else{ + $(".guidance-choice:not(:checked)").attr('disabled', 'disabled') + .siblings(".guidance-group-label").addClass('disabled'); + } + } +}); \ No newline at end of file diff --git a/lib/assets/stylesheets/dmproadmap.scss b/lib/assets/stylesheets/dmproadmap.scss index 2772abb..7231f3f 100644 --- a/lib/assets/stylesheets/dmproadmap.scss +++ b/lib/assets/stylesheets/dmproadmap.scss @@ -19,9 +19,18 @@ $highlight-color: $black; $highlight-background-color: #F36F24; -$error-color: #FFF; -$error-background: #827D7E; -$disabled-button-color: #CCC; +/* MESSAGES */ +$error-color: $white; +$error-background: #990000; + +$notice-color: $white; +$notice-background: #196719; + +$tooltip-color: $white; +$tooltip-background: #333; + +/* BUTTONS */ +$disabled-button-color: #808080; $cancel-button-color: #F17D04; /* HEADER STYLING */ @@ -33,4 +42,6 @@ /* HEADER LOGO POSITIONING */ $header-logo-top-margin: 20px; -$header-logo-left-margin: 10px; \ No newline at end of file +$header-logo-left-margin: 10px; + +$body-background: $white; \ No newline at end of file diff --git a/lib/assets/stylesheets/dmproadmap/base.scss b/lib/assets/stylesheets/dmproadmap/base.scss index 3234ee0..0b3f654 100644 --- a/lib/assets/stylesheets/dmproadmap/base.scss +++ b/lib/assets/stylesheets/dmproadmap/base.scss @@ -6,7 +6,7 @@ /* Main page layout: header, content, footer */ body { - background-color: $white; + background: $body-background; color: $black; font-family: $font-family; font-size: 14px; @@ -19,9 +19,14 @@ font-weight: lighter; text-rendering: optimizelegibility; color: $primary-color; + margin-top: 10px; + margin-bottom: 15px; } -h1 { font-size: 40px; } +h1 { + width: 65%; + font-size: 40px; +} h2 { font-size: 32px; } h3 { font-size: 26px; } h4 { font-size: 20px; } @@ -135,12 +140,13 @@ position: absolute; font-family: $font-family; font-size: 14px; - color: $white; - background-color: $dark-grey; + color: $tooltip-color; + background: $tooltip-background; border-radius: 3px; padding: 15px 20px; z-index: 10; - a { + a, a:hover, a:visited, a:focus, + h1, h2, h3, h4, h5 { color: $white; } } @@ -154,8 +160,8 @@ position: absolute; top: 15px; width: 300px; - background-color: $dark-grey; - color: $white; + background: $tooltip-background; + color: $tooltip-color; padding: 6px 10px; border-radius: 3px; z-index: 9; @@ -351,8 +357,7 @@ position: relative; float: right; margin-top: 10px; - padding: 8px 30px; - border: 1px solid $dark-grey; + padding: 8px 30px 10px 60px; border-radius: 5px; vertical-align: middle; width: auto; @@ -372,17 +377,17 @@ } } div.roadmap-info-box { - color: $black; - background-color: $white; + color: $notice-color; + background: $notice-background; .fa { - color: green; + color: $notice-color; } } div.roadmap-alert-box { - color: $black; - background-color: $white; + color: $error-color; + background: $error-background; .fa { - color: red; + color: $error-color; } } @@ -394,10 +399,13 @@ div.page { position: relative; width: 100%; - background-color: $white; + background: $body-background; border-radius: 3px; div.content { + background-color: $white; + border-radius: 3px; + padding: 10px 15px 25px 15px; /* By default, page content is one column, but use the below styles to create a 2 column style */ div.column-left { @@ -414,14 +422,15 @@ /* Description Lists - Used to display the read-only version of forms */ dl { - width: 100%; + width: 85%; margin: 0 auto; dt { display: inline-block; - width: 15%; + width: 25%; text-align: right; margin-right: 10px; + margin-top: 10px; font-weight: bold; } dt:not(.dl-buttons):after { diff --git a/lib/assets/stylesheets/dmproadmap/forms.scss b/lib/assets/stylesheets/dmproadmap/forms.scss index 12e30d8..5b5d7d2 100644 --- a/lib/assets/stylesheets/dmproadmap/forms.scss +++ b/lib/assets/stylesheets/dmproadmap/forms.scss @@ -41,6 +41,10 @@ height: 65px; } +label.disabled { + color: $disabled-button-color; +} + .checkbox-label { display: inline-block; font-size: 1em; @@ -60,12 +64,26 @@ border: 0; } +div.under-input { + display: block; + margin: -5px 0 10px; + + label { + font-weight: normal; + } +} /* Roadmap Form Styling */ /* ------------------------------------------------ */ form.roadmap-form { text-align: top; + div.form-separator { + width: 75%; + margin: 25px auto; + border-bottom: 1px solid $dark-grey; + } + fieldset.padded { padding: 10px 10px 25px 10px; } @@ -78,6 +96,16 @@ text-align: left; margin-bottom: 25px; + div.form-separator { + margin-left: 15px; + } + + .mce-tinymce { + display: inline-block; + margin: 10px 5px 15px 15px; + width: 70%; + } + label, input[type="checkbox"], .combobox-container, @@ -93,6 +121,14 @@ vertical-align: top; } + label:not(.checkbox-label) { + display: block; + } + + input, select { + margin-bottom: 15px; + } + .checkbox-label { font-weight: normal; display: inline-block; @@ -111,6 +147,14 @@ width: 51%; } + div.under-input { + margin-left: 25%; + + label { + width: auto; + } + } + div { label, .button-spacer, @@ -161,7 +205,7 @@ border-bottom: none; } - label { + label:not(.regular-text) { font-weight: bold; } label:not(.no-colon):not(.checkbox-label):after { @@ -175,15 +219,6 @@ clear: both; } - div.inline { - display: inline-block; - } - .left-indent { - margin-left: 15px; - } - .right-indent { - margin-right: 5px; - } .input-full-width { width: 95%; } @@ -207,10 +242,6 @@ width: 550px; } - /* Override the button color for the Org Admin sections */ - input[type="submit"].admin{ - background-color: $primary-color; - } input.form-submit[aria-disabled='true'] { background-color: $disabled-button-color; } @@ -250,43 +281,41 @@ display: none; width: 45%; background: $error-background; - border-radius: 3px; + border-radius: 6px; color: $error-color; - padding: 4px 6px; + padding: 6px 25px 7px 10px; } - .error-tooltip[role='tooltip'], .submit-tooltip[role='tooltip'] { - top: 55px; + .error-tooltip[role='alert'], .submit-tooltip[role='tooltip'] { + top: 65px; left: 0; display: inline; position: absolute; z-index: 9; } - .error-tooltip[role='tooltip']:before, .submit-tooltip[role='tooltip']:before { + .error-tooltip[role='alert']:before, .submit-tooltip[role='tooltip']:before { display: inline; position: absolute; - top: -5px; - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 5px solid $error-background; + top: -30px; + margin: 0 auto; + @include icon(caret-up); + color: $error-background; + font-size: 44px; } - .error-tooltip-right[role="tooltip"] { + .error-tooltip-right[role="alert"], .error-tooltip-right[role="tooltip"] { top: 0; - left: 500px; + left: 400px; display: inline; } - .error-tooltip-right[role='tooltip']:before { + .error-tooltip-right[role='alert']:before, .error-tooltip-right[role="tooltip"] { display: inline; - position: absolute; - left: -5px; - width: 0; - height: 0; - border-top: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 5px solid $error-background; + position: relative; + left: -23px; + top: 11px; + @include icon(caret-left); + color: $error-background; + font-size: 44px; } } @@ -618,35 +647,29 @@ .project-title-container { width: 60%; } -div.show-plan { - width: 60%; - +#details-panel { + hr { - width: 45%; - margin: 5px 0 15px 0; - } - - div.side-by-side { - margin: 10px auto 0 auto; - } - - label { - margin-bottom: 15px; + width: 40%; } } .edit-plan-left { display: inline-block; width: 60%; - - hr { - width: 65%; - } } .edit-plan-right { vertical-align: top; display: inline-block; width: 35%; + h2 { + margin-top: 0; + } + + ul { + list-style: none; + } + .fa { vertical-align: top; font-size: 18px; diff --git a/test/functional/plans_controller_test.rb b/test/functional/plans_controller_test.rb index 8a4327a..69a51d7 100644 --- a/test/functional/plans_controller_test.rb +++ b/test/functional/plans_controller_test.rb @@ -195,7 +195,7 @@ # PUT /plans/:id/update_guidance_choices (update_guidance_choices_plan_path) # ---------------------------------------------------------- test "update the selected guidance" do - params = {guidance_group_ids: [GuidanceGroup.first.id, GuidanceGroup.last.id]} + ids = [GuidanceGroup.first.id, GuidanceGroup.last.id] # Make sure the guidance is attached to the template first so that its a valid selection! q = @template.phases.first.sections.first.questions.first @@ -203,23 +203,24 @@ q.themes << GuidanceGroup.last.guidances.first.themes.first q.save - put update_guidance_choices_plan_path(@plan, format: :json), params + put plan_path(@plan), {plan: {}, guidance_group_ids: ids} assert_unauthorized_redirect_to_root_path # User who does not have access to the plan sign_in User.first - put update_guidance_choices_plan_path(@plan, format: :json), params + put plan_path(@plan), {plan: {}, guidance_group_ids: ids} assert_equal _('You are not authorized to perform this action.'), flash[:alert] assert_response :redirect assert_redirected_to plans_url sign_in @user - put update_guidance_choices_plan_path(@plan, format: :json), params + put plan_path(@plan), {plan: {id: @plan.id}, guidance_group_ids: ids} assert_response :redirect assert_redirected_to plan_path(@plan) @plan.reload ggs = @plan.guidance_groups.ids + assert ggs.include?(GuidanceGroup.first.id), "expected the plan to have the first GuidanceGroup selected" assert ggs.include?(GuidanceGroup.last.id), "expected the plan to have the last GuidanceGroup selected" end diff --git a/test/functional/roles_controller_test.rb b/test/functional/roles_controller_test.rb index c0f7a98..6a61b79 100644 --- a/test/functional/roles_controller_test.rb +++ b/test/functional/roles_controller_test.rb @@ -90,11 +90,7 @@ sign_in @user # Valid save - put role_path(role), {role: params} - assert flash[:notice].start_with?('Successfully') && flash[:notice].include?('saved') - assert_response :redirect - assert_redirected_to share_plan_path(@plan) - assert assigns(:role) + put role_path(role, format: :json), {role: params} assert_equal 13, role.reload.access, "expected the record to have been updated" # TODO: Role should require a user, plan and an access level :/