Skip to content

Commit

Permalink
Merge 588fa4c into d375572
Browse files Browse the repository at this point in the history
  • Loading branch information
wvengen committed Jun 27, 2014
2 parents d375572 + 588fa4c commit 9955844
Show file tree
Hide file tree
Showing 33 changed files with 879 additions and 39 deletions.
26 changes: 26 additions & 0 deletions app/assets/stylesheets/bootstrap_and_overrides.css.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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%;
Expand Down
39 changes: 39 additions & 0 deletions app/controllers/admin/configs_controller.rb
Original file line number Diff line number Diff line change
@@ -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
26 changes: 25 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :select_foodcoop, :authenticate, :store_controller, :items_per_page
after_filter :remove_controller
around_filter :set_time_zone, :set_currency


# Returns the controller handling the current request.
Expand Down Expand Up @@ -167,5 +168,28 @@ def items_per_page
def default_url_options(options = {})
{foodcoop: FoodsoftConfig.scope}
end


# Set timezone according to foodcoop preference.
# @see http://stackoverflow.com/questions/4362663/timezone-with-rails-3
# @see http://archives.ryandaigle.com/articles/2008/1/25/what-s-new-in-edge-rails-easier-timezones
def set_time_zone
old_time_zone = Time.zone
Time.zone = FoodsoftConfig[:time_zone] if FoodsoftConfig[:time_zone]
yield
ensure
Time.zone = old_time_zone
end

# Set currency according to foodcoop preference.
# @see #set_time_zone
def set_currency
old_currency = ::I18n.t('number.currency.format.unit')
new_currency = FoodsoftConfig[:currency_unit] || ''
new_currency += "\u202f" if FoodsoftConfig[:currency_space]
::I18n.backend.store_translations(::I18n.locale, number: {currency: {format: {unit: new_currency}}})
yield
ensure
::I18n.backend.store_translations(::I18n.locale, number: {currency: {format: {unit: old_currency}}})
end

end
129 changes: 129 additions & 0 deletions app/helpers/admin/configs_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
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.
# When the key is not {FoodsoftConfig#allowed_key? allowed}, +nil+ is returned.
# @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.
# @todo find way to pass current value to time_zone input without using default
def config_input(form, key, options = {}, &block)
return unless @cfg.allowed_key? key
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' if options[:checked_value].nil?
options[:unchecked_value] = 'false' if options[:unchecked_value].nil?
elsif options[:collection] or options[:as] == :select
options[:selected] = options[:input_html].delete(:value)
return form.input key, options, &block
elsif options[:as] == :time_zone
options[:default] = 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
# @option options [String] :checked_value Value for boolean when checked (default +true+)
# @option options [String] :unchecked_value Value for boolean when not checked (default +false+)
# @todo find out how to pass +checked_value+ and +unchecked_value+ to +input_field+
def config_input_field(form, key, options = {})
return unless @cfg.allowed_key? :key
options[:required] ||= false
config_input_field_options form, key, options
config_input_tooltip_options form, key, options
if options[:as] == :boolean
checked_value = options.delete(:checked_value) || 'true'
unchecked_value = options.delete(:unchecked_value) || 'false'
options[:checked] = 'checked' if options.delete(:value)
form.hidden_field(key, value: unchecked_value, as: :hidden) + form.check_box(key, options, checked_value, 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
10 changes: 10 additions & 0 deletions app/views/admin/configs/_tab_foodcoop.html.haml
Original file line number Diff line number Diff line change
@@ -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'}
9 changes: 9 additions & 0 deletions app/views/admin/configs/_tab_language.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
= 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
= config_input form, :time_zone, as: :time_zone, include_blank: true, input_html: {class: 'input-xlarge'}
= config_input form, :currency_unit do
= config_input_field form, :currency_unit, class: 'input-mini'
%label.inline
= config_input_label form, :currency_space
= config_input_field form, :currency_space, as: :boolean
7 changes: 7 additions & 0 deletions app/views/admin/configs/_tab_layout.html.haml
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions app/views/admin/configs/_tab_messages.html.haml
Original file line number Diff line number Diff line change
@@ -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'}
5 changes: 5 additions & 0 deletions app/views/admin/configs/_tab_others.html.haml
Original file line number Diff line number Diff line change
@@ -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'}
12 changes: 12 additions & 0 deletions app/views/admin/configs/_tab_payment.html.haml
Original file line number Diff line number Diff line change
@@ -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'
3 changes: 3 additions & 0 deletions app/views/admin/configs/_tab_tasks.html.haml
Original file line number Diff line number Diff line change
@@ -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'}
11 changes: 11 additions & 0 deletions app/views/admin/configs/_tabs.html.haml
Original file line number Diff line number Diff line change
@@ -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')
16 changes: 16 additions & 0 deletions app/views/admin/configs/list.html.haml
Original file line number Diff line number Diff line change
@@ -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]
13 changes: 13 additions & 0 deletions app/views/admin/configs/show.html.haml
Original file line number Diff line number Diff line change
@@ -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'

6 changes: 3 additions & 3 deletions app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions config/app_config.yml.SAMPLE
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ default: &defaults
# In case you really want foodsoft in a certain language by default, set this to true.
# When members are logged in, the language from their profile settings is still used.
#ignore_browser_locale: false
# Default timezone, e.g. UTC, Amsterdam, Berlin, etc.
#time_zone: Berlin
# Currency symbol, and whether to add a whitespace after the unit.
#currency_unit: €
#currency_space: true

# price markup in percent
price_markup: 2.0
Expand Down
3 changes: 3 additions & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true

# We clear the cache for each test, let's do that in memory.
config.cache_store = :memory_store

# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
Expand Down
7 changes: 7 additions & 0 deletions config/initializers/currency_display.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# remove all currency translations, so that we can set the default language and
# have it shown in all other languages too
::I18n.available_locales.each do |locale|
unless locale == ::I18n.default_locale
::I18n.backend.store_translations(locale, number: {currency: {format: {unit: nil}}})
end
end
Loading

0 comments on commit 9955844

Please sign in to comment.