diff --git a/CHANGELOG.md b/CHANGELOG.md index b5637083df..0dbef08333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +- Redesigned plan-creation page to enforce template access rules and simplify UI [#3534](https://github.com/DMPRoadmap/roadmap/issues/3534) + ## v5.0.2 - Bump Ruby to v3.1.4 and use `.ruby-version` in CI - [#3566](https://github.com/DMPRoadmap/roadmap/pull/3566) diff --git a/app/assets/stylesheets/blocks/_forms.scss b/app/assets/stylesheets/blocks/_forms.scss index 59dfd49f88..1fb27cfead 100644 --- a/app/assets/stylesheets/blocks/_forms.scss +++ b/app/assets/stylesheets/blocks/_forms.scss @@ -1,21 +1,55 @@ @use '../variables/colours' as *; -.form-control { - border: 0px; -} -.form-control input, .form-control textarea, .form-control select{ - border: 2px solid $color-border-light; + +.form-control input, +.form-control textarea, +.form-control select { + border: 2px solid $color-border-light; } .form-check { - padding-left: 0rem; + padding-left: 0rem; } -.form-inline{ - margin-bottom: 5px; +.form-inline { + margin-bottom: 5px; } .form-check-label { - padding-left: 5px; + padding-left: 5px; +} + +// Added for new plan create page app/views/plans/new.html.erb +.roadmap-form { + margin-bottom: 1rem; + + legend { + padding-inline: 2px; + float: none; + width: auto; + padding: 0.5rem; + font-size: 1rem; + background-color: $color-primary-background; + color: $color-primary-text; + } + + fieldset { + border: 2px solid #555555; + padding: 1rem; + margin-bottom: 1rem; + } + + .form-row { + margin-bottom: 1rem; + } + + .form-row:last-child { + margin-bottom: 0; + } + + .form-check .form-check-input { + float: left; + margin-left: 0.5rem; + } } diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index c66bbfdeb4..677addc013 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -29,31 +29,15 @@ def index # rubocop:enable Metrics/AbcSize # GET /plans/new - # rubocop:disable Metrics/AbcSize def new @plan = Plan.new authorize @plan + org_id = current_user.org&.id - # Get all of the available funders and non-funder orgs - @funders = Org.funder - .includes(identifiers: :identifier_scheme) - .joins(:templates) - .where(templates: { published: true }).uniq.sort_by(&:name) - @orgs = (Org.includes(identifiers: :identifier_scheme).organisation + - Org.includes(identifiers: :identifier_scheme).institution + - Org.includes(identifiers: :identifier_scheme).default_orgs) - @orgs = @orgs.flatten.uniq.sort_by(&:name) - - @plan.org_id = current_user.org&.id - - # TODO: is this still used? We cannot switch this to use the :plan_params - # strong params because any calls that do not include `plan` in the - # query string will fail - flash[:notice] = "#{_('This is a')} #{_('test plan')}" if params.key?(:test) - @is_test = params[:test] ||= false + # Get templates grouped hash + @templates_grouped = templates_available_to_org_user(org_id) respond_to :html end - # rubocop:enable Metrics/AbcSize # POST /plans # rubocop:disable Metrics/AbcSize, Metrics/MethodLength @@ -71,6 +55,15 @@ def create format.html { redirect_to new_plan_path } end else + template_id = plan_params[:template_id].to_i + unless validate_template_available_to_org_user?(template_id, current_user.org_id) + respond_to do |format| + flash[:alert] = _('The selected template is not available to your organisation.') + format.html { redirect_to new_plan_path } + end + return + end + @plan.visibility = if plan_params['visibility'].blank? Rails.configuration.x.plans.default_visibility else @@ -537,5 +530,67 @@ def render_phases_edit(plan, phase, guidance_groups) guidance_presenter: GuidancePresenter.new(plan) }) end + + # Get templates available to org users + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def templates_available_to_org_user(org_id) + # looks into the list of families of templates + customizations = Template.latest_customized_version_per_org(org_id) + customization_ids = customizations.select(&:published?).collect(&:customization_of) + + # get templates of user's own org + user_org_own_templates = Template.organisationally_visible + .where(org_id: org_id, customization_of: nil) + .published + .uniq.sort_by(&:title) + + # get templates of user's customised org + user_org_custom_templates = Template.latest_customized_version_per_org(org_id) + .published + .uniq.sort_by(&:title) + + # get funder templates no customised templates + funder_non_customised_templates = Template.published + .joins(:org) + .where(orgs: { org_type: Org.org_type_values_for(:funder) }) + # The next line removes templates that belong to a family that + # has customised templates + .where.not(family_id: customization_ids) + .uniq.sort_by(&:title) + + # get global templates + global_templates = Template.published + .where(is_default: true) + # The next line removes templates that belong to a family that + # has customised templates + .where.not(family_id: customization_ids) + .uniq.sort_by(&:title) + + # create templates-grouped hash + @templates_grouped = { + _("Your Organisation's Templates:") => user_org_own_templates.map do |t| + [t.title, t.id] + end, + _("Your Organisation's Customised Templates:") => user_org_custom_templates.map do |t| + [t.title, t.id] + end, + _('Global Templates:') => global_templates.map do |t| + [t.title, t.id] + end, + _('Funder Templates:') => funder_non_customised_templates.map do |t| + [t.title, t.id] + end + }.reject { |_, val| val.empty? } + end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + + # Validate that a template_id is available to the org user + def validate_template_available_to_org_user?(template_id, org_id) + return false if template_id.blank? || org_id.blank? + + available_templates = templates_available_to_org_user(org_id) + available_template_ids = available_templates.values.flat_map { |group| group.map(&:last) } + available_template_ids.include?(template_id.to_i) + end end # rubocop:enable Metrics/ClassLength diff --git a/app/views/plans/new.html.erb b/app/views/plans/new.html.erb index c9838b70dd..fee232424b 100644 --- a/app/views/plans/new.html.erb +++ b/app/views/plans/new.html.erb @@ -1,125 +1,90 @@ -<% title _('Create a new plan') %> -<% required_project_title_tooltip = _('This field is required.') %> -<% project_title_tooltip = _('If applying for funding, state the project title exactly as in the proposal.') %> -<% required_research_org_tooltip = _('You must select a research organisation from the list or click the checkbox.') %> -<% research_org_tooltip = _('Please select a valid research organisation from the list.') %> -<% required_primary_funding_tooltip = _('You must select a funder from the list or click the checkbox.') %> -<% primary_funding_tooltip = _('Please select a valid funding organisation from the list.') %> - -
- <%= _("Before you get started, we need some information about your research project to set you up with the best DMP template for your needs.") %> -
+