add foodcoop configuration screen

This commit is contained in:
wvengen 2014-03-16 02:08:15 +01:00
parent dd3ac0971c
commit 7b000c39eb
20 changed files with 562 additions and 12 deletions

View file

@ -140,6 +140,23 @@ table {
text-align: center;
}
// Navigation with embedded tabs
.nav-tabs-with-heading {
> li {
line-height: 40px;
margin-top: 16.5px;
a { padding-bottom: 9px; }
}
> li.heading {
> h1, > h2, > h3 {
font-size: 31.5px;
line-height: 40px;
margin: 0;
}
margin: 10px 1em 5px 0;
}
}
// Tasks ..
.accepted {
color: #468847;
@ -324,6 +341,15 @@ table.table {
}
}
// inline (boolean) position after/before heading
label {
h1, h2, h3, h4 {
input[type=checkbox] {
margin: auto 0.3em auto 0.3em;
}
}
}
// it's a bit distracting
.icon-asterisk {
font-size: 80%;

View file

@ -0,0 +1,39 @@
class Admin::ConfigsController < Admin::BaseController
before_action :get_tabs, only: [:show, :list]
def show
@current_tab = @tabs.include?(params[:tab]) ? params[:tab] : @tabs.first
@cfg = FoodsoftConfig
end
def list
@current_tab = 'list'
@cfg = FoodsoftConfig
@dfl = FoodsoftConfig.config
@keys = FoodsoftConfig.keys.select {|k| FoodsoftConfig.allowed_key?(k)}.sort
end
def update
ActiveRecord::Base.transaction do
# TODO support nested configuration keys
params[:config].each do |key, val|
FoodsoftConfig[key] = val
end
end
flash[:notice] = I18n.t('admin.configs.update.notice')
redirect_to action: 'show'
end
protected
# Set configuration tab names as `@tabs`
def get_tabs
@tabs = %w(foodcoop payment tasks messages layout language others)
# allow engines to modify this list
engines = Rails::Engine.subclasses.map(&:instance).select { |e| e.respond_to?(:configuration) }
engines.each { |e| e.configuration(@tabs, self) }
@tabs.uniq!
end
end

View file

@ -0,0 +1,117 @@
module Admin::ConfigsHelper
# Returns form input for configuration key.
# For configuration keys that contain a {Hash}, {ActiveView::Helpers::FormBuilder#fields_for fields_for} can be used.
# @param form [ActionView::Helpers::FormBuilder] Form object.
# @param key [Symbol, String] Configuration key.
# @param options [Hash] Options passed to the form builder.
# @option options [Boolean] :required Wether field is shown as required (default not).
# @return [String] Form input for configuration key.
def config_input(form, key, options = {}, &block)
options[:label] = config_input_label(form, key)
options[:required] ||= false
options[:input_html] ||= {}
config_input_field_options form, key, options[:input_html]
config_input_tooltip_options form, key, options[:input_html]
if options[:as] == :boolean
options[:input_html][:checked] = 'checked' if options[:input_html].delete(:value)
options[:checked_value] = true
options[:unchecked_value] = false
elsif options[:collection] or options[:as] == :select
options[:selected] = options[:input_html].delete(:value)
return form.input key, options, &block
end
form.input key, options, &block
end
# @return [String] Label name in form for configuration key.
# @param form [ActionView::Helpers::FormBuilder] Form object.
# @param key [Symbol, String] Configuration key.
# @see #config_input
def config_input_label(form, key)
cfg_path = form.lookup_model_names[1..-1] + [key]
I18n.t("config.keys.#{cfg_path.map(&:to_s).join('.')}")
end
# @return [String] Form input field for configuration key.
# @see config_input
# @todo find out how to pass +checked_value+ and +unchecked_value+ to +input_field+
def config_input_field(form, key, options = {})
config_input_field_options form, key, options
config_input_tooltip_options form, key, options
if options[:as] == :boolean
options[:checked] = 'checked' if options.delete(:value)
form.hidden_field(key, value: false, as: :hidden) + form.check_box(key, options, true, false)
else
form.input_field key, options
end
end
# @return [String] Form heading with checkbox with block passed in expandable +fieldset+.
# @param form [ActionView::Helpers::FormBuilder] Form object.
# @param key [Symbol, String] Configuration key of a boolean (e.g. +use_messages+).
# @option options [String] :label Label to show
def config_use_heading(form, key, options = {})
head = content_tag :label do
lbl = options[:label] || config_input_label(form, key)
field = config_input_field(form, key, as: :boolean, boolean_style: :inline,
data: {toggle: 'collapse', target: "##{key}-fields"})
content_tag :h4 do
# put in span to keep space for tooltip at right
content_tag :span, (lbl + field).html_safe, config_input_tooltip_options(form, key, {})
end
end
fields = content_tag(:fieldset, id: "#{key}-fields", class: "collapse#{' in' if @cfg[key]}") do
yield
end
head + fields
end
# Returns configuration value suitable for rendering in HTML.
# Makes keys different from +app_config.yml+ configuration bold,
# protects sensitive values like keys and passwords, and makes
# links from URLs.
# @param key [String] Configuration key
# @param value [String] Configuration value
# @return [String] Configuration value suitable for rendering in HTML.
def show_config_value(key, value)
if key =~ /passw|secr|key/
'(protected)'
elsif value.is_a? Hash
content_tag :ul do
value.map do |k,v|
content_tag :li, content_tag(:tt, "#{k}: ") + show_config_value(k, v).to_s
end.join.html_safe
end
elsif value.is_a? Enumerable
content_tag :ul, value.map {|v| content_tag :li, h(v)}.join.html_safe
elsif key =~ /url|website|www|homepage/
link_to(value, value).html_safe
else
value
end
end
private
def config_input_tooltip_options(form, key, options)
# tooltip with help info to the right
cfg_path = form.lookup_model_names[1..-1] + [key]
tooltip = I18n.t("config.hints.#{cfg_path.map(&:to_s).join('.')}", default: '')
unless tooltip.blank?
options[:data] ||= {}
options[:data][:toggle] ||= 'tooltip'
options[:data][:placement] ||= 'right'
options[:title] ||= tooltip
end
options
end
def config_input_field_options(form, key, options)
cfg_path = form.lookup_model_names[1..-1] + [key]
# set current value
value = @cfg
cfg_path.each {|n| value = value[n] unless value.nil? }
options[:value] ||= value
options
end
end

View file

@ -0,0 +1,10 @@
= config_input form, :name, required: true, input_html: {class: 'input-xlarge'}
= form.fields_for :contact do |c|
= config_input c, :street, input_html: {class: 'input-xlarge'}
.fold-line
= config_input c, :zip_code, input_html: {class: 'input-mini'}
= config_input c, :city, input_html: {class: 'input-medium'}
= config_input c, :country, as: :string, input_html: {class: 'input-xlarge'}
= config_input c, :email, required: true, input_html: {class: 'input-xlarge'}
= config_input c, :phone, input_html: {class: 'input-medium'}
= config_input form, :homepage, required: true, as: :url, input_html: {class: 'input-xlarge'}

View file

@ -0,0 +1,3 @@
= config_input form, :default_locale,
collection: I18n.available_locales.map {|l| [t("simple_form.options.settings.profile.language.#{l}"), l]}
= config_input form, :ignore_browser_locale, as: :boolean

View file

@ -0,0 +1,7 @@
= config_input form, :page_footer, as: :text, input_html: {class: 'input-xxlarge', rows: 2, placeholder: "#{link_to(FoodsoftConfig[:name], FoodsoftConfig[:homepage])}"}
%h4= t '.pdf_title'
.fold-line
= config_input form, :pdf_font_size, as: :integer, input_html: {class: 'input-mini'}
= config_input form, :pdf_page_size, input_html: {class: 'input-medium'}
= config_input form, :pdf_add_page_breaks, as: :boolean

View file

@ -0,0 +1,7 @@
%fieldset
%label
%h4= t '.emails_title'
= config_input form, :email_from, as: :string, input_html: {class: 'input-xlarge', placeholder: "#{@cfg[:name]} <#{@cfg[:contact][:email]}>"}
= config_input form, :email_replyto, as: :string, input_html: {class: 'input-xlarge'}
-# sender is better configured by server administrator, since it affects SPF records
-#= config_input form, :email_sender, as: :string, input_html: {class: 'input-xlarge'}

View file

@ -0,0 +1,5 @@
- if defined? FoodsoftWiki # avoid requiring deface here (the single exception)
= config_input form, :use_wiki, as: :boolean
= config_input form, :use_nick, as: :boolean
= config_input form, :tolerance_is_costly, as: :boolean
= config_input form, :help_url, as: :url, input_html: {class: 'input-xlarge'}

View file

@ -0,0 +1,12 @@
= config_input form, :price_markup do
.input-append
= config_input_field form, :price_markup, as: :decimal, class: 'input-mini'
%span.add-on %
= config_input form, :tax_default do
.input-append
= config_input_field form, :tax_default, as: :decimal, class: 'input-mini'
%span.add-on %
= config_input form, :minimum_balance do
.input-prepend
%span.add-on= t 'number.currency.format.unit'
= config_input_field form, :minimum_balance, as: :decimal, class: 'input-small'

View file

@ -0,0 +1,3 @@
-#= config_use_heading form, :use_tasks do
= config_use_heading form, :use_apple_points do
= config_input form, :stop_ordering_under, as: :numeric, input_html: {class: 'input-small'}

View file

@ -0,0 +1,11 @@
%ul.nav.nav-tabs.nav-tabs-with-heading
%li.heading
%h1= t '.title'
- for tab in @tabs
- url = action_name == 'show' ? nil : admin_config_path(tab: tab)
%li{class: ('active' if @current_tab==tab)}= link_to t("config.tabs.#{tab}"), "#{url}#tab-#{tab}", data: ({toggle: 'tab'} unless url)
-# make this a button to give some indicator that navigation away might lose changes
%li.pull-right{class: ('active' if @current_tab=='list')}
= link_to t('config.tabs.list'), list_admin_config_path, class: ('btn' unless @current_tab=='list')

View file

@ -0,0 +1,16 @@
- title t('.title'), false
= render 'tabs'
%table.table
%thead
%tr
%th= t '.key'
%th= t '.value'
%tbody
- @keys.each do |key|
%tr
%td
%tt= key
%td{style: if @cfg[key] != @dfl[key] then 'font-weight: bold' end}
= show_config_value key, @cfg[key]

View file

@ -0,0 +1,13 @@
- title t('admin.configs.tabs.title'), false
= simple_form_for :config, method: :patch do |f|
= render 'tabs', url: nil
.tab-content
- for tab in @tabs
.tab-pane{class: ('active' if @current_tab==tab), id: "tab-#{tab}"}= render "tab_#{tab}", form: f
.form-actions
= f.submit t('.submit'), class: 'btn btn-primary'

View file

@ -10,9 +10,9 @@
%li= link_to t('.profile'), my_profile_path
%li= link_to t('.ordergroup'), my_ordergroup_path
%li= link_to t('.logout'), logout_path
%li{class: ('disabled' if FoodsoftConfig.config[:homepage].blank?)}
= link_to FoodsoftConfig.config[:name], FoodsoftConfig.config[:homepage]
%li= link_to t('.help'), FoodsoftConfig.config[:help_url]
%li{class: ('disabled' if FoodsoftConfig[:homepage].blank?)}
= link_to FoodsoftConfig[:name], FoodsoftConfig[:homepage]
%li= link_to t('.help'), FoodsoftConfig[:help_url]
%li= link_to t('.feedback.title'), new_feedback_path, title: t('.feedback.desc')
.clearfix