mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2026-01-07 00:36:08 +08:00
create form object for role assigment, create helper object for project member, added new user_projects modal
This commit is contained in:
parent
04ef7a4478
commit
c136d953d0
20 changed files with 280 additions and 66 deletions
|
|
@ -44,6 +44,7 @@
|
|||
//= require shared/remote_modal
|
||||
//= require shared/swap_remote_container
|
||||
//= require shared/autosave_form
|
||||
//= require shared/replace_form
|
||||
//= require activestorage
|
||||
//= require global_activities/side_pane
|
||||
//= require protocols/header
|
||||
|
|
|
|||
|
|
@ -229,23 +229,6 @@
|
|||
manageProjectUsersModal.find('.modal-footer').html(data.html_footer);
|
||||
}
|
||||
|
||||
// Initialize manage project users modal remote loading.
|
||||
function initManageProjectUsersLink() {
|
||||
$(projectsWrapper).on('ajax:success', '.manage-project-users-link', function(e, data) {
|
||||
initManageProjectUsersModalBody(data);
|
||||
manageProjectUsersModal.modal('show');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize view project users modal remote loading.
|
||||
function initViewProjectUsersLink() {
|
||||
$('#cardsWrapper').on('ajax:success', '.view-project-users-link', function(e, data) {
|
||||
let viewProjectUsersModal = $('#viewProjectUsersModal');
|
||||
viewProjectUsersModal.find('.modal-title').html(data.html_title);
|
||||
viewProjectUsersModal.find('.modal-body').html(data.html_body);
|
||||
viewProjectUsersModal.modal('show');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize reloading manage user modal content after posting new
|
||||
// user.
|
||||
|
|
@ -637,8 +620,6 @@
|
|||
initExportProjectsModal();
|
||||
initExportProjects();
|
||||
initArchiveRestoreToolbarButtons();
|
||||
initViewProjectUsersLink();
|
||||
initManageProjectUsersLink();
|
||||
initAddUserForm();
|
||||
initRemoveUserLinks();
|
||||
initUserRoleForms();
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@
|
|||
})
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', initAutosaveListeners);
|
||||
$(document).one('turbolinks:load', initAutosaveListeners);
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
'use strict';
|
||||
|
||||
function initRemoteModalListeners() {
|
||||
$(document).on('click', 'a[data-action="remote-modal"]', function(el) {
|
||||
el.stopPropagation();
|
||||
el.preventDefault();
|
||||
$.get(el.target.getAttribute('href')).then(function({modal}) {
|
||||
$(document).on('click', 'a[data-action="remote-modal"]', function(ev) {
|
||||
ev.stopImmediatePropagation();
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
$.get(ev.currentTarget.getAttribute('href')).then(function({modal}) {
|
||||
$(modal).modal('show')
|
||||
.on("shown.bs.modal", function() {
|
||||
$(this).find(".selectpicker").selectpicker();
|
||||
|
|
@ -14,5 +15,5 @@
|
|||
})
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', initRemoteModalListeners);
|
||||
$(document).one('turbolinks:load', initRemoteModalListeners);
|
||||
})();
|
||||
|
|
|
|||
13
app/assets/javascripts/shared/replace_form.js
Normal file
13
app/assets/javascripts/shared/replace_form.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
function initReplaceFormListeners() {
|
||||
$(document).on('ajax:success', 'form[data-action="replace-form"]', function({ form }) {
|
||||
let newForm = $(form)
|
||||
$(this).replaceWith(newForm);
|
||||
newForm.find('.selectpicker').selectpicker();
|
||||
})
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initReplaceFormListeners);
|
||||
})();
|
||||
|
|
@ -2,17 +2,21 @@
|
|||
'use strict';
|
||||
|
||||
function initSwapRemoteContainerListeners() {
|
||||
$(document).on('click', 'a[data-action="swap-remote-container"]', function(el) {
|
||||
let element = el.target;
|
||||
el.stopPropagation();
|
||||
el.preventDefault();
|
||||
$(document).on('click', 'a[data-action="swap-remote-container"]', function(ev) {
|
||||
let element = ev.currentTarget;
|
||||
ev.stopImmediatePropagation();
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
$.get(element.getAttribute('href')).then(function({html}) {
|
||||
let target = element.getAttribute('data-target')
|
||||
document.getElementById(target).insertAdjacentHTML(html)
|
||||
let targetID = element.getAttribute('data-target')
|
||||
let targetElement = $(element).closest(targetID)
|
||||
let newContainer = $(html)
|
||||
targetElement.replaceWith(newContainer)
|
||||
newContainer.find('.selectpicker').selectpicker();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
$(document).on('turbolinks:load', initSwapRemoteContainerListeners);
|
||||
$(document).one('turbolinks:load', initSwapRemoteContainerListeners);
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,19 @@ module AccessPermissions
|
|||
before_action :check_read_permissions, only: %i[show]
|
||||
before_action :check_manage_permissions, only: %i[new create edit update destroy]
|
||||
|
||||
def new
|
||||
available_users = current_team.users.where.not(id: @project.users.pluck(:id))
|
||||
@form = AccessPermissions::NewUserProjectForm.new(
|
||||
current_user,
|
||||
@project,
|
||||
users: available_users
|
||||
)
|
||||
|
||||
respond_to do |format|
|
||||
format.json
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.json
|
||||
|
|
@ -30,6 +43,17 @@ module AccessPermissions
|
|||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@form = AccessPermissions::NewUserProjectForm.new(current_user, @project)
|
||||
@form.resource_members = permitted_create_params
|
||||
|
||||
flash[:notice] = "Success" if @form.save
|
||||
|
||||
respond_to do |format|
|
||||
format.json :new
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def permitted_update_params
|
||||
|
|
@ -37,6 +61,11 @@ module AccessPermissions
|
|||
.permit(user_assignments_attributes: %i[user_role_id _destroy id])
|
||||
end
|
||||
|
||||
def permitted_create_params
|
||||
params.require(:access_permissions_new_user_project_form)
|
||||
.permit(resource_members: %i[assign user_id user_role_id])
|
||||
end
|
||||
|
||||
def set_project
|
||||
@project = Project.includes(user_assignments: [:user, :user_role]).find_by(id: params[:id])
|
||||
|
||||
|
|
|
|||
48
app/forms/access_permissions/new_user_project_form.rb
Normal file
48
app/forms/access_permissions/new_user_project_form.rb
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AccessPermissions
|
||||
class NewUserProjectForm
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :project, :resource_members
|
||||
attr_reader :current_user
|
||||
|
||||
def initialize(current_user, project, attributes = {})
|
||||
@project = project
|
||||
@users = attributes[:users]
|
||||
@current_user = current_user
|
||||
set_defaults if @users
|
||||
@error = false
|
||||
end
|
||||
|
||||
def save
|
||||
if @error
|
||||
false
|
||||
else
|
||||
@resource_members.map(&:save)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def resource_members=(attributes)
|
||||
@resource_members ||= []
|
||||
attributes.fetch(:resource_members).each do |i, resource_member|
|
||||
user = User.find(resource_member[:user_id])
|
||||
project_member = ProjectMember.new(user, @project, current_user)
|
||||
project_member.assign = resource_member[:assign]
|
||||
project_member.user_role_id = resource_member[:user_role_id]
|
||||
byebug
|
||||
@error = true unless project_member.valid?
|
||||
|
||||
@resource_members << project_member
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
@resource_members ||= @users.order(:full_name).map { |u| ProjectMember.new(u, @project, current_user) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
module UserRolesHelper
|
||||
def user_roles_collection
|
||||
Rails.cache.fetch([current_user, 'available_user_roles']) do
|
||||
@user_roles_collection ||= UserRole.all.pluck(:name, :id)
|
||||
@user_roles_collection ||= [[t('user_assignment.select.default_option'), nil]] + UserRole.all.pluck(:name, :id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
54
app/models/project_member.rb
Normal file
54
app/models/project_member.rb
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectMember
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :user, :project, :assign, :user_role_id, :user_id
|
||||
attr_reader :current_user
|
||||
|
||||
validates :user, :project, :user_role_id, presence: true
|
||||
validate :role_presence
|
||||
validate :validate_user_project_relation_presence
|
||||
validate :validate_user_project_assignment_presence
|
||||
|
||||
def initialize(user, project, current_user)
|
||||
@user = user
|
||||
@project = project
|
||||
@current_user = current_user
|
||||
end
|
||||
|
||||
def save
|
||||
return unless assign
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
UserProject.create!(project: @project, user: @user)
|
||||
UserAssignment.create!(assignable: @project, user: @user, user_role: set_user_role, assigned_by: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def assign=(value)
|
||||
@assign = ActiveModel::Type::Boolean.new.cast(value)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user_role
|
||||
UserRole.find!(user_role_id)
|
||||
end
|
||||
|
||||
def role_presence
|
||||
errors.add(:user_role_id) if UserRole.find(user_role_id).nil?
|
||||
end
|
||||
|
||||
def validate_user_project_relation_presence
|
||||
if UserProject.find_by(project: @project, user: @user).present?
|
||||
errors.add(:user)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_user_project_assignment_presence
|
||||
if UserAssignment.find_by(assignable: @project, user: @user).present?
|
||||
errors.add(:user_role_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="user_assignments_modal">
|
||||
<%= form_with(model: resource, url: update_path, remote: true, html: { data: { action: 'autosave-form' } }) do |f| %>
|
||||
<div class="modal-header">
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<%= f.nested_fields_for :user_assignments, resource.user_assignments, wrapper_options: { class: 'row' } do |user_assignment_form| %>
|
||||
<%= render('access_permissions/partials/user_assignment_field.html.erb', f: user_assignment_form) if user_assignment_form.object.persisted? %>
|
||||
<%= render('access_permissions/partials/user_permission_field.html.erb', f: user_assignment_form) if user_assignment_form.object.persisted? %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content" id="user_assignments_modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
|
|
@ -11,7 +11,12 @@
|
|||
<%= render partial: 'access_permissions/partials/user_assignment', collection: resource.user_assignments, cached: ->(user_assignment) { [user_assignment. resource, current_user] } %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
|
||||
<% if can_manage_resource %>
|
||||
<%= link_to new_resource_path, class: 'btn btn-default pull-left', data: { action: 'swap-remote-container', target: '#user_assignments_modal' } do %>
|
||||
<i class="fas fa-plus"></i>
|
||||
<%= t '.new_resource_assignments', resource: resource.model_name.human.downcase %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<div class="modal-content" id="user_assignments_modal">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">
|
||||
<%= link_to resource_path, class: 'pull-left', data: { action: 'swap-remote-container', target: '#user_assignments_modal' } do %>
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
<% end %>
|
||||
<%= t '.title', resource_name: resource.name %>
|
||||
</h4>
|
||||
</div>
|
||||
<%= form_with(model: form_object, url: create_path, method: :post, remote: true, html: { data: { action: 'replace-form' } }) do |f| %>
|
||||
<div class="modal-body">
|
||||
<% f.object.resource_members.each do |member| %>
|
||||
<%= f.fields_for :resource_members, member do |member_form| %>
|
||||
<%= render 'access_permissions/partials/user_assignment_field.html.erb', f: member_form %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<%= f.submit t('.submit'), class: "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -1,31 +1,28 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<% user_assignment = f.object %>
|
||||
<% project_member = f.object %>
|
||||
<% user = project_member.user %>
|
||||
|
||||
<div class="col-xs-2">
|
||||
<span class="global-avatar-container">
|
||||
<%= image_tag avatar_path(user_assignment.user, :icon_small), title: current_assignee_name(user_assignment.user), class: 'img-circle pull-left' %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<%= f.hidden_field :user_id, value: user.id, name:"access_permissions_new_user_project_form[resource_members][#{user.id}][user_id]" %>
|
||||
<div class="col-xs-1 checkbox text-center">
|
||||
<label>
|
||||
<%= f.check_box :assign, name: "access_permissions_new_user_project_form[resource_members][#{user.id}][assign]" %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<span class="global-avatar-container">
|
||||
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<span><%= current_assignee_name(user) %></span>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-3">
|
||||
<span><%= current_assignee_name(user_assignment.user) %></span>
|
||||
<br>
|
||||
<small class="text-muted"><%= user_assignment.user_role.name %></small>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-7">
|
||||
<div class="row">
|
||||
<div class="col-xs-7">
|
||||
<% unless user_assignment.user == current_user %>
|
||||
<%= f.select :user_role_id, options_for_select(user_roles_collection), {}, class: 'form-control selectpicker' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<%= f.remove_nested_fields_link class: 'btn btn-link' do %>
|
||||
<span class="fas fa-times"></span>
|
||||
<%= t 'general.remove' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-xs-4 form-group">
|
||||
<% unless user == current_user %>
|
||||
<%= f.select :user_role_id, options_for_select(user_roles_collection), {}, name: "access_permissions_new_user_project_form[resource_members][#{user.id}][user_role_id]", class: 'form-control selectpicker pull-right' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
<% user_assignment = f.object %>
|
||||
|
||||
<div class="col-xs-2">
|
||||
<span class="global-avatar-container">
|
||||
<%= image_tag avatar_path(user_assignment.user, :icon_small), title: current_assignee_name(user_assignment.user), class: 'img-circle pull-left' %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<span><%= current_assignee_name(user_assignment.user) %></span>
|
||||
<br>
|
||||
<small class="text-muted"><%= user_assignment.user_role.name %></small>
|
||||
</div>
|
||||
<div class="col-xs-7">
|
||||
<div class="row">
|
||||
<div class="col-xs-7">
|
||||
<% unless user_assignment.user == current_user %>
|
||||
<%= f.select :user_role_id, options_for_select(user_roles_collection), {}, class: 'form-control selectpicker' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<%= f.remove_nested_fields_link class: 'btn btn-link' do %>
|
||||
<span class="fas fa-times"></span>
|
||||
<%= t 'general.remove' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -3,6 +3,10 @@
|
|||
json.modal controller.render_to_string(
|
||||
partial: 'access_permissions/modals/edit_modal',
|
||||
formats: [:html],
|
||||
locals: { resource: @project, update_path: access_permissions_project_path(@project, format: :json), new_resource_path: new_access_permissions_project_path },
|
||||
locals: {
|
||||
resource: @project,
|
||||
update_path: access_permissions_project_path(@project, format: :json),
|
||||
new_resource_path: new_access_permissions_project_path(id: @project, format: :json)
|
||||
},
|
||||
layout: false
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
json.html controller.render_to_string(
|
||||
partial: 'access_permissions/partials/new_assignments_form',
|
||||
formats: [:html],
|
||||
locals: {
|
||||
resource: @project,
|
||||
form_object: @form,
|
||||
create_path: access_permissions_projects_path(id: @project.id, format: :json),
|
||||
resource_path: edit_access_permissions_project_path(@project, format: :json)
|
||||
},
|
||||
layout: false
|
||||
)
|
||||
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
json.modal controller.render_to_string(
|
||||
partial: 'access_permissions/modals/show_modal',
|
||||
formats: [:html],
|
||||
locals: { resource: @project },
|
||||
locals: {
|
||||
resource: @project,
|
||||
can_manage_resource: can_manage_project?(@project)
|
||||
},
|
||||
layout: false
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,14 +51,14 @@
|
|||
<span class="card-label"><%= t('projects.index.card.users') %></span>
|
||||
<div class="value">
|
||||
<% if can_manage_project?(project) %>
|
||||
<%= link_to edit_project_users_path(project), class: 'project-users-link manage-project-users-link', remote: true do %>
|
||||
<%= link_to edit_access_permissions_project_path(project, format: :json), class: 'project-users-link', data: { action: 'remote-modal' } do %>
|
||||
<%= render partial: 'projects/index/users_list.html.erb', locals: { project: project } %>
|
||||
<span class="new-user global-avatar-container">
|
||||
<i class="fas fa-plus"></i>
|
||||
</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= link_to project_users_path(project), class: 'project-users-link view-project-users-link', remote: true do %>
|
||||
<%= link_to access_permissions_project_path(project, format: :json), class: 'project-users-link', data: { action: 'remote-modal' } do %>
|
||||
<%= render partial: 'projects/index/users_list.html.erb', locals: { project: project } %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -2316,14 +2316,21 @@ en:
|
|||
default_task_name: "New Task"
|
||||
|
||||
user_assignment:
|
||||
select:
|
||||
default_option: "Select User role"
|
||||
current_assignee: "(you)"
|
||||
access_permissions:
|
||||
partials:
|
||||
new_assignments_form:
|
||||
title: "Select members"
|
||||
submit: "Grand access"
|
||||
modals:
|
||||
edit_modal:
|
||||
title: "Manage access for to %{resource_name}"
|
||||
new_resource_assignments: "Grant new access to %{resource}"
|
||||
show_modal:
|
||||
title: "Access to %{resource_name}"
|
||||
new_resource_assignments: "Grant new access to %{resource}"
|
||||
zip_export:
|
||||
modal_label: 'Export inventory'
|
||||
notification_title: 'Your requested export package is ready!'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue