git-svn-id: http://redmine.rubyforge.org/svn/trunk@95 e93f8b46-1217-0410-a6f0-8f06a7374b81pull/351/head
parent
236c735d08
commit
2b0142580f
@ -0,0 +1,49 @@ |
|||||||
|
# redMine - project management software |
||||||
|
# Copyright (C) 2006 Jean-Philippe Lang |
||||||
|
# |
||||||
|
# This program is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU General Public License |
||||||
|
# as published by the Free Software Foundation; either version 2 |
||||||
|
# of the License, or (at your option) any later version. |
||||||
|
# |
||||||
|
# This program is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with this program; if not, write to the Free Software |
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
|
||||||
|
class QueriesController < ApplicationController |
||||||
|
layout 'base' |
||||||
|
before_filter :require_login, :find_query |
||||||
|
|
||||||
|
def edit |
||||||
|
if request.post? |
||||||
|
@query.filters = {} |
||||||
|
params[:fields].each do |field| |
||||||
|
@query.add_filter(field, params[:operators][field], params[:values][field]) |
||||||
|
end if params[:fields] |
||||||
|
@query.attributes = params[:query] |
||||||
|
|
||||||
|
if @query.save |
||||||
|
flash[:notice] = l(:notice_successful_update) |
||||||
|
redirect_to :controller => 'projects', :action => 'list_issues', :id => @project, :query_id => @query |
||||||
|
end |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def destroy |
||||||
|
@query.destroy if request.post? |
||||||
|
redirect_to :controller => 'reports', :action => 'issue_report', :id => @project |
||||||
|
end |
||||||
|
|
||||||
|
private |
||||||
|
def find_query |
||||||
|
@query = Query.find(params[:id]) |
||||||
|
@project = @query.project |
||||||
|
# check if user is allowed to manage queries (same permission as add_query) |
||||||
|
authorize('projects', 'add_query') |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,6 @@ |
|||||||
|
module QueriesHelper |
||||||
|
|
||||||
|
def operators_for_select(filter_type) |
||||||
|
Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} |
||||||
|
end |
||||||
|
end |
@ -1,106 +0,0 @@ |
|||||||
# redMine - project management software |
|
||||||
# Copyright (C) 2006 Jean-Philippe Lang |
|
||||||
# |
|
||||||
# This program is free software; you can redistribute it and/or |
|
||||||
# modify it under the terms of the GNU General Public License |
|
||||||
# as published by the Free Software Foundation; either version 2 |
|
||||||
# of the License, or (at your option) any later version. |
|
||||||
# |
|
||||||
# This program is distributed in the hope that it will be useful, |
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
# GNU General Public License for more details. |
|
||||||
# |
|
||||||
# You should have received a copy of the GNU General Public License |
|
||||||
# along with this program; if not, write to the Free Software |
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
|
|
||||||
module SearchFilterHelper |
|
||||||
|
|
||||||
def search_filter_criteria(name, options = {}) |
|
||||||
@search_filter ||= {} |
|
||||||
@search_filter[name] ||= {} |
|
||||||
@search_filter[name][:options] = [] |
|
||||||
@search_filter[name][:conditions] = {} |
|
||||||
yield.each { |c| |
|
||||||
@search_filter[name][:options] << [c[0], c[1].to_s] |
|
||||||
@search_filter[name][:conditions].store(c[1].to_s, c[2]) |
|
||||||
} |
|
||||||
end |
|
||||||
|
|
||||||
def search_filter_update |
|
||||||
session[:search_filter] ||= {} |
|
||||||
@search_filter.each_key {|field| session[:search_filter][field] = params[field] } |
|
||||||
end |
|
||||||
|
|
||||||
def search_filter_clause |
|
||||||
session[:search_filter] ||= {} |
|
||||||
clause = ["1=1"] |
|
||||||
@search_filter.each { |k, v| |
|
||||||
filter_value = session[:search_filter][k] || v[:options][0][1] |
|
||||||
if v[:conditions][filter_value] |
|
||||||
clause[0] = clause[0] + " AND " + v[:conditions][filter_value].first |
|
||||||
clause += v[:conditions][filter_value][1..-1] |
|
||||||
end |
|
||||||
} |
|
||||||
clause |
|
||||||
end |
|
||||||
|
|
||||||
def search_filter_tag(criteria, options = {}) |
|
||||||
session[:search_filter] ||= {} |
|
||||||
options[:name] = criteria |
|
||||||
options[:class] += " active-filter" if session[:search_filter][criteria] and session[:search_filter][criteria] != @search_filter[criteria][:options][0][1] |
|
||||||
content_tag("select", |
|
||||||
options_for_select(@search_filter[criteria][:options], session[:search_filter][criteria]), |
|
||||||
options |
|
||||||
) |
|
||||||
end |
|
||||||
|
|
||||||
def search_filter_init_list_issues |
|
||||||
search_filter_criteria('status_id') { |
|
||||||
[ [('['+l(:label_open_issues_plural)+']'), "O", ["issue_statuses.is_closed=?", false]], |
|
||||||
[('['+l(:label_closed_issues_plural)+']'), "C", ["issue_statuses.is_closed=?", true]], |
|
||||||
[('['+l(:label_all)+']'), "A", nil] |
|
||||||
] + IssueStatus.find(:all).collect {|s| [s.name, s.id, ["issues.status_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('tracker_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil] |
|
||||||
] + Tracker.find(:all).collect {|s| [s.name, s.id, ["issues.tracker_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('priority_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil] |
|
||||||
] + Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect {|s| [s.name, s.id, ["issues.priority_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('category_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil], |
|
||||||
[('['+l(:label_none)+']'), "N", ["issues.category_id is null"]] |
|
||||||
] + @project.issue_categories.find(:all).collect {|s| [s.name, s.id, ["issues.category_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('fixed_version_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil], |
|
||||||
[('['+l(:label_none)+']'), "N", ["issues.fixed_version_id is null"]] |
|
||||||
] + @project.versions.collect {|s| [s.name, s.id, ["issues.fixed_version_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('author_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil], |
|
||||||
] + @project.users.collect {|s| [s.display_name, s.id, ["issues.author_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('assigned_to_id') { |
|
||||||
[ [('['+l(:label_all)+']'), "A", nil], |
|
||||||
[('['+l(:label_none)+']'), "N", ["issues.assigned_to_id is null"]] |
|
||||||
] + @project.users.collect {|s| [s.display_name, s.id, ["issues.assigned_to_id=?", s.id]] } |
|
||||||
} |
|
||||||
|
|
||||||
search_filter_criteria('subproject_id') { |
|
||||||
[ [('['+l(:label_none)+']'), "N", ["issues.project_id=?", @project.id]], |
|
||||||
[('['+l(:label_all)+']'), "A", ["(issues.project_id=? or projects.parent_id=?)", @project.id, @project.id]] |
|
||||||
] |
|
||||||
} |
|
||||||
end |
|
||||||
end |
|
@ -0,0 +1,166 @@ |
|||||||
|
# redMine - project management software |
||||||
|
# Copyright (C) 2006 Jean-Philippe Lang |
||||||
|
# |
||||||
|
# This program is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU General Public License |
||||||
|
# as published by the Free Software Foundation; either version 2 |
||||||
|
# of the License, or (at your option) any later version. |
||||||
|
# |
||||||
|
# This program is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with this program; if not, write to the Free Software |
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
|
||||||
|
class Query < ActiveRecord::Base |
||||||
|
belongs_to :project |
||||||
|
belongs_to :user |
||||||
|
serialize :filters |
||||||
|
|
||||||
|
attr_protected :project, :user |
||||||
|
|
||||||
|
validates_presence_of :name, :on => :save |
||||||
|
|
||||||
|
@@operators = { "=" => :label_equals, |
||||||
|
"!" => :label_not_equals, |
||||||
|
"o" => :label_open_issues, |
||||||
|
"c" => :label_closed_issues, |
||||||
|
"!*" => :label_none, |
||||||
|
"*" => :label_all, |
||||||
|
"<t+" => :label_in_less_than, |
||||||
|
">t+" => :label_in_more_than, |
||||||
|
"t+" => :label_in, |
||||||
|
"t" => :label_today, |
||||||
|
">t-" => :label_less_than_ago, |
||||||
|
"<t-" => :label_more_than_ago, |
||||||
|
"t-" => :label_ago, |
||||||
|
"~" => :label_contains, |
||||||
|
"!~" => :label_not_contains } |
||||||
|
|
||||||
|
cattr_reader :operators |
||||||
|
|
||||||
|
@@operators_by_filter_type = { :list => [ "=", "!" ], |
||||||
|
:list_status => [ "o", "=", "!", "c", "*" ], |
||||||
|
:list_optional => [ "=", "!", "!*", "*" ], |
||||||
|
:date => [ "<t+", ">t+", "t+", "t", ">t-", "<t-", "t-" ], |
||||||
|
:date_past => [ ">t-", "<t-", "t-", "t" ], |
||||||
|
:text => [ "~", "!~" ] } |
||||||
|
|
||||||
|
cattr_reader :operators_by_filter_type |
||||||
|
|
||||||
|
def initialize(attributes = nil) |
||||||
|
super attributes |
||||||
|
self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } |
||||||
|
self.is_public = true |
||||||
|
end |
||||||
|
|
||||||
|
def validate |
||||||
|
filters.each_key do |field| |
||||||
|
errors.add field.gsub(/\_id$/, ""), :activerecord_error_blank unless |
||||||
|
# filter requires one or more values |
||||||
|
(values_for(field) and !values_for(field).first.empty?) or |
||||||
|
# filter doesn't require any value |
||||||
|
["o", "c", "!*", "*", "t"].include? operator_for(field) |
||||||
|
end if filters |
||||||
|
end |
||||||
|
|
||||||
|
def available_filters |
||||||
|
return @available_filters if @available_filters |
||||||
|
@available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all).collect{|s| [s.name, s.id.to_s] } }, |
||||||
|
"tracker_id" => { :type => :list, :order => 2, :values => Tracker.find(:all).collect{|s| [s.name, s.id.to_s] } }, |
||||||
|
"priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect{|s| [s.name, s.id.to_s] } }, |
||||||
|
"subject" => { :type => :text, :order => 7 }, |
||||||
|
"created_on" => { :type => :date_past, :order => 8 }, |
||||||
|
"updated_on" => { :type => :date_past, :order => 9 }, |
||||||
|
"start_date" => { :type => :date, :order => 10 }, |
||||||
|
"due_date" => { :type => :date, :order => 11 } } |
||||||
|
unless project.nil? |
||||||
|
# project specific filters |
||||||
|
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => @project.users.collect{|s| [s.name, s.id.to_s] } } |
||||||
|
@available_filters["author_id"] = { :type => :list, :order => 5, :values => @project.users.collect{|s| [s.name, s.id.to_s] } } |
||||||
|
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } } |
||||||
|
# remove category filter if no category defined |
||||||
|
@available_filters.delete "category_id" if @available_filters["category_id"][:values].empty? |
||||||
|
end |
||||||
|
@available_filters |
||||||
|
end |
||||||
|
|
||||||
|
def add_filter(field, operator, values) |
||||||
|
# values must be an array |
||||||
|
return unless values and values.is_a? Array # and !values.first.empty? |
||||||
|
# check if field is defined as an available filter |
||||||
|
if available_filters.has_key? field |
||||||
|
filter_options = available_filters[field] |
||||||
|
# check if operator is allowed for that filter |
||||||
|
#if @@operators_by_filter_type[filter_options[:type]].include? operator |
||||||
|
# allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]}) |
||||||
|
# filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator |
||||||
|
#end |
||||||
|
filters[field] = {:operator => operator, :values => values } |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def add_short_filter(field, expression) |
||||||
|
return unless expression |
||||||
|
parms = expression.scan(/^(o|c|\!|\*)?(.*)$/).first |
||||||
|
add_filter field, (parms[0] || "="), [parms[1] || ""] |
||||||
|
end |
||||||
|
|
||||||
|
def has_filter?(field) |
||||||
|
filters and filters[field] |
||||||
|
end |
||||||
|
|
||||||
|
def operator_for(field) |
||||||
|
has_filter?(field) ? filters[field][:operator] : nil |
||||||
|
end |
||||||
|
|
||||||
|
def values_for(field) |
||||||
|
has_filter?(field) ? filters[field][:values] : nil |
||||||
|
end |
||||||
|
|
||||||
|
def statement |
||||||
|
sql = "1=1" |
||||||
|
sql << " AND issues.project_id=%d" % project.id if project |
||||||
|
filters.each_key do |field| |
||||||
|
v = values_for field |
||||||
|
next unless v and !v.empty? |
||||||
|
sql = sql + " AND " unless sql.empty? |
||||||
|
case operator_for field |
||||||
|
when "=" |
||||||
|
sql = sql + "issues.#{field} IN (" + v.each(&:to_i).join(",") + ")" |
||||||
|
when "!" |
||||||
|
sql = sql + "issues.#{field} NOT IN (" + v.each(&:to_i).join(",") + ")" |
||||||
|
when "!*" |
||||||
|
sql = sql + "issues.#{field} IS NULL" |
||||||
|
when "*" |
||||||
|
sql = sql + "issues.#{field} IS NOT NULL" |
||||||
|
when "o" |
||||||
|
sql = sql + "issue_statuses.is_closed=#{connection.quoted_false}" if field == "status_id" |
||||||
|
when "c" |
||||||
|
sql = sql + "issue_statuses.is_closed=#{connection.quoted_true}" if field == "status_id" |
||||||
|
when ">t-" |
||||||
|
sql = sql + "issues.#{field} >= '%s'" % connection.quoted_date(Date.today - v.first.to_i) |
||||||
|
when "<t-" |
||||||
|
sql = sql + "issues.#{field} <= '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'" |
||||||
|
when "t-" |
||||||
|
sql = sql + "issues.#{field} = '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'" |
||||||
|
when ">t+" |
||||||
|
sql = sql + "issues.#{field} >= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" |
||||||
|
when "<t+" |
||||||
|
sql = sql + "issues.#{field} <= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" |
||||||
|
when "t+" |
||||||
|
sql = sql + "issues.#{field} = '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" |
||||||
|
when "t" |
||||||
|
sql = sql + "issues.#{field} = '%s'" % connection.quoted_date(Date.today) |
||||||
|
when "~" |
||||||
|
sql = sql + "issues.#{field} LIKE '%#{connection.quote_string(v.first)}%'" |
||||||
|
when "!~" |
||||||
|
sql = sql + "issues.#{field} NOT LIKE '%#{connection.quote_string(v.first)}%'" |
||||||
|
end |
||||||
|
end if filters and valid? |
||||||
|
sql |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,6 @@ |
|||||||
|
<h2><%= l(:label_query_new) %></h2> |
||||||
|
|
||||||
|
<%= start_form_tag :action => 'add_query', :id => @project %> |
||||||
|
<%= render :partial => 'queries/form', :locals => {:query => @query} %> |
||||||
|
<%= submit_tag l(:button_create) %> |
||||||
|
<%= end_form_tag %> |
@ -0,0 +1,100 @@ |
|||||||
|
<script> |
||||||
|
|
||||||
|
function add_filter() { |
||||||
|
select = $('add_filter_select'); |
||||||
|
field = select.value |
||||||
|
Element.show('tr_' + field); |
||||||
|
check_box = $('cb_' + field); |
||||||
|
check_box.checked = true; |
||||||
|
toggle_filter(field); |
||||||
|
select.selectedIndex = 0; |
||||||
|
|
||||||
|
for (i=0; i<select.options.length; i++) { |
||||||
|
if (select.options[i].value == field) { |
||||||
|
select.options[i].disabled = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function toggle_filter(field) { |
||||||
|
check_box = $('cb_' + field); |
||||||
|
|
||||||
|
if (check_box.checked) { |
||||||
|
Element.show("operators[" + field + "]"); |
||||||
|
toggle_operator(field); |
||||||
|
} else { |
||||||
|
Element.hide("operators[" + field + "]"); |
||||||
|
Element.hide("values_div[" + field + "]"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function toggle_operator(field) { |
||||||
|
operator = $("operators[" + field + "]"); |
||||||
|
switch (operator.value) { |
||||||
|
case "!*": |
||||||
|
case "*": |
||||||
|
case "t": |
||||||
|
case "o": |
||||||
|
case "c": |
||||||
|
Element.hide("values_div[" + field + "]"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
Element.show("values_div[" + field + "]"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function toggle_multi_select(field) { |
||||||
|
select = $('values[' + field + '][]'); |
||||||
|
if (select.multiple == true) { |
||||||
|
select.multiple = false; |
||||||
|
} else { |
||||||
|
select.multiple = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<fieldset style="margin:0;"><legend><%= l(:label_filter_plural) %></legend> |
||||||
|
<table width="100%" cellpadding=0 cellspacing=0> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<table> |
||||||
|
<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> |
||||||
|
<% field = filter[0] |
||||||
|
options = filter[1] %> |
||||||
|
<tr <%= 'style="display:none;"' unless query.has_filter?(field) %> id="tr_<%= field %>"> |
||||||
|
<td valign="top" width="200"> |
||||||
|
<%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> |
||||||
|
<label for="cb_<%= field %>"><%= l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label> |
||||||
|
</td> |
||||||
|
<td valign="top" width="150"> |
||||||
|
<%= select_tag "operators[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %> |
||||||
|
</td> |
||||||
|
<td valign="top"> |
||||||
|
<div id="values_div[<%= field %>]"> |
||||||
|
<% case options[:type] |
||||||
|
when :list, :list_optional, :list_status %> |
||||||
|
<select <%= "multiple=true" if query.values_for(field) and query.values_for(field).length > 1 %>" name="values[<%= field %>][]" id="values[<%= field %>][]" class="select-small" style="vertical-align: top;"> |
||||||
|
<%= options_for_select options[:values], query.values_for(field) %> |
||||||
|
</select> |
||||||
|
<%= link_to_function image_tag('expand'), "toggle_multi_select('#{field}');" %> |
||||||
|
<% when :date, :date_past %> |
||||||
|
<%= text_field_tag "values[#{field}][]", query.values_for(field), :size => 3, :class => "select-small" %> <%= l(:label_day_plural) %> |
||||||
|
<% when :text %> |
||||||
|
<%= text_field_tag "values[#{field}][]", query.values_for(field), :size => 30, :class => "select-small" %> |
||||||
|
<% end %> |
||||||
|
</div> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
<script>toggle_filter('<%= field %>');</script> |
||||||
|
<% end %> |
||||||
|
</table> |
||||||
|
</td> |
||||||
|
<td align="right" valign="top"> |
||||||
|
<%= l(:label_filter_add) %>: |
||||||
|
<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [l(("field_"+field[0].to_s.gsub(/\_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), :onchange => "add_filter();", :class => "select-small" %> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</fieldset> |
@ -0,0 +1,12 @@ |
|||||||
|
<%= error_messages_for 'query' %> |
||||||
|
|
||||||
|
<!--[form:query]--> |
||||||
|
<div class="box"> |
||||||
|
<div class="tabular"> |
||||||
|
<p><label for="query_name"><%=l(:field_name)%></label> |
||||||
|
<%= text_field 'query', 'name', :size => 80 %></p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<%= render :partial => 'queries/filters', :locals => {:query => query}%> |
||||||
|
</div> |
||||||
|
<!--[eoform:query]--> |
@ -0,0 +1,6 @@ |
|||||||
|
<h2><%= l(:label_query) %></h2> |
||||||
|
|
||||||
|
<%= start_form_tag :action => 'edit', :id => @query %> |
||||||
|
<%= render :partial => 'form', :locals => {:query => @query} %> |
||||||
|
<%= submit_tag l(:button_save) %> |
||||||
|
<%= end_form_tag %> |
@ -0,0 +1,15 @@ |
|||||||
|
class CreateQueries < ActiveRecord::Migration |
||||||
|
def self.up |
||||||
|
create_table :queries, :force => true do |t| |
||||||
|
t.column "project_id", :integer |
||||||
|
t.column "name", :string, :default => "", :null => false |
||||||
|
t.column "filters", :text |
||||||
|
t.column "user_id", :integer, :default => 0, :null => false |
||||||
|
t.column "is_public", :boolean, :default => false, :null => false |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
def self.down |
||||||
|
drop_table :queries |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,9 @@ |
|||||||
|
class AddQueriesPermissions < ActiveRecord::Migration |
||||||
|
def self.up |
||||||
|
Permission.create :controller => "projects", :action => "add_query", :description => "button_create", :sort => 600, :is_public => false, :mail_option => 0, :mail_enabled => 0 |
||||||
|
end |
||||||
|
|
||||||
|
def self.down |
||||||
|
Permission.find(:first, :conditions => ["controller=? and action=?", 'projects', 'add_query']).destroy |
||||||
|
end |
||||||
|
end |
After Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
After Width: | Height: | Size: 266 B |
Loading…
Reference in new issue