mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-12 09:20:45 +08:00
UX changes for permission modal [SCI-7619]
This commit is contained in:
parent
37eb902b25
commit
00b792b1bb
17 changed files with 87 additions and 56 deletions
|
|
@ -45,6 +45,12 @@
|
||||||
$('.user-assignments-modal').replaceWith(data.html);
|
$('.user-assignments-modal').replaceWith(data.html);
|
||||||
$('.user-assignments-modal').modal('show');
|
$('.user-assignments-modal').modal('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.user-assignment-dropdown .user-role-selector', function() {
|
||||||
|
let roleId = $(this).data('role-id');
|
||||||
|
$(this).closest('.dropdown').find('#user_assignment_user_role_id').val(roleId);
|
||||||
|
$(this).closest('form').trigger('submit');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).one('turbolinks:load', initNewUserAssignmentFormListener);
|
$(document).one('turbolinks:load', initNewUserAssignmentFormListener);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#user_assignments_modal {
|
#user_assignments_modal {
|
||||||
.modal-body {
|
.modal-body {
|
||||||
max-height: 400px;
|
min-height: calc(100vh - 200px);
|
||||||
min-height: 250px;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -33,6 +32,16 @@
|
||||||
|
|
||||||
.user-assignment-controls {
|
.user-assignment-controls {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
||||||
|
.caret {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-assignment-dropdown {
|
||||||
|
a {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-avatar-container {
|
.global-avatar-container {
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,15 @@ module AccessPermissions
|
||||||
|
|
||||||
def update
|
def update
|
||||||
user_id = permitted_update_params[:user_id]
|
user_id = permitted_update_params[:user_id]
|
||||||
@user_assignment = UserAssignment.find_by(
|
@user_assignment = @experiment.user_assignments.find_by(user_id: user_id, team: current_team)
|
||||||
assignable: @experiment,
|
|
||||||
user_id: user_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if permitted_update_params[:user_role_id] == 'reset'
|
if permitted_update_params[:user_role_id] == 'reset'
|
||||||
@user_assignment.update(
|
@user_assignment.update!(
|
||||||
user_role_id: @project.user_assignments.find_by(user_id: user_id).user_role_id,
|
user_role_id: @project.user_assignments.find_by(user_id: user_id, team: current_team).user_role_id,
|
||||||
assigned: :automatically
|
assigned: :automatically
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@user_assignment.update(
|
@user_assignment.update!(
|
||||||
user_role_id: permitted_update_params[:user_role_id],
|
user_role_id: permitted_update_params[:user_role_id],
|
||||||
assigned: :manually
|
assigned: :manually
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,15 @@ module AccessPermissions
|
||||||
|
|
||||||
def update
|
def update
|
||||||
user_id = permitted_update_params[:user_id]
|
user_id = permitted_update_params[:user_id]
|
||||||
@user_assignment = UserAssignment.find_by(
|
@user_assignment = @my_module.user_assignments.find_by(user_id: user_id, team: current_team)
|
||||||
assignable: @my_module,
|
|
||||||
user_id: user_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if permitted_update_params[:user_role_id] == 'reset'
|
if permitted_update_params[:user_role_id] == 'reset'
|
||||||
@user_assignment.update(
|
@user_assignment.update!(
|
||||||
user_role_id: @experiment.user_assignments.find_by(user_id: user_id).user_role_id,
|
user_role_id: @experiment.user_assignments.find_by(user_id: user_id, team: current_team).user_role_id,
|
||||||
assigned: :automatically
|
assigned: :automatically
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@user_assignment.update(
|
@user_assignment.update!(
|
||||||
user_role_id: permitted_update_params[:user_role_id],
|
user_role_id: permitted_update_params[:user_role_id],
|
||||||
assigned: :manually
|
assigned: :manually
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ module AccessPermissions
|
||||||
before_action :available_users, only: %i(new create)
|
before_action :available_users, only: %i(new create)
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@user_assignment = UserAssignment.new(assignable: @protocol, assigned_by: current_user)
|
@user_assignment = @project.user_assignments.new(
|
||||||
|
assigned_by: current_user,
|
||||||
|
team: current_team
|
||||||
|
)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json
|
format.json
|
||||||
|
|
@ -28,7 +31,10 @@ module AccessPermissions
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@user_assignment = UserAssignment.find_by(user_id: permitted_update_params[:user_id], assignable: @project)
|
@user_assignment = @project.user_assignments.find_by(
|
||||||
|
user_id: permitted_update_params[:user_id],
|
||||||
|
team: current_team
|
||||||
|
)
|
||||||
@user_assignment.update!(permitted_update_params)
|
@user_assignment.update!(permitted_update_params)
|
||||||
|
|
||||||
log_activity(:change_user_role_on_project, @user_assignment)
|
log_activity(:change_user_role_on_project, @user_assignment)
|
||||||
|
|
@ -48,7 +54,8 @@ module AccessPermissions
|
||||||
|
|
||||||
user_assignment = UserAssignment.find_or_initialize_by(
|
user_assignment = UserAssignment.find_or_initialize_by(
|
||||||
assignable: @project,
|
assignable: @project,
|
||||||
user_id: user_assignment_params[:user_id]
|
user_id: user_assignment_params[:user_id],
|
||||||
|
team: current_team
|
||||||
)
|
)
|
||||||
|
|
||||||
user_assignment.update!(
|
user_assignment.update!(
|
||||||
|
|
@ -75,7 +82,7 @@ module AccessPermissions
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
user = @project.assigned_users.find(params[:user_id])
|
user = @project.assigned_users.find(params[:user_id])
|
||||||
user_assignment = @project.user_assignments.find_by(user_id: params[:user_id])
|
user_assignment = @project.user_assignments.find_by(user: user, team: current_team)
|
||||||
|
|
||||||
if @project.visible?
|
if @project.visible?
|
||||||
user_assignment.update!(
|
user_assignment.update!(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,11 @@ module AccessPermissions
|
||||||
before_action :check_manage_permissions, except: %i(show)
|
before_action :check_manage_permissions, except: %i(show)
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@user_assignment = UserAssignment.new(assignable: @protocol, assigned_by: current_user)
|
@user_assignment = UserAssignment.new(
|
||||||
|
assignable: @protocol,
|
||||||
|
assigned_by: current_user,
|
||||||
|
team: current_team
|
||||||
|
)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json
|
format.json
|
||||||
|
|
@ -27,7 +31,10 @@ module AccessPermissions
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@user_assignment = UserAssignment.find_by(user_id: permitted_update_params[:user_id], assignable: @protocol)
|
@user_assignment = @protocol.user_assignments.find_by(
|
||||||
|
user_id: permitted_update_params[:user_id],
|
||||||
|
team: current_team
|
||||||
|
)
|
||||||
@user_assignment.update(permitted_update_params)
|
@user_assignment.update(permitted_update_params)
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
|
|
@ -43,6 +50,7 @@ module AccessPermissions
|
||||||
|
|
||||||
user_assignment = UserAssignment.new(user_assignment_params)
|
user_assignment = UserAssignment.new(user_assignment_params)
|
||||||
user_assignment.assignable = @protocol
|
user_assignment.assignable = @protocol
|
||||||
|
user_assignment.team = current_team
|
||||||
user_assignment.assigned_by = current_user
|
user_assignment.assigned_by = current_user
|
||||||
user_assignment.save!
|
user_assignment.save!
|
||||||
end
|
end
|
||||||
|
|
@ -61,7 +69,7 @@ module AccessPermissions
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
user = @protocol.assigned_users.find(params[:user_id])
|
user = @protocol.assigned_users.find(params[:user_id])
|
||||||
user_assignment = @protocol.user_assignments.find_by(user_id: params[:user_id])
|
user_assignment = @protocol.user_assignments.find_by(user: user, team: current_team)
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if user_assignment.destroy
|
if user_assignment.destroy
|
||||||
format.json do
|
format.json do
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<div class="modal fade experiment-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
<div class="modal fade experiment-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
||||||
<div class="modal-dialog modal-md" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="user_assignments_modal">
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<div class="modal fade my-module-assignments-modal" tabindex="-1" role="dialog">
|
<div class="modal fade my-module-assignments-modal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog modal-md" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="user_assignments_modal">
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,5 @@
|
||||||
<%= f.select :default_public_user_role_id, options_for_select(user_roles_collection, selected: project.default_public_user_role_id), {}, class: 'form-control selectpicker', title: t('user_assignment.change_project_role'), data: { 'selected-text-format' => 'static' } %>
|
<%= f.select :default_public_user_role_id, options_for_select(user_roles_collection, selected: project.default_public_user_role_id), {}, class: 'form-control selectpicker', title: t('user_assignment.change_project_role'), data: { 'selected-text-format' => 'static' } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-assignment-remove">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<%
|
<%
|
||||||
object_assignment = UserAssignment.find_by(user_id: user.id, assignable: object)
|
object_assignment = object.user_assignments.find_by(user_id: user.id, team: current_team)
|
||||||
item_id = dom_id(user, :assignment_member)
|
item_id = dom_id(user, :assignment_member)
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%= form_with(model: object_assignment, url: update_path, method: :put, remote: true, html: { class: 'row member-item', id: item_id, data: { action: 'replace-form autosave-form', object_type: :assignment_member } }) do |f| %>
|
<%= form_with(model: object_assignment, url: update_path, method: :put, remote: true, html: { class: 'member-item', id: item_id, data: { action: 'replace-form autosave-form', object_type: :assignment_member } }) do |f| %>
|
||||||
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
||||||
<div class="user-assignment-info">
|
<div class="user-assignment-info">
|
||||||
<div class="global-avatar-container">
|
<div class="global-avatar-container">
|
||||||
|
|
@ -13,25 +13,34 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<%= current_assignee_name(user) %>
|
<%= current_assignee_name(user) %>
|
||||||
<br>
|
|
||||||
<small class="text-muted"><%= user_assignment_resource_role_name(user, object) %></small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-assignment-controls">
|
<div class="user-assignment-controls">
|
||||||
<% unless defined?(with_inherit) && current_user == user %>
|
<% unless defined?(with_inherit) && current_user == user %>
|
||||||
<div class="user-assignment-role">
|
<div class="dropdown pull-right">
|
||||||
<%= f.select :user_role_id, options_for_select(user_roles_collection(with_inherit: defined? with_inherit), selected: f.object.user_role.id), {}, class: 'form-control selectpicker', title: t('user_assignment.change_role'), data: { 'selected-text-format' => 'static' } %>
|
<button class="btn btn-light" type="button" id="userAccess_<%= user.id %>" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
|
<%= f.object.user_role.name %>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<%= f.hidden_field :user_role_id, value: f.object.user_role.id %>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right user-assignment-dropdown" aria-labelledby="userAccess_<%= user.id %>">
|
||||||
|
<% user_roles_collection(with_inherit: defined? with_inherit).each do |role| %>
|
||||||
|
<li>
|
||||||
|
<a href="#" data-turbolinks="false" class="user-role-selector" data-role-id="<%= role[1] %>">
|
||||||
|
<%= role[0] %>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
<% if defined?(delete_path) && !object_assignment.last_assignable_owner? %>
|
||||||
|
<li role="separator" class="divider" data-hook="support-dropdown-separator"></li>
|
||||||
|
<li>
|
||||||
|
<%= link_to delete_path, remote: true, method: :delete, data: { action: 'remote-destroy', target: "##{item_id}" } do %>
|
||||||
|
<%= t('access_permissions.remove_access') %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<% if defined? delete_path %>
|
|
||||||
<div class="user-assignment-remove">
|
|
||||||
<% unless object_assignment.last_assignable_owner? %>
|
|
||||||
<%= link_to delete_path, remote: true, method: :delete, class: 'btn btn-secondary', data: { action: 'remote-destroy', target: "##{item_id}" } do %>
|
|
||||||
<span class="fas fa-times"></span>
|
|
||||||
<%= t 'general.remove' %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<div class="row member-item">
|
<div class="member-item">
|
||||||
<div class="user-assignment-info">
|
<div class="user-assignment-info">
|
||||||
<div class="global-avatar-container">
|
<div class="global-avatar-container">
|
||||||
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<%= current_assignee_name(user) %>
|
<%= current_assignee_name(user) %>
|
||||||
<br>
|
|
||||||
<small class="text-muted"><%= user_assignment_resource_role_name(user, resource) %></small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="user-assignment-controls">
|
||||||
|
<%= resource.user_assignments.find_by(user: user, team: current_team).user_role.name %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<%= link_to new_resource_path, class: 'btn btn-default pull-left', data: { action: 'swap-remote-container', target: '#user_assignments_modal' } do %>
|
<%= 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>
|
<i class="fas fa-plus"></i>
|
||||||
<%= t '.new_resource_assignments', resource: project.model_name.human.downcase %>
|
<%= t('access_permissions.grant_access') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<div class="modal fade project-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
<div class="modal fade project-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
||||||
<div class="modal-dialog modal-md" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="user_assignments_modal">
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<%= link_to new_resource_path, class: 'btn btn-default pull-left', data: { action: 'swap-remote-container', target: '#user_assignments_modal' } do %>
|
<%= 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>
|
<i class="fas fa-plus"></i>
|
||||||
<%= t('.new_resource_assignments', resource: protocol.model_name.human.downcase) %>
|
<%= t('access_permissions.grant_access') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<% # frozen_string_literal: true %>
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
<div class="modal fade protocol-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
<div class="modal fade protocol-assignments-modal" tabindex="-1" role="dialog" data-action="modal-close">
|
||||||
<div class="modal-dialog modal-md" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content" id="user_assignments_modal">
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ json.form controller.render_to_string(
|
||||||
formats: [:html],
|
formats: [:html],
|
||||||
locals: {
|
locals: {
|
||||||
user: @user_assignment.user,
|
user: @user_assignment.user,
|
||||||
protocol: @protocol,
|
object: @protocol,
|
||||||
update_path: access_permissions_protocol_path(@protocol)
|
update_path: access_permissions_protocol_path(@protocol),
|
||||||
|
delete_path: access_permissions_protocol_path(@protocol, user_id: @user_assignment.user_id)
|
||||||
},
|
},
|
||||||
layout: false
|
layout: false
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3054,6 +3054,8 @@ en:
|
||||||
access_permissions:
|
access_permissions:
|
||||||
everyone_else: "Everyone else at %{team_name}"
|
everyone_else: "Everyone else at %{team_name}"
|
||||||
reset: "The inherited role will be applied"
|
reset: "The inherited role will be applied"
|
||||||
|
remove_access: "Remove access"
|
||||||
|
grant_access: "Grant access"
|
||||||
create:
|
create:
|
||||||
success:
|
success:
|
||||||
one: "You have successfully granted access to %{count} member to the project."
|
one: "You have successfully granted access to %{count} member to the project."
|
||||||
|
|
@ -3102,18 +3104,14 @@ en:
|
||||||
modals:
|
modals:
|
||||||
show_modal:
|
show_modal:
|
||||||
title: "Access to %{resource_name}"
|
title: "Access to %{resource_name}"
|
||||||
new_resource_assignments: "Grant new access to %{resource}"
|
|
||||||
edit_modal:
|
edit_modal:
|
||||||
title: "Manage access for %{resource_name}"
|
title: "Manage access for %{resource_name}"
|
||||||
new_resource_assignments: "Grant new access to %{resource}"
|
|
||||||
protocols:
|
protocols:
|
||||||
modals:
|
modals:
|
||||||
show_modal:
|
show_modal:
|
||||||
title: "Access to %{resource_name}"
|
title: "Access to %{resource_name}"
|
||||||
new_resource_assignments: "Grant new access to %{resource}"
|
|
||||||
edit_modal:
|
edit_modal:
|
||||||
title: "Manage access for %{resource_name}"
|
title: "Manage access for %{resource_name}"
|
||||||
new_resource_assignments: "Grant new access to %{resource}"
|
|
||||||
experiments:
|
experiments:
|
||||||
modals:
|
modals:
|
||||||
show_modal:
|
show_modal:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue