Added #roles #trackers #decription to custom field settings

This commit is contained in:
marangoz 2019-08-21 14:23:43 +01:00
parent 5d2e8ff82a
commit 329c81dc41
19 changed files with 230 additions and 53 deletions

View File

@ -152,7 +152,8 @@ class CustomTablesController < ApplicationController
def setting_tabs
@setting_tabs = [
{name: 'general', partial: 'custom_tables/edit', label: :label_general}
{name: 'general', partial: 'custom_tables/edit', label: :label_general},
{name: 'custom_fields', partial: 'custom_tables/settings/custom_fields', label: :label_custom_field_plural}
]
call_hook(:controller_setting_tabs_after, { setting_tabs: @setting_tabs, custom_table: @custom_table })
end

View File

@ -6,6 +6,8 @@ class CustomTable < ActiveRecord::Base
has_many :custom_entities, dependent: :destroy
has_one :custom_entity
has_and_belongs_to_many :projects
has_and_belongs_to_many :trackers
has_and_belongs_to_many :roles
acts_as_nested_set
@ -20,7 +22,22 @@ class CustomTable < ActiveRecord::Base
end
}
safe_attributes 'name', 'author_id', 'main_custom_field_id', 'project_ids', 'is_for_all'
scope :visible, lambda {|*args|
user = args.shift || User.current
if user.admin?
# nop
elsif user.memberships.any?
where("#{table_name}.visible = ? OR #{table_name}.id IN (SELECT DISTINCT cfr.custom_table_id FROM #{Member.table_name} m" +
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
" INNER JOIN #{table_name_prefix}custom_tables_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
" WHERE m.user_id = ?)",
true, user.id)
else
where(:visible => true)
end
}
safe_attributes 'name', 'author_id', 'main_custom_field_id', 'project_ids', 'is_for_all', 'description', 'tracker_ids', 'role_ids', 'visible'
validates :name, presence: true, uniqueness: true

View File

@ -1,11 +1,4 @@
<%= labelled_form_for :custom_table, @custom_table, url: custom_table_path(project_id: @project), html: {multipart: true, id: 'custom_table_form'} do |f| %>
<%= render partial: 'form', locals: {f: f} %>
<% tab = {name: 'CustomEntityCustomField', partial: 'table_fields/index', label: :label_spent_time} %>
<%= content_tag('div', render(partial: 'table_fields/index', locals: {tab: tab, f: f})) %>
<%= javascript_tag do %>
$(function() { $("table.custom_fields tbody").positionedItems(); });
<% end %>
<%= submit_tag l(:button_update) %>
<% end %>

View File

@ -1,15 +1,49 @@
<%= error_messages_for @custom_table %>
<div class="splitcontentleft">
<fieldset class="box"><legend><%= l :label_general %></legend>
<div class = "tabular" >
<p><%= f.text_field :name %></p>
</div>
<div class="box tabular">
<p><%= f.text_field :name, size: 50, required: true %></p>
<p><%= f.text_area :description, rows: 7 %></p>
</div>
<fieldset class="box" id="custom_table_tracker_ids"><legend><%= toggle_checkboxes_link("#custom_table_tracker_ids input[type=checkbox]") %><%=l(:label_tracker_plural)%></legend>
<% tracker_ids = @custom_table.tracker_ids %>
<% Tracker.sorted.each do |tracker| %>
<%= check_box_tag "custom_table[tracker_ids][]",
tracker.id,
tracker_ids.include?(tracker.id),
:id => "custom_table_tracker_ids_#{tracker.id}" %>
<label class="no-css" for="custom_table_tracker_ids_<%=tracker.id%>">
<%= tracker.name %>
</label>
<% end %>
<%= hidden_field_tag "custom_table[tracker_ids][]", '' %>
</fieldset>
</div>
<div class="splitcontentright">
<fieldset class="box tabular"><legend><%= l(:field_visible) %></legend>
<label class="block">
<%= radio_button_tag 'custom_table[visible]', 1, @custom_table.visible?, :id => 'custom_table_visible_on',
onclick: "window.ToggleCheckboxes.roles(true)" %>
<%= l(:label_visibility_public) %>
</label>
<label class="block">
<%= radio_button_tag 'custom_table[visible]', 0, !@custom_table.visible?, :id => 'custom_table_visible_off', onclick: "window.ToggleCheckboxes.roles(false)" %>
<%= l(:label_visibility_roles) %>:
</label>
<% role_ids = @custom_table.role_ids %>
<% Role.givable.sorted.each do |role| %>
<label class="block custom_table_role" style="padding-left:2em;">
<%= check_box_tag 'custom_table[role_ids][]', role.id, role_ids.include?(role.id), :id => nil, class: 'custom_table_roles_radio', disabled: f.object.visible? %>
<%= role.name %>
</label>
<% end %>
<%= hidden_field_tag 'custom_table[role_ids][]', '' %>
</fieldset>
<fieldset class="box"><legend><%= toggle_checkboxes_link("#custom_table_project_ids input[type=checkbox]:enabled") %><%= l(:label_project_plural) %></legend>
<p><%= f.check_box :is_for_all, onclick: "window.AllProjects.toggle($(this).is(':checked'))" %></p>
<p><%= f.check_box :is_for_all, onclick: "window.ToggleCheckboxes.projects($(this).is(':checked'))" %></p>
<div id="custom_field_project_ids">
<% project_ids = @custom_table.project_ids.to_a %>
@ -22,9 +56,12 @@
</div>
<script type="text/javascript">
window.AllProjects = {
toggle: function(checked){
window.ToggleCheckboxes = {
projects: function(checked){
$(".custom_table_project_checkbox").prop('disabled', checked);
},
roles: function(checked){
$(".custom_table_roles_radio").prop('disabled', checked);
},
}
</script>

View File

@ -1,4 +1,4 @@
<%= title [l(:label_custom_tables), custom_tables_path], [@custom_table.name, custom_table_path(@custom_table)], l(:label_settings) %>
<%= render_tabs @setting_tabs %>
<%= render_tabs @setting_tabs, params[:tab] %>
<% html_title(l(:label_settings)) -%>

View File

@ -0,0 +1,10 @@
<%= labelled_form_for :custom_table, @custom_table, url: custom_table_path(project_id: @project, back_url: edit_custom_table_path(@custom_table, tab: 'custom_fields')), html: {multipart: true, id: 'custom_table_form'} do |f| %>
<% tab = {name: 'CustomEntityCustomField', partial: 'table_fields/index', label: :label_spent_time} %>
<%= content_tag('div', render(partial: 'table_fields/index', locals: {tab: tab, f: f})) %>
<%= javascript_tag do %>
$(function() { $("table.custom_fields tbody").positionedItems(); });
<% end %>
<%= submit_tag l(:button_update) %>
<% end %>

View File

@ -1,5 +1,5 @@
<% if User.current.allowed_to?(:manage_custom_tables, nil, global: true) %>
<% issue.project.all_issue_custom_tables.each do |custom_table| %>
<% issue.project.all_issue_custom_tables(issue).each do |custom_table| %>
<% query = custom_table.query(totalable_all: true) %>
<% query.add_short_filter('issue_id', "=#{issue.id}") %>
<% back_url = issue_path(issue) %>
@ -17,7 +17,7 @@
back_url: back_url,
entities: query.results_scope} %>
<% end %>
<% elsif issue.project.all_issue_custom_tables.any? %>
<% elsif issue.project.all_issue_custom_tables(issue).any? %>
<div class="warning">
<p>
<strong><%= l(:text_missing_permission_manage_custom_tables) %></strong>

View File

@ -82,9 +82,7 @@ when "IssueCustomField" %>
<% else %>
<p><%= f.check_box :is_required %></p>
<p><%= f.check_box :is_filter, { checked: true } %></p>
<% if User.current.admin? %>
<p><%= f.text_field :external_name %></p>
<% end %>
<p><%= f.text_field :external_name %></p>
<% end %>
<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
</div>

View File

@ -1,3 +1,8 @@
<% back_url = edit_custom_table_path(@custom_table, tab: 'custom_fields')%>
<div class="contextual">
<%= link_to l(:label_new_column), new_table_field_path(custom_table_id: @custom_table, back_url: back_url), remote: true, class: 'icon icon-custom-fields' %>
</div>
<table class="list custom_fields">
<thead><tr>
<th><%=l(:field_name)%></th>
@ -9,14 +14,14 @@
<tbody>
<% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
<tr class="<%= cycle("odd", "even") %>">
<td class="name"><%= link_to custom_field.name, edit_table_field_path(custom_field, custom_table_id: @custom_table.id), remote: true %></td>
<td class="name"><%= link_to custom_field.name, edit_table_field_path(custom_field, custom_table_id: @custom_table.id, back_url: back_url), remote: true %></td>
<td><%= l(custom_field.format.label) %></td>
<td><%= checked_image custom_field.is_required? %></td>
<td><%= f.radio_button :main_custom_field_id, custom_field.id %></td>
<td class="buttons">
<%= reorder_handle(custom_field, url: custom_field_path(custom_field), param: 'custom_field') %>
<%= link_to l(:button_edit), edit_table_field_path(id: custom_field), remote: true, title: l(:button_edit), class: 'icon-only icon-edit' %>
<%= delete_link table_field_path(custom_field, custom_table_id: @custom_table.id), class: 'icon-only icon-del' %>
<%= link_to l(:button_edit), edit_table_field_path(id: custom_field, back_url: back_url), remote: true, title: l(:button_edit), class: 'icon-only icon-edit' %>
<%= delete_link table_field_path(custom_field, custom_table_id: @custom_table.id, back_url: back_url), class: 'icon-only icon-del' %>
</td>
</tr>
<% end; reset_cycle %>

View File

@ -1,5 +1,5 @@
<%= labelled_form_for :custom_field, @custom_field, url: table_field_path(@custom_field), html: {method: :put, id: 'custom_field_form'} do |f| %>
<%= hidden_field_tag :back_url, edit_custom_table_path(@custom_field.custom_table) %>
<%= hidden_field_tag :back_url, params[:back_url] %>
<%= hidden_field_tag :tab, @tab || params[:tab] %>
<%= render partial: 'form', locals: {f: f} %>
<% end %>

View File

@ -1,4 +1,3 @@
<%= labelled_form_for :custom_field, @custom_field, url: table_fields_path, html: {id: 'custom_field_form'} do |f| %>
<%= render partial: 'form', locals: {f: f} %>
<%= hidden_field_tag :type, @custom_field.type %>

View File

@ -0,0 +1,16 @@
class AddTrackerIdsToCustomTable < ActiveRecord::Migration[5.2]
def change
create_table :custom_tables_trackers, id: false do |t|
t.belongs_to :custom_table
t.belongs_to :tracker
end
create_table :custom_tables_roles, id: false do |t|
t.belongs_to :custom_table
t.belongs_to :role
end
add_column :custom_tables, :description, :text
add_column :custom_tables, :visible, :boolean, null: false, default: true
end
end

View File

@ -8,10 +8,13 @@ module CustomTables
# Returns a scope of all custom tables enabled for project issues
# (explicitly associated custom tables and custom tables enabled for all projects)
def all_issue_custom_tables
CustomTable.
def all_issue_custom_tables(issue)
@custom_tables ||= CustomTable.
joins(:trackers).
visible.
sorted.
where("is_for_all = ? OR id IN (?)", true, custom_table_ids)
where("custom_tables.is_for_all = ? OR custom_tables.id IN (?)", true, custom_table_ids).
where(trackers: {id: issue.tracker})
end
end

View File

@ -98,7 +98,53 @@ FactoryBot.define do
tracker { project.trackers.first }
start_date { Date.today }
due_date { Date.today + 7.days }
priority { IssuePriority.default || FactoryBot.create(:issue_priority, :default) }
association :status, factory: :issue_status
association :author, :factory => :user, :firstname => "Author"
end
factory :enumeration do
name { 'Test' }
trait :default do
name { 'Default' }
is_default { true }
end
end
factory :role do
sequence(:name){ |n| "Role ##{n}" }
permissions { Role.new.setable_permissions.collect(&:name).uniq }
end
factory :issue_priority, parent: :enumeration, class: 'IssuePriority' do
sequence(:name){ |n| "Priority ##{n}" }
end
factory :member_role do
role
member
end
factory :member do
project
user
roles { [] }
after :build do |member, evaluator|
if evaluator.roles.empty?
member.member_roles << FactoryBot.build(:member_role, member: member)
else
evaluator.roles.each do |role|
member.member_roles << FactoryBot.build(:member_role, member: member, role: role)
end
end
end
trait :without_roles do
after :create do |member, evaluator|
member.member_roles.clear
end
end
end
end

View File

@ -0,0 +1,24 @@
require "spec_helper"
describe CustomTable, type: :model do
let(:role) { FactoryBot.create(:role) }
let(:member) { FactoryBot.create(:member) }
let(:user) { FactoryBot.create(:user, memberships: [member]) }
let(:custom_table) { FactoryBot.create(:custom_table, visible: false, roles: user.roles) }
describe 'visible' do
it 'when table is visible' do
expect(CustomTable.visible(user)).to include custom_table
end
context 'should be invisible' do
let(:user) { FactoryBot.create(:user) }
it 'user is not member' do
expect(CustomTable.visible(user)).not_to include custom_table
end
end
end
end

View File

@ -0,0 +1,16 @@
require "spec_helper"
describe Project, type: :model do
let(:tracker) { FactoryBot.create(:tracker) }
let(:project) { FactoryBot.create(:project, trackers: [tracker]) }
let(:issue) { FactoryBot.create(:issue, project: project, tracker: tracker) }
let(:custom_table) { FactoryBot.create(:custom_table, projects: [project], trackers: [tracker]) }
it '#all_issue_custom_tables' do
custom_table
expect(project.all_issue_custom_tables(issue)).
to include custom_table
end
end

View File

@ -0,0 +1,33 @@
require "spec_helper"
RSpec.describe "custom_tables/new" do
include_context 'logged as admin'
let(:tracker) { FactoryBot.create(:tracker) }
let(:role) { FactoryBot.create(:role) }
let(:custom_table) { FactoryBot.create(:custom_table, description: 'Table desc', trackers: [tracker], roles: [role]) }
before(:each) do
@custom_table = assign(:custom_table, custom_table)
end
it "It displays description" do
assign(:custom_table, custom_table)
render
expect(rendered).to match /Table desc/
end
it "It displays trackers" do
assign(:custom_table, custom_table)
render
expect(rendered).to match /#{custom_table.trackers.first.name}/
end
it "It displays roles" do
assign(:custom_table, custom_table)
render
expect(rendered).to match /#{custom_table.roles.first.name}/
end
end

View File

@ -3,7 +3,8 @@ require "spec_helper"
RSpec.describe "issues/_custom_tables" do
include_context 'logged as'
let(:issue) { FactoryBot.create(:issue) }
let(:tracker) { FactoryBot.create(:tracker) }
let(:issue) { FactoryBot.create(:issue, tracker: tracker) }
let(:custom_table) { FactoryBot.create(:custom_table) }
before(:each) do
@ -19,7 +20,6 @@ RSpec.describe "issues/_custom_tables" do
end
context 'with permission' do
let(:issue) { FactoryBot.create(:issue) }
before(:each) do
allow_any_instance_of(User).

View File

@ -1,21 +0,0 @@
require "spec_helper"
RSpec.describe "issues/_query_custom_table" do
include_context 'logged as admin'
helper(QueriesHelper)
let(:issue) { FactoryBot.create(:issue) }
let(:custom_table) { FactoryBot.create(:custom_table) }
it "Displays no data" do
render partial: "issues/query_custom_table", locals: {
query: custom_table.query,
custom_table: custom_table,
back_url: issue_path(issue),
entities: custom_table.query.results_scope }
expect(rendered).to match /No data to display/
end
end