mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-27 15:36:39 +08:00
add fe logic for disable/enable fields
This commit is contained in:
parent
8a74546cdf
commit
11e5662c47
17 changed files with 173 additions and 49 deletions
45
app/assets/javascripts/access_permissions/projects.js
Normal file
45
app/assets/javascripts/access_permissions/projects.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
function initNewUserAssignmentFormListener() {
|
||||
$(document).on('change', 'form#new-user-assignment-to-project-form', function() {
|
||||
let values = [];
|
||||
let count = 0;
|
||||
let submitBtn = $(this).find('input[type="submit"]')
|
||||
|
||||
$(this).find('input:checked').each((_, el) => {
|
||||
let select = $(el).closest('.row').find('select');
|
||||
let selectValue = parseInt(select.val(), 10);
|
||||
values.push(selectValue);
|
||||
count += 1;
|
||||
|
||||
if (isNaN(selectValue)) {
|
||||
select.closest('.form-group ')
|
||||
.addClass('has-error');
|
||||
} else {
|
||||
select.closest('.form-group ')
|
||||
.removeClass('has-error');
|
||||
}
|
||||
});
|
||||
|
||||
if (values.includes(NaN) || values.length === 0) {
|
||||
submitBtn.attr('disabled', 'disabled');
|
||||
} else {
|
||||
submitBtn.attr('disabled', false);
|
||||
}
|
||||
|
||||
switch (count) {
|
||||
case 0:
|
||||
submitBtn.val(submitBtn.data('label-default'));
|
||||
break;
|
||||
case 1:
|
||||
submitBtn.val(submitBtn.data('label-singular'));
|
||||
break;
|
||||
default:
|
||||
submitBtn.val(submitBtn.data('label-plural').replace('{num}', count));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initNewUserAssignmentFormListener);
|
||||
})();
|
|
@ -46,6 +46,7 @@
|
|||
//= require shared/autosave_form
|
||||
//= require shared/replace_form
|
||||
//= require shared/remote_destroy
|
||||
//= require shared/toggle_visibility
|
||||
//= require activestorage
|
||||
//= require global_activities/side_pane
|
||||
//= require protocols/header
|
||||
|
@ -55,6 +56,7 @@
|
|||
//= require_directory ./repositories/validators
|
||||
//= require_directory ./dashboard
|
||||
//= require_directory ./sitewide
|
||||
//= require_directory ./access_permissions
|
||||
//= require sidebar
|
||||
//= require turbolinks
|
||||
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
(function () {
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function initRemoteDestroyListeners() {
|
||||
$(document).on('ajax:success', 'a[data-action*="remote-destroy"]', function({ currentTarget }) {
|
||||
let target = currentTarget.getAttribute('data-target')
|
||||
document.querySelector(target).remove()
|
||||
})
|
||||
$(document).on('ajax:success', 'a[data-action*="remote-destroy"]', function({ currentTarget, flash }) {
|
||||
let target = currentTarget.getAttribute('data-target');
|
||||
document.querySelector(target).remove();
|
||||
if (flash) {
|
||||
HelperModule.flashAlertMsg(flash, 'success');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('ajax:error', 'a[data-action*="remote-destroy"]', function(_, data) {
|
||||
HelperModule.flashAlertMsg(data.responseJSON.flash, 'danger');
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initRemoteDestroyListeners);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
(function () {
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function initReplaceFormListeners() {
|
||||
$(document).on('ajax:success', 'form[data-action*="replace-form"]', function(_, {form}) {
|
||||
let newForm = $(form)
|
||||
$(document).on('ajax:success', 'form[data-action*="replace-form"]', function(_, { form, flash }) {
|
||||
let newForm = $(form);
|
||||
let target = this.getAttribute('data-target');
|
||||
|
||||
if (target) {
|
||||
|
@ -11,8 +11,13 @@
|
|||
} else {
|
||||
$(this).replaceWith(newForm);
|
||||
}
|
||||
|
||||
newForm.find('.selectpicker').selectpicker();
|
||||
})
|
||||
|
||||
if (flash) {
|
||||
HelperModule.flashAlertMsg(flash, 'success');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initReplaceFormListeners);
|
||||
|
|
|
@ -8,14 +8,18 @@
|
|||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
$.get(element.getAttribute('href')).then(function({html}) {
|
||||
let targetID = element.getAttribute('data-target')
|
||||
let targetElement = $(element).closest(targetID)
|
||||
let newContainer = $(html)
|
||||
targetElement.replaceWith(newContainer)
|
||||
$.get(element.getAttribute('href')).then(function({html, flash}) {
|
||||
let targetID = element.getAttribute('data-target');
|
||||
let targetElement = $(element).closest(targetID);
|
||||
let newContainer = $(html);
|
||||
targetElement.replaceWith(newContainer);
|
||||
newContainer.find('.selectpicker').selectpicker();
|
||||
})
|
||||
})
|
||||
|
||||
if (flash) {
|
||||
HelperModule.flashAlertMsg(flash, 'success');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initSwapRemoteContainerListeners);
|
||||
|
|
18
app/assets/javascripts/shared/toggle_visibility.js
Normal file
18
app/assets/javascripts/shared/toggle_visibility.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
function initToggleVisibilityListeners() {
|
||||
$(document).on('change', 'input[data-action="toggle-visibility"]', function({currentTarget}) {
|
||||
let toggleId = currentTarget.getAttribute('data-target');
|
||||
let element = document.getElementById(toggleId);
|
||||
|
||||
if (currentTarget.checked) {
|
||||
element.classList.remove('hidden');
|
||||
} else {
|
||||
element.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).one('turbolinks:load', initToggleVisibilityListeners);
|
||||
})();
|
|
@ -45,11 +45,12 @@ module AccessPermissions
|
|||
def create
|
||||
@form = AccessPermissions::NewUserProjectForm.new(current_user, @project)
|
||||
@form.resource_members = permitted_create_params
|
||||
|
||||
respond_to do |format|
|
||||
if @form.save
|
||||
@message = t('access_permissions.create.success', count: @form.resource_members.count)
|
||||
format.json { render :edit }
|
||||
else
|
||||
@message = t('access_permissions.create.failure')
|
||||
format.json { render :new }
|
||||
end
|
||||
end
|
||||
|
@ -58,11 +59,18 @@ module AccessPermissions
|
|||
def destroy
|
||||
user = @project.users.find(params[:user_id])
|
||||
project_member = ProjectMember.new(user, @project)
|
||||
project_member.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: { status: :ok }
|
||||
if project_member.destroy
|
||||
format.json do
|
||||
render json: { flash: t('access_permissions.destroy.success', member_name: user.full_name) },
|
||||
status: :ok
|
||||
end
|
||||
else
|
||||
format.json do
|
||||
render json: { flash: t('access_permissions.destroy.failure') },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,4 +6,8 @@ module UserRolesHelper
|
|||
@user_roles_collection ||= UserRole.all.pluck(:name, :id)
|
||||
end
|
||||
end
|
||||
|
||||
def new_user_roles_collection
|
||||
[[t('user_assignment.select_role'), nil]] + user_roles_collection
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,7 +40,7 @@ class ProjectMember
|
|||
def destroy
|
||||
user_assignment = UserAssignment.find_by!(assignable: @project, user: @user)
|
||||
user_project = UserProject.find_by!(project: @project, user: @user)
|
||||
|
||||
return false if last_project_owner?
|
||||
ActiveRecord::Base.transaction do
|
||||
user_assignment.destroy!
|
||||
user_project.destroy!
|
||||
|
@ -51,6 +51,10 @@ class ProjectMember
|
|||
@assign = ActiveModel::Type::Boolean.new.cast(value)
|
||||
end
|
||||
|
||||
def last_project_owner?
|
||||
project_owners.count == 1 && user_role.owner?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user_role
|
||||
|
@ -72,4 +76,10 @@ class ProjectMember
|
|||
errors.add(:user_role_id, :already_present)
|
||||
end
|
||||
end
|
||||
|
||||
def project_owners
|
||||
@project_owners ||= @project.user_assignments
|
||||
.includes(:user_role)
|
||||
.where(user_roles: { name: 'Owner' })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -83,6 +83,10 @@ class UserRole < ApplicationRecord
|
|||
)
|
||||
end
|
||||
|
||||
def owner?
|
||||
self.name == 'Owner'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prevent_update
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" 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>
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
<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, remote: true, class: 'pull-left', data: { action: 'swap-remote-container', target: '#user_assignments_modal' } do %>
|
||||
<%= link_to resource_path, remote: true, class: 'pull-left spacer', 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', target: '#user_assignments_modal' } }) do |f| %>
|
||||
<%= form_with(model: form_object, url: create_path, method: :post, remote: true, html: { id: 'new-user-assignment-to-project-form', data: { action: 'replace-form', target: '#user_assignments_modal' } }) do |f| %>
|
||||
<div class="modal-body">
|
||||
<% f.object.resource_members.each do |member| %>
|
||||
<%= f.fields_for :resource_members, member do |member_form| %>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<%= f.submit t('.submit'), class: "btn btn-primary" %>
|
||||
<%= f.submit t('.submit'), class: "btn btn-primary", disabled: true, data: { 'label-default' => t('.submit'), 'label-singular' => t('.submit_singular'), 'label-plural' => t('.submit_plural') }%>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
<% project_member = ProjectMember.new(user, project) %>
|
||||
<% item_id = "project-member-#{user.id}" %>
|
||||
|
||||
<%
|
||||
project_member = ProjectMember.new(user, project)
|
||||
item_id = dom_id(user, :project_member)
|
||||
%>
|
||||
|
||||
<%= form_with(model: project_member, url: update_path, method: :put, remote: true, html: { id: item_id, data: { action: 'replace-form autosave-form' } }) do |f| %>
|
||||
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
||||
|
@ -15,20 +18,22 @@
|
|||
<br>
|
||||
<small class="text-muted"><%= project_member.user_role.name %></small>
|
||||
</div>
|
||||
<div class="col-xs-7">
|
||||
<div class="row">
|
||||
<div class="col-xs-7">
|
||||
<% unless user == current_user %>
|
||||
<% unless user == current_user %>
|
||||
<div class="col-xs-7">
|
||||
<div class="row">
|
||||
<div class="col-xs-7">
|
||||
<%= f.select :user_role_id, options_for_select(user_roles_collection, selected: f.object.user_role.id), {}, class: 'form-control selectpicker' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<%= link_to access_permissions_project_path(project, user_id: user, format: :json), remote: true, method: :delete, class: 'btn btn-link', data: { action: 'remote-destroy', target: "##{item_id}" } do %>
|
||||
<span class="fas fa-times"></span>
|
||||
<%= t 'general.remove' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<% unless project_member.last_project_owner? %>
|
||||
<%= link_to access_permissions_project_path(project, user_id: user, format: :json), remote: true, method: :delete, class: 'btn btn-link', data: { action: 'remote-destroy', target: "##{item_id}" } do %>
|
||||
<span class="fas fa-times"></span>
|
||||
<%= t 'general.remove' %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<% project_member = f.object %>
|
||||
<% user = project_member.user %>
|
||||
<%
|
||||
project_member = f.object
|
||||
user = project_member.user
|
||||
id = dom_id(user, :new_project_member)
|
||||
%>
|
||||
|
||||
<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]" %>
|
||||
<%= f.check_box :assign,
|
||||
name: "access_permissions_new_user_project_form[resource_members][#{user.id}][assign]",
|
||||
data: { action: 'toggle-visibility', target: id}
|
||||
%>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
|
@ -19,10 +25,7 @@
|
|||
<span><%= current_assignee_name(user) %></span>
|
||||
</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 class="col-xs-4 form-group hidden" id="<%= id %>">
|
||||
<%= f.select :user_role_id, options_for_select(new_user_roles_collection), {}, name: "access_permissions_new_user_project_form[resource_members][#{user.id}][user_role_id]", class: 'form-control selectpicker pull-right' %>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
|
|
@ -24,3 +24,5 @@ modal_container = controller.render_to_string(
|
|||
|
||||
json.html modal_container
|
||||
json.form modal_container
|
||||
|
||||
json.flash @message
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<% # frozen_string_literal: true %>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<%= render 'access_permissions/partials/edit_assignments_content', project: project, new_resource_path: new_resource_path, update_path: update_path %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2317,7 +2317,16 @@ en:
|
|||
|
||||
user_assignment:
|
||||
current_assignee: "(you)"
|
||||
select_role: "Select role"
|
||||
access_permissions:
|
||||
create:
|
||||
success:
|
||||
one: "You have successfully granted access to %{count} member to the project."
|
||||
other: "You have successfully granted access to %{count} members to the project."
|
||||
failure: "Something went wrong"
|
||||
destroy:
|
||||
success: "You have successfully removed %{member_name} from the project."
|
||||
failure: "Something went wrong"
|
||||
partials:
|
||||
edit_assignments_content:
|
||||
title: "Manage access for to %{resource_name}"
|
||||
|
@ -2325,6 +2334,8 @@ en:
|
|||
new_assignments_form:
|
||||
title: "Select members"
|
||||
submit: "Grand access"
|
||||
submit_singular: "Grand access to 1 user"
|
||||
submit_plural: "Grand access to {num} users"
|
||||
modals:
|
||||
show_modal:
|
||||
title: "Access to %{resource_name}"
|
||||
|
|
Loading…
Add table
Reference in a new issue