Merge master
This commit is contained in:
commit
16bea87fd3
@ -49,6 +49,7 @@
|
||||
"notEqual",
|
||||
"require",
|
||||
"requirejs",
|
||||
"hasModule",
|
||||
"Blob",
|
||||
"File"],
|
||||
"node" : false,
|
||||
|
||||
31
Gemfile
31
Gemfile
@ -67,17 +67,19 @@ unless Bundler::Dependency::PLATFORM_MAP.include? :mri_21
|
||||
end
|
||||
end
|
||||
|
||||
gem 'seed-fu', '~> 2.3.3'
|
||||
|
||||
if rails_master?
|
||||
gem 'arel', git: 'https://github.com/rails/arel.git'
|
||||
gem 'rails', git: 'https://github.com/rails/rails.git'
|
||||
gem 'rails-observers', git: 'https://github.com/SamSaffron/rails-observers.git'
|
||||
gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse'
|
||||
else
|
||||
gem 'seed-fu', '~> 2.3.3'
|
||||
gem 'rails'
|
||||
gem 'rails-observers'
|
||||
end
|
||||
|
||||
gem 'actionpack-action_caching'
|
||||
gem 'rails-observers'
|
||||
|
||||
# Rails 4.1.6+ will relax the mail gem version requirement to `~> 2.5, >= 2.5.4`.
|
||||
# However, mail gem 2.6.x currently does not work with discourse because of the
|
||||
@ -102,9 +104,10 @@ end
|
||||
gem 'onebox'
|
||||
|
||||
gem 'ember-rails'
|
||||
gem 'ember-source', '1.6.0.beta.2'
|
||||
gem 'handlebars-source', '1.3.0'
|
||||
gem 'ember-source', '1.9.0.beta.4'
|
||||
gem 'handlebars-source', '2.0.0'
|
||||
gem 'barber'
|
||||
gem '6to5'
|
||||
|
||||
gem 'message_bus'
|
||||
gem 'rails_multisite', path: 'vendor/gems/rails_multisite'
|
||||
@ -114,15 +117,13 @@ gem 'eventmachine'
|
||||
gem 'fast_xs'
|
||||
|
||||
gem 'fast_xor'
|
||||
gem 'fastimage'
|
||||
gem 'fog', '1.22.1', require: false
|
||||
|
||||
# while we sort out https://github.com/sdsykes/fastimage/pull/46
|
||||
gem 'fastimage_discourse', require: 'fastimage'
|
||||
gem 'fog', '1.26.0', require: false
|
||||
gem 'unf', require: false
|
||||
|
||||
# see: https://twitter.com/samsaffron/status/412360162297393152
|
||||
# Massive amount of changes made in branch we use, no PR upstreamed
|
||||
# We need to get this sorted
|
||||
# https://github.com/samsaffron/email_reply_parser
|
||||
gem 'email_reply_parser-discourse', require: 'email_reply_parser'
|
||||
gem 'email_reply_parser'
|
||||
|
||||
# note: for image_optim to correctly work you need
|
||||
# sudo apt-get install -y advancecomp gifsicle jpegoptim libjpeg-progs optipng pngcrush
|
||||
@ -144,8 +145,7 @@ gem 'omniauth-github-discourse', require: 'omniauth-github'
|
||||
gem 'omniauth-oauth2', require: false
|
||||
gem 'omniauth-google-oauth2'
|
||||
gem 'oj'
|
||||
# while resolving https://groups.google.com/forum/#!topic/ruby-pg/5_ylGmog1S4
|
||||
gem 'pg', '0.15.1'
|
||||
gem 'pg'
|
||||
gem 'pry-rails', require: false
|
||||
gem 'rake'
|
||||
|
||||
@ -225,7 +225,7 @@ gem 'lru_redux'
|
||||
gem 'htmlentities', require: false
|
||||
|
||||
# IMPORTANT: mini profiler monkey patches, so it better be required last
|
||||
# If you want to amend mini profiler to do the monkey patches in the railstie
|
||||
# If you want to amend mini profiler to do the monkey patches in the railties
|
||||
# we are open to it. by deferring require to the initializer we can configure discourse installs without it
|
||||
|
||||
gem 'flamegraph', require: false
|
||||
@ -240,6 +240,9 @@ gem 'rbtrace', require: false, platform: :mri
|
||||
gem 'ruby-readability', require: false
|
||||
|
||||
gem 'simple-rss', require: false
|
||||
|
||||
# TODO mri_22 should be here, but bundler was real slow to pick it up
|
||||
# not even in production bundler yet, monkey patching it in feels bad
|
||||
gem 'gctools', require: false, platform: :mri_21
|
||||
gem 'stackprof', require: false, platform: :mri_21
|
||||
gem 'memory_profiler', require: false, platform: :mri_21
|
||||
|
||||
174
Gemfile.lock
174
Gemfile.lock
@ -6,6 +6,11 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
6to5 (0.5.0)
|
||||
6to5-source (>= 1.14, < 4)
|
||||
execjs (~> 2.0)
|
||||
6to5-source (3.3.7)
|
||||
CFPropertyList (2.2.8)
|
||||
actionmailer (4.1.8)
|
||||
actionpack (= 4.1.8)
|
||||
actionview (= 4.1.8)
|
||||
@ -36,27 +41,26 @@ GEM
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.3.6)
|
||||
annotate (2.6.5)
|
||||
activerecord (>= 2.3.0)
|
||||
rake (>= 0.8.7)
|
||||
arel (5.0.1.20140414130214)
|
||||
barber (0.4.2)
|
||||
barber (0.5.0)
|
||||
ember-source
|
||||
execjs
|
||||
handlebars-source
|
||||
better_errors (2.0.0)
|
||||
handlebars-source (>= 1.0.0.rc.4)
|
||||
better_errors (2.1.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
builder (3.2.2)
|
||||
celluloid (0.15.2)
|
||||
timers (~> 1.1.0)
|
||||
celluloid (0.16.0)
|
||||
timers (~> 4.0.0)
|
||||
certified (1.0.0)
|
||||
coderay (1.1.0)
|
||||
connection_pool (2.0.0)
|
||||
connection_pool (2.1.1)
|
||||
crass (0.2.1)
|
||||
daemons (1.1.9)
|
||||
debug_inspector (0.0.2)
|
||||
@ -65,7 +69,7 @@ GEM
|
||||
dotenv (0.11.1)
|
||||
dotenv-deployment (~> 0.0.2)
|
||||
dotenv-deployment (0.0.2)
|
||||
email_reply_parser-discourse (0.6)
|
||||
email_reply_parser (0.5.8)
|
||||
ember-data-source (0.14)
|
||||
ember-source
|
||||
ember-rails (0.14.1)
|
||||
@ -77,12 +81,12 @@ GEM
|
||||
handlebars-source
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
ember-source (1.6.0.beta.2)
|
||||
handlebars-source (~> 1.0)
|
||||
ember-source (1.9.0.beta.4)
|
||||
handlebars-source (~> 2.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
excon (0.39.6)
|
||||
execjs (2.2.1)
|
||||
eventmachine (1.0.7)
|
||||
excon (0.44.2)
|
||||
execjs (2.2.2)
|
||||
exifr (1.1.3)
|
||||
fabrication (2.9.8)
|
||||
fakeweb (1.3.0)
|
||||
@ -96,30 +100,77 @@ GEM
|
||||
rake
|
||||
rake-compiler
|
||||
fast_xs (0.8.0)
|
||||
fastimage (1.6.3)
|
||||
addressable (~> 2.3, >= 2.3.5)
|
||||
ffi (1.9.5)
|
||||
flamegraph (0.0.8)
|
||||
fastimage_discourse (1.6.6)
|
||||
ffi (1.9.6)
|
||||
fission (0.5.0)
|
||||
CFPropertyList (~> 2.2)
|
||||
flamegraph (0.1.0)
|
||||
fast_stack
|
||||
fog (1.22.1)
|
||||
fog-brightbox
|
||||
fog-core (~> 1.22)
|
||||
fog (1.26.0)
|
||||
fog-atmos
|
||||
fog-brightbox (~> 0.4)
|
||||
fog-core (~> 1.27, >= 1.27.1)
|
||||
fog-ecloud
|
||||
fog-json
|
||||
fog-profitbricks
|
||||
fog-radosgw (>= 0.0.2)
|
||||
fog-sakuracloud (>= 0.0.4)
|
||||
fog-softlayer
|
||||
fog-storm_on_demand
|
||||
fog-terremark
|
||||
fog-vmfusion
|
||||
fog-voxel
|
||||
fog-xml (~> 0.1.1)
|
||||
ipaddress (~> 0.5)
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
fog-brightbox (0.5.1)
|
||||
fog-atmos (0.1.0)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-brightbox (0.7.1)
|
||||
fog-core (~> 1.22)
|
||||
fog-json
|
||||
inflecto
|
||||
fog-core (1.24.0)
|
||||
inflecto (~> 0.0.2)
|
||||
fog-core (1.27.2)
|
||||
builder
|
||||
excon (~> 0.38)
|
||||
formatador (~> 0.2)
|
||||
mime-types
|
||||
net-scp (~> 1.1)
|
||||
net-ssh (>= 2.1.3)
|
||||
fog-ecloud (0.0.2)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-json (1.0.0)
|
||||
multi_json (~> 1.0)
|
||||
fog-profitbricks (0.0.1)
|
||||
fog-core
|
||||
fog-xml
|
||||
nokogiri
|
||||
fog-radosgw (0.0.3)
|
||||
fog-core (>= 1.21.0)
|
||||
fog-json
|
||||
fog-xml (>= 0.0.1)
|
||||
fog-sakuracloud (0.1.1)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (0.3.26)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-storm_on_demand (0.1.0)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-terremark (0.0.3)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-vmfusion (0.0.1)
|
||||
fission
|
||||
fog-core
|
||||
fog-voxel (0.0.2)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-xml (0.1.1)
|
||||
fog-core
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
foreman (0.75.0)
|
||||
dotenv (~> 0.11.1)
|
||||
thor (~> 0.19.1)
|
||||
@ -129,12 +180,13 @@ GEM
|
||||
given_core (3.5.4)
|
||||
sorcerer (>= 0.3.7)
|
||||
guess_html_encoding (0.0.9)
|
||||
handlebars-source (1.3.0)
|
||||
hashie (3.3.1)
|
||||
handlebars-source (2.0.0)
|
||||
hashie (3.3.2)
|
||||
highline (1.6.21)
|
||||
hike (1.2.3)
|
||||
hiredis (0.5.2)
|
||||
htmlentities (4.3.2)
|
||||
hiredis (0.6.0)
|
||||
hitimes (1.2.2)
|
||||
htmlentities (4.3.3)
|
||||
i18n (0.6.11)
|
||||
image_optim (0.9.1)
|
||||
exifr (~> 1.1.3)
|
||||
@ -149,7 +201,7 @@ GEM
|
||||
jquery-rails (3.1.2)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.1)
|
||||
json (1.8.2)
|
||||
jwt (1.0.0)
|
||||
kgio (2.9.2)
|
||||
librarian (0.1.2)
|
||||
@ -163,20 +215,20 @@ GEM
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
memory_profiler (0.0.4)
|
||||
message_bus (1.0.5)
|
||||
message_bus (1.0.6)
|
||||
eventmachine
|
||||
rack (>= 1.1.3)
|
||||
redis
|
||||
metaclass (0.0.4)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.1)
|
||||
minitest (5.4.2)
|
||||
mini_portile (0.6.2)
|
||||
minitest (5.5.1)
|
||||
mocha (1.1.0)
|
||||
metaclass (~> 0.0.1)
|
||||
mock_redis (0.13.2)
|
||||
mock_redis (0.14.0)
|
||||
moneta (0.8.0)
|
||||
msgpack (0.5.8)
|
||||
msgpack (0.5.11)
|
||||
multi_json (1.10.1)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (2.0.0)
|
||||
@ -185,7 +237,7 @@ GEM
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.9.1)
|
||||
netrc (0.7.7)
|
||||
nokogiri (1.6.4.1)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
nokogumbo (1.1.12)
|
||||
nokogiri
|
||||
@ -196,7 +248,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (~> 1.2)
|
||||
oj (2.10.2)
|
||||
oj (2.11.4)
|
||||
omniauth (1.2.2)
|
||||
hashie (>= 1.2, < 4)
|
||||
rack (~> 1.0)
|
||||
@ -222,7 +274,7 @@ GEM
|
||||
omniauth-twitter (1.0.1)
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
onebox (1.5.7)
|
||||
onebox (1.5.12)
|
||||
moneta (~> 0.7)
|
||||
multi_json (~> 1.7)
|
||||
mustache (~> 0.99)
|
||||
@ -230,7 +282,7 @@ GEM
|
||||
openid-redis-store (0.0.2)
|
||||
redis
|
||||
ruby-openid
|
||||
pg (0.15.1)
|
||||
pg (0.18.1)
|
||||
polyglot (0.3.5)
|
||||
progress (3.0.1)
|
||||
pry (0.10.1)
|
||||
@ -239,9 +291,9 @@ GEM
|
||||
slop (~> 3.4)
|
||||
pry-nav (0.2.4)
|
||||
pry (>= 0.9.10, < 0.11.0)
|
||||
pry-rails (0.3.2)
|
||||
pry-rails (0.3.3)
|
||||
pry (>= 0.9.10)
|
||||
puma (2.9.1)
|
||||
puma (2.11.1)
|
||||
rack (>= 1.1, < 2.0)
|
||||
qunit-rails (0.0.7)
|
||||
railties
|
||||
@ -273,18 +325,18 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
raindrops (0.13.0)
|
||||
rake (10.3.2)
|
||||
rake-compiler (0.9.3)
|
||||
rake (10.4.2)
|
||||
rake-compiler (0.9.4)
|
||||
rake
|
||||
rb-fsevent (0.9.4)
|
||||
rb-inotify (0.9.5)
|
||||
ffi (>= 0.5.0)
|
||||
rbtrace (0.4.5)
|
||||
rbtrace (0.4.7)
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
trollop (>= 1.16.2)
|
||||
redcarpet (3.1.2)
|
||||
redis (3.1.0)
|
||||
redcarpet (3.2.2)
|
||||
redis (3.2.1)
|
||||
redis-namespace (1.5.1)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
ref (1.0.5)
|
||||
@ -339,9 +391,9 @@ GEM
|
||||
shoulda-context (1.2.1)
|
||||
shoulda-matchers (2.7.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (3.2.5)
|
||||
celluloid (= 0.15.2)
|
||||
connection_pool (>= 2.0.0)
|
||||
sidekiq (3.3.1)
|
||||
celluloid (>= 0.16.0)
|
||||
connection_pool (>= 2.1.1)
|
||||
json
|
||||
redis (>= 3.0.6)
|
||||
redis-namespace (>= 1.3.1)
|
||||
@ -375,22 +427,23 @@ GEM
|
||||
therubyracer (0.12.1)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thin (1.6.2)
|
||||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 1.0.0)
|
||||
rack (>= 1.0.0)
|
||||
thin (1.6.3)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.4)
|
||||
tilt (1.4.1)
|
||||
timecop (0.7.1)
|
||||
timers (1.1.0)
|
||||
timers (4.0.1)
|
||||
hitimes
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
trollop (2.0)
|
||||
trollop (2.1.1)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (2.5.3)
|
||||
uglifier (2.6.0)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
unf (0.1.4)
|
||||
@ -405,6 +458,7 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
6to5
|
||||
actionpack-action_caching
|
||||
active_model_serializers (~> 0.8.0)
|
||||
annotate
|
||||
@ -412,21 +466,21 @@ DEPENDENCIES
|
||||
better_errors
|
||||
binding_of_caller
|
||||
certified
|
||||
email_reply_parser-discourse
|
||||
email_reply_parser
|
||||
ember-rails
|
||||
ember-source (= 1.6.0.beta.2)
|
||||
ember-source (= 1.9.0.beta.4)
|
||||
eventmachine
|
||||
fabrication (= 2.9.8)
|
||||
fakeweb (~> 1.3.0)
|
||||
fast_blank
|
||||
fast_xor
|
||||
fast_xs
|
||||
fastimage
|
||||
fastimage_discourse
|
||||
flamegraph
|
||||
fog (= 1.22.1)
|
||||
fog (= 1.26.0)
|
||||
foreman
|
||||
gctools
|
||||
handlebars-source (= 1.3.0)
|
||||
handlebars-source (= 2.0.0)
|
||||
highline
|
||||
hiredis
|
||||
htmlentities
|
||||
@ -454,7 +508,7 @@ DEPENDENCIES
|
||||
omniauth-twitter
|
||||
onebox
|
||||
openid-redis-store
|
||||
pg (= 0.15.1)
|
||||
pg
|
||||
pry-nav
|
||||
pry-rails
|
||||
puma
|
||||
|
||||
@ -7,66 +7,26 @@ GIT
|
||||
activemodel (>= 3.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/rails/arel.git
|
||||
revision: 590c784a30b13153667f8db7915998d7731e24e5
|
||||
remote: https://github.com/SamSaffron/rails-observers.git
|
||||
revision: 7d2222d758603a004f6599f82a7068ffeb2d7ebf
|
||||
specs:
|
||||
arel (6.0.0.beta2)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (> 4.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/rails/rails.git
|
||||
revision: eb26f24bde62cbbcd8ef0e7ee9c64060b098baff
|
||||
remote: https://github.com/SamSaffron/seed-fu.git
|
||||
revision: d93df3b6364ea938d87c5629bf950b0d1ffe037e
|
||||
branch: discourse
|
||||
specs:
|
||||
actionmailer (4.2.0.beta4)
|
||||
actionpack (= 4.2.0.beta4)
|
||||
actionview (= 4.2.0.beta4)
|
||||
activejob (= 4.2.0.beta4)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.4)
|
||||
actionpack (4.2.0.beta4)
|
||||
actionview (= 4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
rack (~> 1.6.0.beta)
|
||||
rack-test (~> 0.6.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.4)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.1)
|
||||
actionview (4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.4)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.1)
|
||||
activejob (4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.2.0.beta4)
|
||||
activemodel (= 4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
arel (>= 6.0.0.beta2, < 6.1)
|
||||
activesupport (4.2.0.beta4)
|
||||
i18n (>= 0.7.0.beta1, < 0.8)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
rails (4.2.0.beta4)
|
||||
actionmailer (= 4.2.0.beta4)
|
||||
actionpack (= 4.2.0.beta4)
|
||||
actionview (= 4.2.0.beta4)
|
||||
activejob (= 4.2.0.beta4)
|
||||
activemodel (= 4.2.0.beta4)
|
||||
activerecord (= 4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.2.0.beta4)
|
||||
sprockets-rails (~> 3.0.0.beta1)
|
||||
railties (4.2.0.beta4)
|
||||
actionpack (= 4.2.0.beta4)
|
||||
activesupport (= 4.2.0.beta4)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
seed-fu (2.3.3)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/rails/arel.git
|
||||
revision: 98fc25991137ee09b6800578117f8c1c322680f2
|
||||
specs:
|
||||
arel (6.0.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/rails/sass-rails.git
|
||||
@ -78,6 +38,61 @@ GIT
|
||||
sprockets (~> 2.12)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
|
||||
PATH
|
||||
remote: ../rails
|
||||
specs:
|
||||
actionmailer (5.0.0.alpha)
|
||||
actionpack (= 5.0.0.alpha)
|
||||
actionview (= 5.0.0.alpha)
|
||||
activejob (= 5.0.0.alpha)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
actionpack (5.0.0.alpha)
|
||||
actionview (= 5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
rack (~> 1.6.0.beta2)
|
||||
rack-test (~> 0.6.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.1)
|
||||
actionview (5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.1)
|
||||
activejob (5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
builder (~> 3.1)
|
||||
activerecord (5.0.0.alpha)
|
||||
activemodel (= 5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
arel (~> 6.0)
|
||||
activesupport (5.0.0.alpha)
|
||||
i18n (>= 0.7.0.beta1, < 0.8)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
rails (5.0.0.alpha)
|
||||
actionmailer (= 5.0.0.alpha)
|
||||
actionpack (= 5.0.0.alpha)
|
||||
actionview (= 5.0.0.alpha)
|
||||
activejob (= 5.0.0.alpha)
|
||||
activemodel (= 5.0.0.alpha)
|
||||
activerecord (= 5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 5.0.0.alpha)
|
||||
sprockets-rails
|
||||
railties (5.0.0.alpha)
|
||||
actionpack (= 5.0.0.alpha)
|
||||
activesupport (= 5.0.0.alpha)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
|
||||
PATH
|
||||
remote: vendor/gems/rails_multisite
|
||||
specs:
|
||||
@ -150,7 +165,7 @@ GEM
|
||||
fastimage (1.6.3)
|
||||
addressable (~> 2.3, >= 2.3.5)
|
||||
ffi (1.9.5)
|
||||
flamegraph (0.0.8)
|
||||
flamegraph (0.0.9)
|
||||
fast_stack
|
||||
fog (1.22.1)
|
||||
fog-brightbox
|
||||
@ -285,7 +300,7 @@ GEM
|
||||
openid-redis-store (0.0.2)
|
||||
redis
|
||||
ruby-openid
|
||||
pg (0.15.1)
|
||||
pg (0.18.0.pre20141117110243)
|
||||
polyglot (0.3.5)
|
||||
progress (3.0.1)
|
||||
pry (0.10.1)
|
||||
@ -300,7 +315,7 @@ GEM
|
||||
rack (>= 1.1, < 2.0)
|
||||
qunit-rails (0.0.7)
|
||||
railties
|
||||
rack (1.6.0.beta)
|
||||
rack (1.6.0.beta2)
|
||||
rack-mini-profiler (0.9.2)
|
||||
rack (>= 1.1.3)
|
||||
rack-openid (1.3.1)
|
||||
@ -312,16 +327,14 @@ GEM
|
||||
rack (>= 1.0)
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.4)
|
||||
rails-dom-testing (1.0.5)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.1)
|
||||
loofah (~> 2.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
raindrops (0.13.0)
|
||||
rake (10.3.2)
|
||||
rake (10.4.0)
|
||||
rake-compiler (0.9.3)
|
||||
rake
|
||||
rb-fsevent (0.9.4)
|
||||
@ -373,9 +386,6 @@ GEM
|
||||
nokogiri (>= 1.4.4)
|
||||
nokogumbo (= 1.1.12)
|
||||
sass (3.2.19)
|
||||
seed-fu (2.3.3)
|
||||
activerecord (>= 3.1, < 4.2)
|
||||
activesupport (>= 3.1, < 4.2)
|
||||
shoulda (3.5.0)
|
||||
shoulda-context (~> 1.0, >= 1.0.1)
|
||||
shoulda-matchers (>= 1.4.1, < 3.0)
|
||||
@ -498,7 +508,7 @@ DEPENDENCIES
|
||||
omniauth-twitter
|
||||
onebox
|
||||
openid-redis-store
|
||||
pg (= 0.15.1)
|
||||
pg (= 0.18.0.pre20141117110243)
|
||||
pry-nav
|
||||
pry-rails
|
||||
puma
|
||||
@ -506,7 +516,7 @@ DEPENDENCIES
|
||||
rack-mini-profiler
|
||||
rack-protection
|
||||
rails!
|
||||
rails-observers
|
||||
rails-observers!
|
||||
rails_multisite!
|
||||
rake
|
||||
rb-fsevent
|
||||
@ -525,7 +535,7 @@ DEPENDENCIES
|
||||
sanitize
|
||||
sass
|
||||
sass-rails!
|
||||
seed-fu (~> 2.3.3)
|
||||
seed-fu!
|
||||
shoulda
|
||||
sidekiq
|
||||
simple-rss
|
||||
|
||||
17
README.md
17
README.md
@ -10,13 +10,14 @@ To learn more about the philosophy and goals of the project, [visit **discourse.
|
||||
|
||||
## Screenshots
|
||||
|
||||
[](http://bbs.boingboing.net)
|
||||
[](http://discuss.howtogeek.com)
|
||||
[](http://discuss.newrelic.com)
|
||||
[](https://talk.turtlerockstudios.com/)
|
||||
[](http://discuss.atom.io)
|
||||
[](http://discourse.soylent.me)
|
||||
[](http://bbs.boingboing.net)
|
||||
[](http://discuss.howtogeek.com)
|
||||
[](http://discuss.newrelic.com)
|
||||
[](https://talk.turtlerockstudios.com/)
|
||||
[](http://discuss.atom.io)
|
||||
[](http://discourse.soylent.me)
|
||||
|
||||
Browse [lots more notable Discourse instances](http://www.discourse.org/faq/customers/).
|
||||
|
||||
## Development
|
||||
|
||||
@ -56,8 +57,8 @@ Plus *lots* of Ruby Gems, a complete list of which is at [/master/Gemfile](https
|
||||
|
||||
## Contributing
|
||||
|
||||
[](https://travis-ci.org/discourse/discourse)
|
||||
[](https://codeclimate.com/github/discourse/discourse)
|
||||
[](https://travis-ci.org/discourse/discourse)
|
||||
[](https://codeclimate.com/github/discourse/discourse)
|
||||
|
||||
Discourse is **100% free** and **open-source**. We encourage and support an active, healthy community that
|
||||
accepts contributions from the public – including you!
|
||||
|
||||
4
Vagrantfile
vendored
4
Vagrantfile
vendored
@ -3,8 +3,8 @@
|
||||
# See https://github.com/discourse/discourse/blob/master/docs/VAGRANT.md
|
||||
#
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = 'discourse-0.9.9.13'
|
||||
config.vm.box_url = "https://d3fvb7b7auiut8.cloudfront.net/discourse-0.9.9.13.box"
|
||||
config.vm.box= "discourse/discourse-0.9.9.15.box"
|
||||
config.vm.box_url = "https://vagrantcloud.com/discourse/discourse-0.9.9.15.box"
|
||||
|
||||
# Make this VM reachable on the host network as well, so that other
|
||||
# VM's running other browsers can access our dev server.
|
||||
|
||||
@ -1,12 +1,5 @@
|
||||
<%
|
||||
if Rails.env.development?
|
||||
require_asset ("development/list-view.js")
|
||||
else
|
||||
require_asset ("production/list-view.js")
|
||||
end
|
||||
|
||||
require_asset("main_include_admin.js")
|
||||
|
||||
DiscoursePluginRegistry.admin_javascripts.each { |js| require_asset(js) }
|
||||
|
||||
%>
|
||||
|
||||
@ -31,4 +31,4 @@ export default Ember.Component.extend({
|
||||
_refreshOnReset: function() {
|
||||
this.$("input").select2("data", this.get("selected").map(this._format));
|
||||
}.observes("selected")
|
||||
});
|
||||
});
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['active'],
|
||||
|
||||
router: function() {
|
||||
return this.container.lookup('router:main');
|
||||
}.property(),
|
||||
|
||||
active: function() {
|
||||
const route = this.get('route');
|
||||
if (!route) { return; }
|
||||
|
||||
const routeParam = this.get('routeParam'),
|
||||
router = this.get('router');
|
||||
|
||||
return routeParam ? router.isActive(route, routeParam) : router.isActive(route);
|
||||
}.property('router.url', 'route')
|
||||
});
|
||||
24
app/assets/javascripts/admin/components/color-input.js.es6
Normal file
24
app/assets/javascripts/admin/components/color-input.js.es6
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
An input field for a color.
|
||||
|
||||
@param hexValue is a reference to the color's hex value.
|
||||
@param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor.
|
||||
@params valid is a boolean indicating if the input field is a valid color.
|
||||
**/
|
||||
export default Ember.Component.extend({
|
||||
hexValueChanged: function() {
|
||||
var hex = this.get('hexValue');
|
||||
if (this.get('valid')) {
|
||||
this.$('input').attr('style', 'color: ' + (this.get('brightnessValue') > 125 ? 'black' : 'white') + '; background-color: #' + hex + ';');
|
||||
} else {
|
||||
this.$('input').attr('style', '');
|
||||
}
|
||||
}.observes('hexValue', 'brightnessValue', 'valid'),
|
||||
|
||||
_triggerHexChanged: function() {
|
||||
var self = this;
|
||||
Em.run.schedule('afterRender', function() {
|
||||
self.hexValueChanged();
|
||||
});
|
||||
}.on('didInsertElement')
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
/**
|
||||
An input field for a color.
|
||||
|
||||
@param hexValue is a reference to the color's hex value.
|
||||
@param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor.
|
||||
@params valid is a boolean indicating if the input field is a valid color.
|
||||
|
||||
@class Discourse.ColorInputComponent
|
||||
@extends Ember.Component
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ColorInputComponent = Ember.Component.extend({
|
||||
layoutName: 'components/color-input',
|
||||
|
||||
hexValueChanged: function() {
|
||||
var hex = this.get('hexValue');
|
||||
if (this.get('valid')) {
|
||||
this.$('input').attr('style', 'color: ' + (this.get('brightnessValue') > 125 ? 'black' : 'white') + '; background-color: #' + hex + ';');
|
||||
} else {
|
||||
this.$('input').attr('style', '');
|
||||
}
|
||||
}.observes('hexValue', 'brightnessValue', 'valid'),
|
||||
|
||||
didInsertElement: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
Em.run.schedule('afterRender', function() {
|
||||
self.hexValueChanged();
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -9,6 +9,13 @@ export default Ember.Component.extend({
|
||||
].filter(Boolean).join(", ");
|
||||
}.property("location.{city,region,country}"),
|
||||
|
||||
otherAccountsToDelete: function() {
|
||||
// can only delete up to 50 accounts at a time
|
||||
var total = Math.min(50, this.get("totalOthersWithSameIP") || 0);
|
||||
var visible = Math.min(50, this.get("other_accounts.length") || 0);
|
||||
return Math.max(visible, total);
|
||||
}.property("other_accounts", "totalOthersWithSameIP"),
|
||||
|
||||
actions: {
|
||||
lookup: function () {
|
||||
var self = this;
|
||||
@ -24,10 +31,18 @@ export default Ember.Component.extend({
|
||||
|
||||
if (!this.get("other_accounts")) {
|
||||
this.set("otherAccountsLoading", true);
|
||||
Discourse.AdminUser.findAll("active", {
|
||||
|
||||
var data = {
|
||||
"ip": this.get("ip"),
|
||||
"exclude": this.get("user_id")
|
||||
}).then(function (users) {
|
||||
"exclude": this.get("userId"),
|
||||
"order": "trust_level DESC"
|
||||
};
|
||||
|
||||
Discourse.ajax("/admin/users/total-others-with-same-ip.json", { data: data }).then(function (result) {
|
||||
self.set("totalOthersWithSameIP", result.total);
|
||||
});
|
||||
|
||||
Discourse.AdminUser.findAll("active", data).then(function (users) {
|
||||
self.setProperties({
|
||||
other_accounts: users,
|
||||
otherAccountsLoading: false,
|
||||
@ -38,6 +53,30 @@ export default Ember.Component.extend({
|
||||
|
||||
hide: function () {
|
||||
this.set("show", false);
|
||||
},
|
||||
|
||||
deleteOtherAccounts: function() {
|
||||
var self = this;
|
||||
bootbox.confirm(I18n.t("ip_lookup.confirm_delete_other_accounts"), I18n.t("no_value"), I18n.t("yes_value"), function (confirmed) {
|
||||
if (confirmed) {
|
||||
self.setProperties({
|
||||
other_accounts: null,
|
||||
otherAccountsLoading: true,
|
||||
totalOthersWithSameIP: null
|
||||
});
|
||||
|
||||
Discourse.ajax("/admin/users/delete-others-with-same-ip.json", {
|
||||
type: "DELETE",
|
||||
data: {
|
||||
"ip": self.get("ip"),
|
||||
"exclude": self.get("userId"),
|
||||
"order": "trust_level DESC"
|
||||
}
|
||||
}).then(function() {
|
||||
self.send("lookup");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
53
app/assets/javascripts/admin/components/list-setting.js.es6
Normal file
53
app/assets/javascripts/admin/components/list-setting.js.es6
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
Provide a nice GUI for a pipe-delimited list in the site settings.
|
||||
|
||||
@param settingValue is a reference to SiteSetting.value.
|
||||
@param choices is a reference to SiteSetting.choices
|
||||
**/
|
||||
export default Ember.Component.extend({
|
||||
|
||||
_select2FormatSelection: function(selectedObject, jqueryWrapper, htmlEscaper) {
|
||||
var text = selectedObject.text;
|
||||
if (text.length <= 6) {
|
||||
jqueryWrapper.closest('li.select2-search-choice').css({"border-bottom": '7px solid #'+text});
|
||||
}
|
||||
return htmlEscaper(text);
|
||||
},
|
||||
|
||||
_initializeSelect2: function(){
|
||||
var options = {
|
||||
multiple: false,
|
||||
separator: "|",
|
||||
tokenSeparators: ["|"],
|
||||
tags : this.get("choices") || [],
|
||||
width: 'off',
|
||||
dropdownCss: this.get("choices") ? {} : {display: 'none'}
|
||||
};
|
||||
|
||||
var settingName = this.get('settingName');
|
||||
if (typeof settingName === 'string' && settingName.indexOf('colors') > -1) {
|
||||
options.formatSelection = this._select2FormatSelection;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.$("input").select2(options).on("change", function(obj) {
|
||||
self.set("settingValue", obj.val.join("|"));
|
||||
self.refreshSortables();
|
||||
});
|
||||
|
||||
this.refreshSortables();
|
||||
}.on('didInsertElement'),
|
||||
|
||||
refreshOnReset: function() {
|
||||
this.$("input").select2("val", this.get("settingValue").split("|"));
|
||||
}.observes("settingValue"),
|
||||
|
||||
refreshSortables: function() {
|
||||
var self = this;
|
||||
this.$("ul.select2-choices").sortable().on('sortupdate', function() {
|
||||
self.$("input").select2("onSortEnd");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
/**
|
||||
Provide a nice GUI for a pipe-delimited list in the site settings.
|
||||
|
||||
@param settingValue is a reference to SiteSetting.value.
|
||||
@param choices is a reference to SiteSetting.choices
|
||||
|
||||
@class Discourse.ListSettingComponent
|
||||
@extends Ember.Component
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
Discourse.ListSettingComponent = Ember.Component.extend({
|
||||
tagName: 'div',
|
||||
|
||||
|
||||
_select2FormatSelection: function(selectedObject, jqueryWrapper, htmlEscaper) {
|
||||
var text = selectedObject.text;
|
||||
if (text.length <= 6) {
|
||||
jqueryWrapper.closest('li.select2-search-choice').css({"border-bottom": '7px solid #'+text});
|
||||
}
|
||||
return htmlEscaper(text);
|
||||
},
|
||||
|
||||
didInsertElement: function(){
|
||||
|
||||
var select2_options = {
|
||||
multiple: false,
|
||||
separator: "|",
|
||||
tokenSeparators: ["|"],
|
||||
tags : this.get("choices") || [],
|
||||
width: 'off',
|
||||
dropdownCss: this.get("choices") ? {} : {display: 'none'}
|
||||
};
|
||||
|
||||
var settingName = this.get('settingName');
|
||||
if (typeof settingName === 'string' && settingName.indexOf('colors') > -1) {
|
||||
select2_options.formatSelection = this._select2FormatSelection;
|
||||
}
|
||||
this.$("input").select2(select2_options).on("change", function(obj) {
|
||||
this.set("settingValue", obj.val.join("|"));
|
||||
this.refreshSortables();
|
||||
}.bind(this));
|
||||
|
||||
this.refreshSortables();
|
||||
},
|
||||
|
||||
refreshOnReset: function() {
|
||||
this.$("input").select2("val", this.get("settingValue").split("|"));
|
||||
}.observes("settingValue"),
|
||||
|
||||
refreshSortables: function() {
|
||||
this.$("ul.select2-choices").sortable().on('sortupdate', function() {
|
||||
this.$("input").select2("onSortEnd");
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -9,13 +9,8 @@
|
||||
error="errorAction"
|
||||
uploadText="UPLOAD"
|
||||
}}
|
||||
|
||||
@class ResumableUploadComponent
|
||||
@extends Ember.Component
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ResumableUploadComponent = Ember.Component.extend({
|
||||
Discourse.ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer, {
|
||||
tagName: "button",
|
||||
classNames: ["btn", "ru"],
|
||||
classNameBindings: ["isUploading"],
|
||||
@ -25,7 +20,7 @@ Discourse.ResumableUploadComponent = Ember.Component.extend({
|
||||
isUploading: false,
|
||||
progress: 0,
|
||||
|
||||
shouldRerender: Discourse.View.renderIfChanged("isUploading", "progress"),
|
||||
rerenderTriggers: ['isUploading', 'progress'],
|
||||
|
||||
text: function() {
|
||||
if (this.get("isUploading")) {
|
||||
@ -35,7 +30,7 @@ Discourse.ResumableUploadComponent = Ember.Component.extend({
|
||||
}
|
||||
}.property("isUploading", "progress"),
|
||||
|
||||
render: function(buffer) {
|
||||
renderString: function(buffer) {
|
||||
var icon = this.get("isUploading") ? "times" : "upload";
|
||||
buffer.push("<i class='fa fa-" + icon + "'></i>");
|
||||
buffer.push("<span class='ru-label'>" + this.get("text") + "</span>");
|
||||
|
||||
@ -53,6 +53,9 @@ export default Ember.Controller.extend({
|
||||
actions: {
|
||||
refreshProblems: function() {
|
||||
this.loadProblems();
|
||||
},
|
||||
showTrafficReport: function() {
|
||||
this.set("showTrafficReport", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -36,8 +36,12 @@ export default DiscourseController.extend({
|
||||
data: { email_address: this.get('testEmailAddress') }
|
||||
}).then(function () {
|
||||
self.set('sentTestEmail', true);
|
||||
}).catch(function () {
|
||||
bootbox.alert(I18n.t('admin.email.test_error'));
|
||||
}, function(e) {
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
bootbox.alert(I18n.t('admin.email.error', { server_error: e.responseJSON.errors[0] }));
|
||||
} else {
|
||||
bootbox.alert(I18n.t('admin.email.test_error'));
|
||||
}
|
||||
}).finally(function() {
|
||||
self.set('sendingEmail', false);
|
||||
});
|
||||
|
||||
20
app/assets/javascripts/admin/controllers/admin-emojis.js.es6
Normal file
20
app/assets/javascripts/admin/controllers/admin-emojis.js.es6
Normal file
@ -0,0 +1,20 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
sortProperties: ["name"],
|
||||
|
||||
actions: {
|
||||
emojiUploaded: function (emoji) {
|
||||
this.pushObject(emoji);
|
||||
},
|
||||
|
||||
destroy: function(emoji) {
|
||||
var self = this;
|
||||
return bootbox.confirm(I18n.t("admin.emoji.delete_confirm", { name: emoji.name }), I18n.t("no_value"), I18n.t("yes_value"), function (destroy) {
|
||||
if (destroy) {
|
||||
return Discourse.ajax("/admin/customize/emojis/" + emoji.name, { type: "DELETE" }).then(function() {
|
||||
self.removeObject(emoji);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -5,7 +5,7 @@ export default Ember.ArrayController.extend({
|
||||
adminActiveFlagsView: Em.computed.equal("query", "active"),
|
||||
|
||||
actions: {
|
||||
disagreeFlags: function (flaggedPost) {
|
||||
disagreeFlags(flaggedPost) {
|
||||
var self = this;
|
||||
flaggedPost.disagreeFlags().then(function () {
|
||||
self.removeObject(flaggedPost);
|
||||
@ -14,7 +14,7 @@ export default Ember.ArrayController.extend({
|
||||
});
|
||||
},
|
||||
|
||||
deferFlags: function (flaggedPost) {
|
||||
deferFlags(flaggedPost) {
|
||||
var self = this;
|
||||
flaggedPost.deferFlags().then(function () {
|
||||
self.removeObject(flaggedPost);
|
||||
@ -23,12 +23,12 @@ export default Ember.ArrayController.extend({
|
||||
});
|
||||
},
|
||||
|
||||
doneTopicFlags: function(item) {
|
||||
doneTopicFlags(item) {
|
||||
this.send("disagreeFlags", item);
|
||||
},
|
||||
},
|
||||
|
||||
loadMore: function(){
|
||||
loadMore(){
|
||||
var flags = this.get("model");
|
||||
return Discourse.FlaggedPost.findAll(this.get("query"),flags.length+1).then(function(data){
|
||||
if(data.length===0){
|
||||
|
||||
@ -1,51 +1,86 @@
|
||||
export default Em.ObjectController.extend({
|
||||
needs: ['adminGroups'],
|
||||
members: null,
|
||||
needs: ['adminGroupsType'],
|
||||
disableSave: false,
|
||||
|
||||
currentPage: function() {
|
||||
if (this.get("user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("offset") / this.get("limit")) + 1;
|
||||
}.property("limit", "offset", "user_count"),
|
||||
|
||||
totalPages: function() {
|
||||
if (this.get("user_count") === 0) { return 0; }
|
||||
return Math.floor(this.get("user_count") / this.get("limit")) + 1;
|
||||
}.property("limit", "user_count"),
|
||||
|
||||
showingFirst: Em.computed.lte("currentPage", 1),
|
||||
showingLast: Discourse.computed.propertyEqual("currentPage", "totalPages"),
|
||||
|
||||
aliasLevelOptions: function() {
|
||||
return [
|
||||
{ name: I18n.t("groups.alias_levels.nobody"), value: 0},
|
||||
{ name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2},
|
||||
{ name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3},
|
||||
{ name: I18n.t("groups.alias_levels.everyone"), value: 99}
|
||||
{ name: I18n.t("groups.alias_levels.nobody"), value: 0 },
|
||||
{ name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 },
|
||||
{ name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 },
|
||||
{ name: I18n.t("groups.alias_levels.everyone"), value: 99 }
|
||||
];
|
||||
}.property(),
|
||||
|
||||
usernames: function(key, value) {
|
||||
var members = this.get('members');
|
||||
if (arguments.length > 1) {
|
||||
this.set('_usernames', value);
|
||||
} else {
|
||||
var usernames;
|
||||
if(members) {
|
||||
usernames = members.map(function(user) {
|
||||
return user.get('username');
|
||||
}).join(',');
|
||||
}
|
||||
this.set('_usernames', usernames);
|
||||
}
|
||||
return this.get('_usernames');
|
||||
}.property('members.@each.username'),
|
||||
|
||||
actions: {
|
||||
next: function() {
|
||||
if (this.get("showingLast")) { return; }
|
||||
|
||||
var group = this.get("model"),
|
||||
offset = Math.min(group.get("offset") + group.get("limit"), group.get("user_count"));
|
||||
|
||||
group.set("offset", offset);
|
||||
|
||||
return group.findMembers();
|
||||
},
|
||||
|
||||
previous: function() {
|
||||
if (this.get("showingFirst")) { return; }
|
||||
|
||||
var group = this.get("model"),
|
||||
offset = Math.max(group.get("offset") - group.get("limit"), 0);
|
||||
|
||||
group.set("offset", offset);
|
||||
|
||||
return group.findMembers();
|
||||
},
|
||||
|
||||
removeMember: function(member) {
|
||||
var self = this,
|
||||
message = I18n.t("admin.groups.delete_member_confirm", { username: member.get("username"), group: this.get("name") });
|
||||
return bootbox.confirm(message, I18n.t("no_value"), I18n.t("yes_value"), function(confirm) {
|
||||
if (confirm) {
|
||||
self.get("model").removeMember(member);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addMembers: function() {
|
||||
if (Em.isEmpty(this.get("usernames"))) { return; }
|
||||
this.get("model").addMembers(this.get("usernames"));
|
||||
// clear the user selector
|
||||
this.set("usernames", null);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
var self = this,
|
||||
group = this.get('model');
|
||||
group = this.get('model'),
|
||||
groupsController = this.get("controllers.adminGroupsType");
|
||||
|
||||
self.set('disableSave', true);
|
||||
this.set('disableSave', true);
|
||||
|
||||
var promise;
|
||||
if (group.get('id')) {
|
||||
promise = group.saveWithUsernames(this.get('usernames'));
|
||||
if (group.get("id")) {
|
||||
promise = group.save();
|
||||
} else {
|
||||
promise = group.createWithUsernames(this.get('usernames')).then(function() {
|
||||
var groupsController = self.get('controllers.adminGroups');
|
||||
promise = group.create().then(function() {
|
||||
groupsController.addObject(group);
|
||||
});
|
||||
}
|
||||
promise.then(function() {
|
||||
self.send('showGroup', group);
|
||||
self.transitionToRoute("adminGroup", group);
|
||||
}, function(e) {
|
||||
var message = $.parseJSON(e.responseText).errors;
|
||||
bootbox.alert(message);
|
||||
@ -56,12 +91,13 @@ export default Em.ObjectController.extend({
|
||||
|
||||
destroy: function() {
|
||||
var group = this.get('model'),
|
||||
groupsController = this.get('controllers.adminGroups'),
|
||||
groupsController = this.get('controllers.adminGroupsType'),
|
||||
self = this;
|
||||
|
||||
bootbox.confirm(I18n.t("admin.groups.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
|
||||
if (result) {
|
||||
self.set('disableSave', true);
|
||||
this.set('disableSave', true);
|
||||
|
||||
bootbox.confirm(I18n.t("admin.groups.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(confirmed) {
|
||||
if (confirmed) {
|
||||
group.destroy().then(function() {
|
||||
groupsController.get('model').removeObject(group);
|
||||
self.transitionToRoute('adminGroups.index');
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
sortProperties: ['name'],
|
||||
refreshingAutoGroups: false,
|
||||
|
||||
actions: {
|
||||
refreshAutoGroups: function(){
|
||||
var self = this;
|
||||
this.set('refreshingAutoGroups', true);
|
||||
Discourse.ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(function() {
|
||||
self.transitionToRoute("adminGroupsType", "automatic").then(function() {
|
||||
self.set('refreshingAutoGroups', false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,24 +0,0 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
sortProperties: ['name'],
|
||||
|
||||
refreshingAutoGroups: false,
|
||||
|
||||
actions: {
|
||||
refreshAutoGroups: function(){
|
||||
var self = this,
|
||||
groups = this.get('model');
|
||||
|
||||
self.set('refreshingAutoGroups', true);
|
||||
this.transitionToRoute('adminGroups.index').then(function() {
|
||||
Discourse.ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(function() {
|
||||
return Discourse.Group.findAll().then(function(newGroups) {
|
||||
groups.clear();
|
||||
groups.addObjects(newGroups);
|
||||
}).finally(function() {
|
||||
self.set('refreshingAutoGroups', false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -2,6 +2,10 @@ export default Ember.ObjectController.extend({
|
||||
editing: false,
|
||||
savedIpAddress: null,
|
||||
|
||||
isRange: function() {
|
||||
return this.get("ip_address").indexOf("/") > 0;
|
||||
}.property("ip_address"),
|
||||
|
||||
actions: {
|
||||
allow: function(record) {
|
||||
record.set('action_name', 'do_nothing');
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
loading: false,
|
||||
|
||||
actions: {
|
||||
clearBlock: function(row){
|
||||
clearBlock(row){
|
||||
row.clearBlock().then(function(){
|
||||
// feeling lazy
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
exportScreenedEmailList() {
|
||||
Discourse.ExportCsv.exportScreenedEmailList().then(outputExportResult);
|
||||
}
|
||||
},
|
||||
|
||||
show: function() {
|
||||
show() {
|
||||
var self = this;
|
||||
this.set('loading', true);
|
||||
self.set('loading', true);
|
||||
Discourse.ScreenedEmail.findAll().then(function(result) {
|
||||
self.set('model', result);
|
||||
self.set('loading', false);
|
||||
|
||||
@ -1,19 +1,46 @@
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
loading: false,
|
||||
itemController: 'admin-log-screened-ip-address',
|
||||
filter: null,
|
||||
|
||||
show: function() {
|
||||
show: Discourse.debounce(function() {
|
||||
var self = this;
|
||||
this.set('loading', true);
|
||||
Discourse.ScreenedIpAddress.findAll().then(function(result) {
|
||||
self.set('loading', true);
|
||||
Discourse.ScreenedIpAddress.findAll(this.get("filter")).then(function(result) {
|
||||
self.set('model', result);
|
||||
self.set('loading', false);
|
||||
});
|
||||
},
|
||||
}, 250).observes("filter"),
|
||||
|
||||
actions: {
|
||||
recordAdded: function(arg) {
|
||||
recordAdded(arg) {
|
||||
this.get("model").unshiftObject(arg);
|
||||
},
|
||||
|
||||
rollUp() {
|
||||
const self = this;
|
||||
return bootbox.confirm(I18n.t("admin.logs.screened_ips.roll_up_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function (confirmed) {
|
||||
if (confirmed) {
|
||||
self.set("loading", true);
|
||||
return Discourse.ScreenedIpAddress.rollUp().then(function(results) {
|
||||
if (results && results.subnets) {
|
||||
if (results.subnets.length > 0) {
|
||||
self.send("show");
|
||||
bootbox.alert(I18n.t("admin.logs.screened_ips.rolled_up_some_subnets", { subnets: results.subnets.join(", ") }));
|
||||
} else {
|
||||
self.set("loading", false);
|
||||
bootbox.alert(I18n.t("admin.logs.screened_ips.rolled_up_no_subnet"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
exportScreenedIpList() {
|
||||
Discourse.ExportCsv.exportScreenedIpList().then(outputExportResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
loading: false,
|
||||
|
||||
show: function() {
|
||||
var self = this;
|
||||
this.set('loading', true);
|
||||
show() {
|
||||
const self = this;
|
||||
self.set('loading', true);
|
||||
Discourse.ScreenedUrl.findAll().then(function(result) {
|
||||
self.set('model', result);
|
||||
self.set('loading', false);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
exportScreenedUrlList() {
|
||||
Discourse.ExportCsv.exportScreenedUrlList().then(outputExportResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,65 +1,98 @@
|
||||
/**
|
||||
This controller supports the interface for listing staff action logs in the admin section.
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
@class AdminLogsStaffActionLogsController
|
||||
@extends Ember.ArrayController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
loading: false,
|
||||
filters: {},
|
||||
filters: null,
|
||||
|
||||
show: function() {
|
||||
var self = this;
|
||||
this.set('loading', true);
|
||||
Discourse.URL.set('queryParams', this.get('filters')); // TODO: doesn't work
|
||||
Discourse.StaffActionLog.findAll(this.get('filters')).then(function(result) {
|
||||
self.set('model', result);
|
||||
self.set('loading', false);
|
||||
});
|
||||
}.observes('filters.action_name', 'filters.acting_user', 'filters.target_user', 'filters.subject'),
|
||||
|
||||
filtersExists: function() {
|
||||
return (_.size(this.get('filters')) > 0);
|
||||
}.property('filters.action_name', 'filters.acting_user', 'filters.target_user', 'filters.subject'),
|
||||
filtersExists: Ember.computed.gt('filterCount', 0),
|
||||
|
||||
actionFilter: function() {
|
||||
if (this.get('filters.action_name')) {
|
||||
return I18n.t("admin.logs.staff_actions.actions." + this.get('filters.action_name'));
|
||||
var name = this.get('filters.action_name');
|
||||
if (name) {
|
||||
return I18n.t("admin.logs.staff_actions.actions." + name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}.property('filters.action_name'),
|
||||
|
||||
showInstructions: function() {
|
||||
return this.get('model.length') > 0;
|
||||
}.property('loading', 'model.length'),
|
||||
showInstructions: Ember.computed.gt('model.length', 0),
|
||||
|
||||
refresh: function() {
|
||||
var self = this;
|
||||
this.set('loading', true);
|
||||
|
||||
var filters = this.get('filters'),
|
||||
params = {},
|
||||
count = 0;
|
||||
|
||||
// Don't send null values
|
||||
Object.keys(filters).forEach(function(k) {
|
||||
var val = filters.get(k);
|
||||
if (val) {
|
||||
params[k] = val;
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
this.set('filterCount', count);
|
||||
|
||||
Discourse.StaffActionLog.findAll(params).then(function(result) {
|
||||
self.set('model', result);
|
||||
}).finally(function() {
|
||||
self.set('loading', false);
|
||||
});
|
||||
},
|
||||
|
||||
resetFilters: function() {
|
||||
this.set('filters', Ember.Object.create());
|
||||
this.refresh();
|
||||
}.on('init'),
|
||||
|
||||
_changeFilters: function(props) {
|
||||
this.get('filters').setProperties(props);
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
actions: {
|
||||
clearFilter: function(key) {
|
||||
delete this.get('filters')[key];
|
||||
this.notifyPropertyChange('filters');
|
||||
var changed = {};
|
||||
|
||||
// Special case, clear all action related stuff
|
||||
if (key === 'actionFilter') {
|
||||
changed.action_name = null;
|
||||
changed.action_id = null;
|
||||
changed.custom_type = null;
|
||||
} else {
|
||||
changed[key] = null;
|
||||
}
|
||||
this._changeFilters(changed);
|
||||
},
|
||||
|
||||
clearAllFilters: function() {
|
||||
this.set('filters', {});
|
||||
this.resetFilters();
|
||||
},
|
||||
|
||||
filterByAction: function(action) {
|
||||
this.set('filters.action_name', action);
|
||||
filterByAction: function(logItem) {
|
||||
this._changeFilters({
|
||||
action_name: logItem.get('action_name'),
|
||||
action_id: logItem.get('action'),
|
||||
custom_type: logItem.get('custom_type')
|
||||
});
|
||||
},
|
||||
|
||||
filterByStaffUser: function(acting_user) {
|
||||
this.set('filters.acting_user', acting_user.username);
|
||||
this._changeFilters({ acting_user: acting_user.username });
|
||||
},
|
||||
|
||||
filterByTargetUser: function(target_user) {
|
||||
this.set('filters.target_user', target_user.username);
|
||||
this._changeFilters({ target_user: target_user.username });
|
||||
},
|
||||
|
||||
filterBySubject: function(subject) {
|
||||
this.set('filters.subject', subject);
|
||||
this._changeFilters({ subject: subject });
|
||||
},
|
||||
|
||||
exportStaffActionLogs: function() {
|
||||
Discourse.ExportCsv.exportStaffActionLogs().then(outputExportResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
|
||||
adminRoutes: function() {
|
||||
return this.get('model').map(p => p.admin_route).compact();
|
||||
}.property()
|
||||
});
|
||||
@ -3,29 +3,16 @@ export default Ember.ObjectController.extend({
|
||||
needs: ['adminSiteSettings'],
|
||||
|
||||
filteredContent: function() {
|
||||
if (!this.get('categoryNameKey')) { return Em.A(); }
|
||||
|
||||
var category = this.get('controllers.adminSiteSettings.content').find(function(siteSettingCategory) {
|
||||
return siteSettingCategory.nameKey === this.get('categoryNameKey');
|
||||
}, this);
|
||||
if (!this.get('categoryNameKey')) { return []; }
|
||||
|
||||
var category = this.get('controllers.adminSiteSettings.content').findProperty('nameKey', this.get('categoryNameKey'));
|
||||
if (category) {
|
||||
return category.siteSettings;
|
||||
} else {
|
||||
return Em.A();
|
||||
return [];
|
||||
}
|
||||
}.property('controllers.adminSiteSettings.content', 'categoryNameKey'),
|
||||
|
||||
emptyContentHandler: function() {
|
||||
if (this.get('filteredContent').length < 1) {
|
||||
if ( this.get('controllers.adminSiteSettings.filtered') ) {
|
||||
this.transitionToRoute('adminSiteSettingsCategory', 'all_results');
|
||||
} else {
|
||||
this.transitionToRoute('adminSiteSettings');
|
||||
}
|
||||
}
|
||||
}.observes('filteredContent'),
|
||||
|
||||
actions: {
|
||||
|
||||
/**
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
This controller supports the interface for SiteSettings.
|
||||
|
||||
@class AdminSiteSettingsController
|
||||
@extends Ember.ArrayController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
filter: null,
|
||||
onlyOverridden: false,
|
||||
@ -28,6 +20,7 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
|
||||
if ((filter === undefined || filter.length < 1) && !this.get('onlyOverridden')) {
|
||||
this.set('model', this.get('allSiteSettings'));
|
||||
this.transitionToRoute("adminSiteSettings");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,20 +43,19 @@ export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
});
|
||||
if (matches.length > 0) {
|
||||
matchesGroupedByCategory[0].siteSettings.pushObjects(matches);
|
||||
matchesGroupedByCategory.pushObject({
|
||||
nameKey: settingsCategory.nameKey,
|
||||
name: settingsCategory.name,
|
||||
siteSettings: matches});
|
||||
}
|
||||
});
|
||||
|
||||
this.set('model', matchesGroupedByCategory);
|
||||
this.transitionToRoute("adminSiteSettingsCategory", "all_results");
|
||||
}, 250).observes('filter', 'onlyOverridden'),
|
||||
|
||||
actions: {
|
||||
clearFilter: function() {
|
||||
this.set('filter', '');
|
||||
this.set('onlyOverridden', false);
|
||||
this.setProperties({
|
||||
filter: '',
|
||||
onlyOverridden: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ export default Ember.ObjectController.extend({
|
||||
|
||||
saveDisabled: function() {
|
||||
if (this.get('saving')) { return true; }
|
||||
if ((!this.get('allow_blank')) && Ember.empty(this.get('value'))) { return true; }
|
||||
if ((!this.get('allow_blank')) && Ember.isEmpty(this.get('value'))) { return true; }
|
||||
return false;
|
||||
}.property('saving', 'value'),
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ export default Ember.ArrayController.extend({
|
||||
}
|
||||
});
|
||||
|
||||
return badges;
|
||||
return _.sortBy(badges, "name");
|
||||
}.property('badges.@each', 'model.@each'),
|
||||
|
||||
/**
|
||||
|
||||
@ -17,15 +17,18 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
||||
if (this.get('required')) {
|
||||
ret.push(I18n.t('admin.user_fields.required.enabled'));
|
||||
}
|
||||
if (this.get('show_on_profile')) {
|
||||
ret.push(I18n.t('admin.user_fields.show_on_profile.enabled'));
|
||||
}
|
||||
|
||||
return ret.join(', ');
|
||||
}.property('editable', 'required'),
|
||||
}.property('editable', 'required', 'show_on_profile'),
|
||||
|
||||
actions: {
|
||||
save: function() {
|
||||
var self = this;
|
||||
|
||||
var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required');
|
||||
var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required', 'show_on_profile');
|
||||
|
||||
this.get('model').save(attrs).then(function(res) {
|
||||
self.set('model.id', res.user_field.id);
|
||||
@ -50,7 +53,7 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
||||
|
||||
cancel: function() {
|
||||
var id = this.get('id');
|
||||
if (Ember.empty(id)) {
|
||||
if (Ember.isEmpty(id)) {
|
||||
this.get('controllers.admin-user-fields').send('destroy', this.get('model'));
|
||||
} else {
|
||||
this.rollbackBuffer();
|
||||
|
||||
@ -19,7 +19,7 @@ export default ObjectController.extend(CanCheckEmails, {
|
||||
var siteUserFields = this.site.get('user_fields'),
|
||||
userFields = this.get('user_fields');
|
||||
|
||||
if (!Ember.empty(siteUserFields)) {
|
||||
if (!Ember.isEmpty(siteUserFields)) {
|
||||
return siteUserFields.map(function(uf) {
|
||||
var value = userFields ? userFields[uf.get('id').toString()] : null;
|
||||
return {name: uf.get('name'), value: value};
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
export default Ember.ArrayController.extend({
|
||||
query: null,
|
||||
showEmails: false,
|
||||
refreshing: false,
|
||||
listFilter: null,
|
||||
selectAll: false,
|
||||
|
||||
queryNew: Em.computed.equal('query', 'new'),
|
||||
queryPending: Em.computed.equal('query', 'pending'),
|
||||
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
|
||||
showApproval: Em.computed.and('siteSettings.must_approve_users', 'queryHasApproval'),
|
||||
searchHint: Discourse.computed.i18n('search_hint'),
|
||||
hasSelection: Em.computed.gt('selectedCount', 0),
|
||||
|
||||
selectedCount: function() {
|
||||
var model = this.get('model');
|
||||
if (!model || !model.length) return 0;
|
||||
return model.filterProperty('selected').length;
|
||||
}.property('model.@each.selected'),
|
||||
|
||||
selectAllChanged: function() {
|
||||
var val = this.get('selectAll');
|
||||
this.get('model').forEach(function(user) {
|
||||
if (user.get('can_approve')) {
|
||||
user.set('selected', val);
|
||||
}
|
||||
});
|
||||
}.observes('selectAll'),
|
||||
|
||||
title: function() {
|
||||
return I18n.t('admin.users.titles.' + this.get('query'));
|
||||
}.property('query'),
|
||||
|
||||
_filterUsers: Discourse.debounce(function() {
|
||||
this._refreshUsers();
|
||||
}, 250).observes('listFilter'),
|
||||
|
||||
_refreshUsers: function() {
|
||||
var self = this;
|
||||
this.set('refreshing', true);
|
||||
|
||||
Discourse.AdminUser.findAll(this.get('query'), { filter: this.get('listFilter'), show_emails: this.get('showEmails') }).then(function (result) {
|
||||
self.set('model', result);
|
||||
}).finally(function() {
|
||||
self.set('refreshing', false);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
approveUsers: function() {
|
||||
Discourse.AdminUser.bulkApprove(this.get('model').filterProperty('selected'));
|
||||
this._refreshUsers();
|
||||
},
|
||||
|
||||
rejectUsers: function() {
|
||||
var maxPostAge = this.siteSettings.delete_user_max_post_age;
|
||||
var controller = this;
|
||||
Discourse.AdminUser.bulkReject(this.get('model').filterProperty('selected')).then(function(result){
|
||||
var message = I18n.t("admin.users.reject_successful", {count: result.success});
|
||||
if (result.failed > 0) {
|
||||
message += ' ' + I18n.t("admin.users.reject_failures", {count: result.failed});
|
||||
message += ' ' + I18n.t("admin.user.delete_forbidden", {count: maxPostAge});
|
||||
}
|
||||
bootbox.alert(message);
|
||||
controller._refreshUsers();
|
||||
});
|
||||
},
|
||||
|
||||
showEmails: function() {
|
||||
this.set('showEmails', true);
|
||||
this._refreshUsers(true);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,140 +0,0 @@
|
||||
/**
|
||||
This controller supports the interface for listing users in the admin section.
|
||||
|
||||
@class AdminUsersListController
|
||||
@extends Ember.ArrayController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
export default Ember.ArrayController.extend(Discourse.Presence, {
|
||||
username: null,
|
||||
query: null,
|
||||
selectAll: false,
|
||||
loading: false,
|
||||
|
||||
mustApproveUsers: Discourse.computed.setting('must_approve_users'),
|
||||
queryNew: Em.computed.equal('query', 'new'),
|
||||
queryPending: Em.computed.equal('query', 'pending'),
|
||||
queryHasApproval: Em.computed.or('queryNew', 'queryPending'),
|
||||
|
||||
searchHint: function() { return I18n.t("search_hint"); }.property(),
|
||||
|
||||
/**
|
||||
Triggered when the selectAll property is changed
|
||||
|
||||
@event selectAll
|
||||
**/
|
||||
selectAllChanged: function() {
|
||||
var _this = this;
|
||||
_.each(this.get('model'),function(user) {
|
||||
user.set('selected', _this.get('selectAll'));
|
||||
});
|
||||
}.observes('selectAll'),
|
||||
|
||||
/**
|
||||
Triggered when the username filter is changed
|
||||
|
||||
@event filterUsers
|
||||
**/
|
||||
filterUsers: Discourse.debounce(function() {
|
||||
this.refreshUsers();
|
||||
}, 250).observes('username'),
|
||||
|
||||
/**
|
||||
Triggered when the order of the users list is changed
|
||||
|
||||
@event orderChanged
|
||||
**/
|
||||
orderChanged: function() {
|
||||
this.refreshUsers();
|
||||
}.observes('query'),
|
||||
|
||||
/**
|
||||
The title of the user list, based on which query was performed.
|
||||
|
||||
@property title
|
||||
**/
|
||||
title: function() {
|
||||
return I18n.t('admin.users.titles.' + this.get('query'));
|
||||
}.property('query'),
|
||||
|
||||
/**
|
||||
Do we want to show the approval controls?
|
||||
|
||||
@property showApproval
|
||||
**/
|
||||
showApproval: function() {
|
||||
return Discourse.SiteSettings.must_approve_users && this.get('queryHasApproval');
|
||||
}.property('queryPending'),
|
||||
|
||||
/**
|
||||
How many users are currently selected
|
||||
|
||||
@property selectedCount
|
||||
**/
|
||||
selectedCount: function() {
|
||||
if (this.blank('model')) return 0;
|
||||
return this.get('model').filterProperty('selected').length;
|
||||
}.property('model.@each.selected'),
|
||||
|
||||
/**
|
||||
Do we have any selected users?
|
||||
|
||||
@property hasSelection
|
||||
**/
|
||||
hasSelection: Em.computed.gt('selectedCount', 0),
|
||||
|
||||
/**
|
||||
Refresh the current list of users.
|
||||
|
||||
@method refreshUsers
|
||||
**/
|
||||
refreshUsers: function(showEmails) {
|
||||
var adminUsersListController = this;
|
||||
adminUsersListController.set('loading', true);
|
||||
|
||||
Discourse.AdminUser.findAll(this.get('query'), { filter: this.get('username'), show_emails: showEmails }).then(function (result) {
|
||||
adminUsersListController.set('model', result);
|
||||
adminUsersListController.set('loading', false);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
Show the list of users.
|
||||
|
||||
@method show
|
||||
**/
|
||||
show: function(term) {
|
||||
if (this.get('query') === term) {
|
||||
this.refreshUsers();
|
||||
return;
|
||||
}
|
||||
this.set('query', term);
|
||||
},
|
||||
|
||||
actions: {
|
||||
approveUsers: function() {
|
||||
Discourse.AdminUser.bulkApprove(this.get('model').filterProperty('selected'));
|
||||
this.refreshUsers();
|
||||
},
|
||||
|
||||
rejectUsers: function() {
|
||||
var controller = this;
|
||||
Discourse.AdminUser.bulkReject(this.get('model').filterProperty('selected')).then(function(result){
|
||||
var message = I18n.t("admin.users.reject_successful", {count: result.success});
|
||||
if (result.failed > 0) {
|
||||
message += ' ' + I18n.t("admin.users.reject_failures", {count: result.failed});
|
||||
message += ' ' + I18n.t("admin.user.delete_forbidden", {count: Discourse.SiteSettings.delete_user_max_post_age});
|
||||
}
|
||||
bootbox.alert(message);
|
||||
controller.refreshUsers();
|
||||
});
|
||||
},
|
||||
|
||||
showEmails: function() {
|
||||
this.refreshUsers(true);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -2,6 +2,6 @@ import DiscourseController from 'discourse/controllers/controller';
|
||||
|
||||
export default DiscourseController.extend({
|
||||
showBadges: function() {
|
||||
return this.get('currentUser.admin') && Discourse.SiteSettings.enable_badges;
|
||||
return this.get('currentUser.admin') && this.siteSettings.enable_badges;
|
||||
}.property()
|
||||
});
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
/**
|
||||
Return the count of users at the given trust level.
|
||||
|
||||
@method valueAtTrustLevel
|
||||
@for Handlebars
|
||||
**/
|
||||
Handlebars.registerHelper('valueAtTrustLevel', function(property, trustLevel) {
|
||||
var data = Ember.Handlebars.get(this, property);
|
||||
if( data ) {
|
||||
var item = data.find( function(d) { return parseInt(d.x,10) === parseInt(trustLevel,10); } );
|
||||
if( item ) {
|
||||
return item.y;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
13
app/assets/javascripts/admin/helpers/value-at-tl.js.es6
Normal file
13
app/assets/javascripts/admin/helpers/value-at-tl.js.es6
Normal file
@ -0,0 +1,13 @@
|
||||
import registerUnbound from 'discourse/helpers/register-unbound';
|
||||
|
||||
registerUnbound('value-at-tl', function(data, params) {
|
||||
var tl = parseInt(params.level, 10);
|
||||
if (data) {
|
||||
var item = data.find( function(d) { return parseInt(d.x, 10) === tl; } );
|
||||
if (item) {
|
||||
return item.y;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -98,7 +98,21 @@ Discourse.AdminUser = Discourse.User.extend({
|
||||
this.set('admin', true);
|
||||
this.set('can_grant_admin', false);
|
||||
this.set('can_revoke_admin', true);
|
||||
Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_admin", {type: 'PUT'});
|
||||
var self = this;
|
||||
|
||||
Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_admin", {type: 'PUT'})
|
||||
.then(null, function(e) {
|
||||
self.set('admin', false);
|
||||
self.set('can_grant_admin', true);
|
||||
self.set('can_revoke_admin', false);
|
||||
|
||||
var error;
|
||||
if (e.responseJSON && e.responseJSON.error) {
|
||||
error = e.responseJSON.error;
|
||||
}
|
||||
error = error || I18n.t('admin.user.grant_admin_failed', { error: "http: " + e.status + " - " + e.body });
|
||||
bootbox.alert(error);
|
||||
});
|
||||
},
|
||||
|
||||
// Revoke the user's moderation access
|
||||
@ -113,7 +127,20 @@ Discourse.AdminUser = Discourse.User.extend({
|
||||
this.set('moderator', true);
|
||||
this.set('can_grant_moderation', false);
|
||||
this.set('can_revoke_moderation', true);
|
||||
Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_moderation", {type: 'PUT'});
|
||||
var self = this;
|
||||
Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_moderation", {type: 'PUT'})
|
||||
.then(null, function(e) {
|
||||
self.set('moderator', false);
|
||||
self.set('can_grant_moderation', true);
|
||||
self.set('can_revoke_moderation', false);
|
||||
|
||||
var error;
|
||||
if (e.responseJSON && e.responseJSON.error) {
|
||||
error = e.responseJSON.error;
|
||||
}
|
||||
error = error || I18n.t('admin.user.grant_moderation_failed', { error: "http: " + e.status + " - " + e.body });
|
||||
bootbox.alert(error);
|
||||
});
|
||||
},
|
||||
|
||||
refreshBrowsers: function() {
|
||||
@ -298,9 +325,7 @@ Discourse.AdminUser = Discourse.User.extend({
|
||||
});
|
||||
},
|
||||
|
||||
deleteForbidden: function() {
|
||||
return (!this.get('can_be_deleted') || this.get('post_count') > 0);
|
||||
}.property('post_count'),
|
||||
deleteForbidden: Em.computed.not("canBeDeleted"),
|
||||
|
||||
deleteExplanation: function() {
|
||||
if (this.get('deleteForbidden')) {
|
||||
@ -316,9 +341,10 @@ Discourse.AdminUser = Discourse.User.extend({
|
||||
|
||||
destroy: function(opts) {
|
||||
var user = this;
|
||||
var location = document.location.pathname;
|
||||
|
||||
var performDestroy = function(block) {
|
||||
var formData = { context: window.location.pathname };
|
||||
var formData = { context: location };
|
||||
if (block) {
|
||||
formData["block_email"] = true;
|
||||
formData["block_urls"] = true;
|
||||
@ -332,7 +358,11 @@ Discourse.AdminUser = Discourse.User.extend({
|
||||
data: formData
|
||||
}).then(function(data) {
|
||||
if (data.deleted) {
|
||||
document.location = "/admin/users/list/active";
|
||||
if (/^\/admin\/users\/list\//.test(location)) {
|
||||
document.location = location;
|
||||
} else {
|
||||
document.location = "/admin/users/list/active";
|
||||
}
|
||||
} else {
|
||||
bootbox.alert(I18n.t("admin.user.delete_failed"));
|
||||
if (data.user) {
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
/**
|
||||
Data model for representing an export
|
||||
|
||||
@class ExportCsv
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.ExportCsv = Discourse.Model.extend({});
|
||||
|
||||
Discourse.ExportCsv.reopenClass({
|
||||
/**
|
||||
Exports user list
|
||||
|
||||
@method export_user_list
|
||||
**/
|
||||
exportUserList: function() {
|
||||
return Discourse.ajax("/admin/export_csv/users.json").then(function(result) {
|
||||
if (result.success) {
|
||||
bootbox.alert(I18n.t("admin.export_csv.success"));
|
||||
} else {
|
||||
bootbox.alert(I18n.t("admin.export_csv.failed"));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -45,11 +45,15 @@ Discourse.ScreenedIpAddress = Discourse.Model.extend({
|
||||
});
|
||||
|
||||
Discourse.ScreenedIpAddress.reopenClass({
|
||||
findAll: function() {
|
||||
return Discourse.ajax("/admin/logs/screened_ip_addresses.json").then(function(screened_ips) {
|
||||
findAll: function(filter) {
|
||||
return Discourse.ajax("/admin/logs/screened_ip_addresses.json", { data: { filter: filter } }).then(function(screened_ips) {
|
||||
return screened_ips.map(function(b) {
|
||||
return Discourse.ScreenedIpAddress.create(b);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
rollUp: function() {
|
||||
return Discourse.ajax("/admin/logs/screened_ip_addresses/roll_up", { type: "POST" });
|
||||
}
|
||||
});
|
||||
|
||||
@ -7,11 +7,16 @@
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.SiteCustomization = Discourse.Model.extend({
|
||||
trackedProperties: ['enabled', 'name', 'stylesheet', 'header', 'footer', 'mobile_stylesheet', 'mobile_header', 'mobile_footer', 'override_default_style'],
|
||||
trackedProperties: [
|
||||
'enabled', 'name',
|
||||
'stylesheet', 'header', 'top', 'footer',
|
||||
'mobile_stylesheet', 'mobile_header', 'mobile_top', 'mobile_footer',
|
||||
'head_tag', 'body_tag'
|
||||
],
|
||||
|
||||
description: function() {
|
||||
return "" + this.name + (this.enabled ? ' (*)' : '');
|
||||
}.property('selected', 'name'),
|
||||
}.property('selected', 'name', 'enabled'),
|
||||
|
||||
changed: function() {
|
||||
var self = this;
|
||||
@ -25,8 +30,10 @@ Discourse.SiteCustomization = Discourse.Model.extend({
|
||||
if (changed) { this.set('savingStatus', ''); }
|
||||
|
||||
return changed;
|
||||
|
||||
}.property('override_default_style', 'enabled', 'name', 'stylesheet', 'header', 'footer', 'mobile_stylesheet', 'mobile_header', 'mobile_footer', 'originals'),
|
||||
}.property('enabled', 'name', 'originals',
|
||||
'stylesheet', 'header', 'top', 'footer',
|
||||
'mobile_stylesheet', 'mobile_header', 'mobile_top', 'mobile_footer',
|
||||
'head_tag', 'body_tag'),
|
||||
|
||||
startTrackingChanges: function() {
|
||||
var self = this;
|
||||
@ -43,16 +50,20 @@ Discourse.SiteCustomization = Discourse.Model.extend({
|
||||
save: function() {
|
||||
this.set('savingStatus', I18n.t('saving'));
|
||||
this.set('saving',true);
|
||||
|
||||
var data = {
|
||||
name: this.name,
|
||||
enabled: this.enabled,
|
||||
stylesheet: this.stylesheet,
|
||||
header: this.header,
|
||||
top: this.top,
|
||||
footer: this.footer,
|
||||
mobile_stylesheet: this.mobile_stylesheet,
|
||||
mobile_header: this.mobile_header,
|
||||
mobile_top: this.mobile_top,
|
||||
mobile_footer: this.mobile_footer,
|
||||
override_default_style: this.override_default_style
|
||||
head_tag: this.head_tag,
|
||||
body_tag: this.body_tag
|
||||
};
|
||||
|
||||
var siteCustomization = this;
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
Our data model for interacting with site settings.
|
||||
|
||||
@class SiteSetting
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.SiteSetting = Discourse.Model.extend({
|
||||
|
||||
validationMessage: null,
|
||||
@ -17,16 +9,13 @@ Discourse.SiteSetting = Discourse.Model.extend({
|
||||
**/
|
||||
enabled: function(key, value) {
|
||||
|
||||
if (arguments.length === 1) {
|
||||
// get the boolean value of the setting
|
||||
if (this.blank('value')) return false;
|
||||
return this.get('value') === 'true';
|
||||
|
||||
} else {
|
||||
// set the boolean value of the setting
|
||||
if (arguments.length > 1) {
|
||||
this.set('value', value ? 'true' : 'false');
|
||||
}
|
||||
|
||||
if (this.blank('value')) return false;
|
||||
return this.get('value') === 'true';
|
||||
|
||||
}.property('value'),
|
||||
|
||||
/**
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/**
|
||||
Represents an action taken by a staff member that has been logged.
|
||||
|
||||
@class StaffActionLog
|
||||
@extends Discourse.Model
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.StaffActionLog = Discourse.Model.extend({
|
||||
showFullDetails: false,
|
||||
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
var _fieldTypes = [
|
||||
Ember.Object.create({id: 'text', name: I18n.t('admin.user_fields.field_types.text') }),
|
||||
Ember.Object.create({id: 'confirm', name: I18n.t('admin.user_fields.field_types.confirm') })
|
||||
];
|
||||
|
||||
var UserField = Ember.Object.extend({
|
||||
destroy: function() {
|
||||
var self = this;
|
||||
@ -43,11 +38,18 @@ UserField.reopenClass({
|
||||
},
|
||||
|
||||
fieldTypes: function() {
|
||||
return _fieldTypes;
|
||||
if (!this._fieldTypes) {
|
||||
this._fieldTypes = [
|
||||
Ember.Object.create({id: 'text', name: I18n.t('admin.user_fields.field_types.text') }),
|
||||
Ember.Object.create({id: 'confirm', name: I18n.t('admin.user_fields.field_types.confirm') })
|
||||
];
|
||||
}
|
||||
|
||||
return this._fieldTypes;
|
||||
},
|
||||
|
||||
fieldTypeById: function(id) {
|
||||
return _fieldTypes.findBy('id', id);
|
||||
return this.fieldTypes().findBy('id', id);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
/**
|
||||
Handles the default admin route
|
||||
|
||||
@class AdminDashboardRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
|
||||
setupController: function(c) {
|
||||
@ -16,8 +7,9 @@ export default Discourse.Route.extend({
|
||||
fetchDashboardData: function(c) {
|
||||
if( !c.get('dashboardFetchedAt') || moment().subtract(30, 'minutes').toDate() > c.get('dashboardFetchedAt') ) {
|
||||
c.set('dashboardFetchedAt', new Date());
|
||||
var versionChecks = this.siteSettings.version_checks;
|
||||
Discourse.AdminDashboard.find().then(function(d) {
|
||||
if( Discourse.SiteSettings.version_checks ){
|
||||
if (versionChecks) {
|
||||
c.set('versionCheck', Discourse.VersionCheck.create(d.version_check));
|
||||
}
|
||||
_.each(d.reports,function(report){
|
||||
@ -32,7 +24,8 @@ export default Discourse.Route.extend({
|
||||
c.set('top_referrers', topReferrers);
|
||||
}
|
||||
|
||||
['admins', 'moderators', 'blocked', 'suspended', 'top_traffic_sources', 'top_referred_topics', 'updated_at'].forEach(function(x) {
|
||||
[ 'disk_space','admins', 'moderators', 'blocked', 'suspended',
|
||||
'top_traffic_sources', 'top_referred_topics', 'updated_at'].forEach(function(x) {
|
||||
c.set(x, d[x]);
|
||||
});
|
||||
|
||||
|
||||
7
app/assets/javascripts/admin/routes/admin-emojis.js.es6
Normal file
7
app/assets/javascripts/admin/routes/admin-emojis.js.es6
Normal file
@ -0,0 +1,7 @@
|
||||
export default Discourse.Route.extend({
|
||||
model: function() {
|
||||
return Discourse.ajax("/admin/customize/emojis.json").then(function(emojis) {
|
||||
return emojis.map(function (emoji) { return Ember.Object.create(emoji); });
|
||||
});
|
||||
}
|
||||
});
|
||||
20
app/assets/javascripts/admin/routes/admin-group.js.es6
Normal file
20
app/assets/javascripts/admin/routes/admin-group.js.es6
Normal file
@ -0,0 +1,20 @@
|
||||
export default Discourse.Route.extend({
|
||||
|
||||
model: function(params) {
|
||||
var groups = this.modelFor('adminGroupsType'),
|
||||
group = groups.findProperty('name', params.name);
|
||||
|
||||
if (!group) { return this.transitionTo('adminGroups.index'); }
|
||||
|
||||
return group;
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set("model", model);
|
||||
// clear the user selector
|
||||
controller.set("usernames", null);
|
||||
// load the members of the group
|
||||
model.findMembers();
|
||||
}
|
||||
|
||||
});
|
||||
@ -0,0 +1,5 @@
|
||||
export default Discourse.Route.extend({
|
||||
redirect: function() {
|
||||
this.transitionTo("adminGroupsType", "custom");
|
||||
}
|
||||
});
|
||||
17
app/assets/javascripts/admin/routes/admin-groups-type.js.es6
Normal file
17
app/assets/javascripts/admin/routes/admin-groups-type.js.es6
Normal file
@ -0,0 +1,17 @@
|
||||
export default Discourse.Route.extend({
|
||||
model(params) {
|
||||
return Discourse.Group.findAll().then(function(groups) {
|
||||
return groups.filterBy("type", params.type);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
newGroup() {
|
||||
const self = this;
|
||||
this.transitionTo("adminGroupsType", "custom").then(function() {
|
||||
var group = Discourse.Group.create({ automatic: false, visible: true });
|
||||
self.transitionTo("adminGroup", group);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
export default Discourse.Route.extend({
|
||||
// TODO: make this automatic using an `{{outlet}}`
|
||||
renderTemplate: function() {
|
||||
this.render('admin/templates/logs/staff_action_logs', {into: 'adminLogs'});
|
||||
},
|
||||
|
||||
setupController: function(controller) {
|
||||
controller.resetFilters();
|
||||
controller.refresh();
|
||||
},
|
||||
|
||||
actions: {
|
||||
showDetailsModal: function(logRecord) {
|
||||
Discourse.Route.showModal(this, 'admin_staff_action_log_details', logRecord);
|
||||
this.controllerFor('modal').set('modalClass', 'log-details-modal');
|
||||
},
|
||||
|
||||
showCustomDetailsModal: function(logRecord) {
|
||||
Discourse.Route.showModal(this, logRecord.action_name + '_details', logRecord);
|
||||
this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal');
|
||||
}
|
||||
}
|
||||
});
|
||||
12
app/assets/javascripts/admin/routes/admin-plugins.js.es6
Normal file
12
app/assets/javascripts/admin/routes/admin-plugins.js.es6
Normal file
@ -0,0 +1,12 @@
|
||||
export default Ember.Route.extend({
|
||||
model() {
|
||||
return this.store.findAll('plugin');
|
||||
},
|
||||
|
||||
actions: {
|
||||
showSettings() {
|
||||
this.transitionTo('adminSiteSettingsCategory', 'plugins');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
66
app/assets/javascripts/admin/routes/admin-route-map.js.es6
Normal file
66
app/assets/javascripts/admin/routes/admin-route-map.js.es6
Normal file
@ -0,0 +1,66 @@
|
||||
export default {
|
||||
resource: 'admin',
|
||||
|
||||
map() {
|
||||
this.route('dashboard', { path: '/' });
|
||||
this.resource('adminSiteSettings', { path: '/site_settings' }, function() {
|
||||
this.resource('adminSiteSettingsCategory', { path: 'category/:category_id'} );
|
||||
});
|
||||
|
||||
this.resource('adminEmail', { path: '/email'}, function() {
|
||||
this.route('all');
|
||||
this.route('sent');
|
||||
this.route('skipped');
|
||||
this.route('previewDigest', { path: '/preview-digest' });
|
||||
});
|
||||
|
||||
this.resource('adminCustomize', { path: '/customize' } ,function() {
|
||||
this.route('colors');
|
||||
this.route('css_html');
|
||||
this.resource('adminSiteText', { path: '/site_text' }, function() {
|
||||
this.route('edit', {path: '/:text_type'});
|
||||
});
|
||||
this.resource('adminUserFields', { path: '/user_fields' });
|
||||
this.resource('adminEmojis', { path: '/emojis' });
|
||||
});
|
||||
this.route('api');
|
||||
|
||||
this.resource('admin.backups', { path: '/backups' }, function() {
|
||||
this.route('logs');
|
||||
});
|
||||
|
||||
this.resource('adminReports', { path: '/reports/:type' });
|
||||
|
||||
this.resource('adminFlags', { path: '/flags' }, function() {
|
||||
this.route('list', { path: '/:filter' });
|
||||
});
|
||||
|
||||
this.resource('adminLogs', { path: '/logs' }, function() {
|
||||
this.route('staffActionLogs', { path: '/staff_action_logs' });
|
||||
this.route('screenedEmails', { path: '/screened_emails' });
|
||||
this.route('screenedIpAddresses', { path: '/screened_ip_addresses' });
|
||||
this.route('screenedUrls', { path: '/screened_urls' });
|
||||
});
|
||||
|
||||
this.resource('adminGroups', { path: '/groups' }, function() {
|
||||
this.resource('adminGroupsType', { path: '/:type' }, function() {
|
||||
this.resource('adminGroup', { path: '/:name' });
|
||||
});
|
||||
});
|
||||
|
||||
this.resource('adminUsers', { path: '/users' }, function() {
|
||||
this.resource('adminUser', { path: '/:username' }, function() {
|
||||
this.route('badges');
|
||||
this.route('tl3Requirements', { path: '/tl3_requirements' });
|
||||
});
|
||||
|
||||
this.resource('adminUsersList', { path: '/list' }, function() {
|
||||
this.route('show', { path: '/:filter' });
|
||||
});
|
||||
});
|
||||
|
||||
this.resource('adminBadges', { path: '/badges' }, function() {
|
||||
this.route('show', { path: '/:badge_id' });
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,5 @@
|
||||
export default Discourse.Route.extend({
|
||||
redirect: function() {
|
||||
this.replaceWith('adminUsersList.show', 'active');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,15 @@
|
||||
export default Discourse.Route.extend({
|
||||
model: function(params) {
|
||||
this.userFilter = params.filter;
|
||||
return Discourse.AdminUser.findAll(params.filter);
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.setProperties({
|
||||
model: model,
|
||||
query: this.userFilter,
|
||||
showEmails: false,
|
||||
refreshing: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
19
app/assets/javascripts/admin/routes/admin-users-list.js.es6
Normal file
19
app/assets/javascripts/admin/routes/admin-users-list.js.es6
Normal file
@ -0,0 +1,19 @@
|
||||
import { outputExportResult } from 'discourse/lib/export-result';
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
|
||||
actions: {
|
||||
exportUsers: function() {
|
||||
Discourse.ExportCsv.exportUserList().then(outputExportResult);
|
||||
},
|
||||
|
||||
sendInvites: function() {
|
||||
this.transitionTo('user.invited', Discourse.User.current());
|
||||
},
|
||||
|
||||
deleteUser: function(user) {
|
||||
Discourse.AdminUser.create(user).destroy({ deletePosts: true });
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,13 +1,4 @@
|
||||
/**
|
||||
Handles email routes
|
||||
|
||||
@class AdminEmailRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminEmailIndexRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return Discourse.EmailSettings.find();
|
||||
},
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
Discourse.AdminGroupRoute = Discourse.Route.extend({
|
||||
|
||||
model: function(params) {
|
||||
var groups = this.modelFor('adminGroups'),
|
||||
group = groups.findProperty('name', params.name);
|
||||
|
||||
if (!group) { return this.transitionTo('adminGroups.index'); }
|
||||
return group;
|
||||
},
|
||||
|
||||
afterModel: function(model) {
|
||||
var self = this;
|
||||
return model.findMembers().then(function(members) {
|
||||
self.set('_members', members);
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
controller.set('model', model);
|
||||
controller.set('members', this.get('_members'));
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
Handles routes for admin groups
|
||||
|
||||
@class AdminGroupsRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminGroupsRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
return Discourse.Group.findAll();
|
||||
},
|
||||
|
||||
actions: {
|
||||
showGroup: function(g) {
|
||||
// This hack is needed because the autocomplete plugin does not
|
||||
// refresh properly when the underlying data changes. TODO should
|
||||
// be to update the plugin so it works properly and remove this hack.
|
||||
var self = this;
|
||||
this.transitionTo('adminGroups.index').then(function() {
|
||||
self.transitionTo('adminGroup', g);
|
||||
});
|
||||
},
|
||||
|
||||
newGroup: function(){
|
||||
var group = Discourse.Group.create({ visible: true });
|
||||
this.send('showGroup', group);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -12,47 +12,6 @@ Discourse.AdminLogsIndexRoute = Discourse.Route.extend({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
The route that lists staff actions that were logged.
|
||||
|
||||
@class AdminLogsStaffActionLogsRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminLogsStaffActionLogsRoute = Discourse.Route.extend({
|
||||
renderTemplate: function() {
|
||||
this.render('admin/templates/logs/staff_action_logs', {into: 'adminLogs'});
|
||||
},
|
||||
|
||||
setupController: function(controller) {
|
||||
var queryParams = Discourse.URL.get('queryParams');
|
||||
if (queryParams) {
|
||||
controller.set('filters', queryParams);
|
||||
}
|
||||
return controller.show();
|
||||
},
|
||||
|
||||
actions: {
|
||||
showDetailsModal: function(logRecord) {
|
||||
Discourse.Route.showModal(this, 'admin_staff_action_log_details', logRecord);
|
||||
this.controllerFor('modal').set('modalClass', 'log-details-modal');
|
||||
},
|
||||
|
||||
showCustomDetailsModal: function(logRecord) {
|
||||
Discourse.Route.showModal(this, logRecord.action_name + '_details', logRecord);
|
||||
this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal');
|
||||
}
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
this._super();
|
||||
|
||||
// Clear any filters when we leave the route
|
||||
Discourse.URL.set('queryParams', null);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
The route that lists blocked email addresses.
|
||||
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
Discourse.Route.buildRoutes(function() {
|
||||
this.resource('admin', function() {
|
||||
this.route('dashboard', { path: '/' });
|
||||
this.resource('adminSiteSettings', { path: '/site_settings' }, function() {
|
||||
this.resource('adminSiteSettingsCategory', { path: 'category/:category_id'} );
|
||||
});
|
||||
|
||||
this.resource('adminEmail', { path: '/email'}, function() {
|
||||
this.route('all');
|
||||
this.route('sent');
|
||||
this.route('skipped');
|
||||
this.route('previewDigest', { path: '/preview-digest' });
|
||||
});
|
||||
|
||||
this.resource('adminCustomize', { path: '/customize' } ,function() {
|
||||
this.route('colors');
|
||||
this.route('css_html');
|
||||
this.resource('adminSiteText', { path: '/site_text' }, function() {
|
||||
this.route('edit', {path: '/:text_type'});
|
||||
});
|
||||
this.resource('adminUserFields', { path: '/user_fields' }, function() {
|
||||
});
|
||||
});
|
||||
this.route('api');
|
||||
|
||||
this.resource('admin.backups', { path: '/backups' }, function() {
|
||||
this.route('logs');
|
||||
});
|
||||
|
||||
this.resource('adminReports', { path: '/reports/:type' });
|
||||
|
||||
this.resource('adminFlags', { path: '/flags' }, function() {
|
||||
this.route('list', { path: '/:filter' });
|
||||
});
|
||||
|
||||
this.resource('adminLogs', { path: '/logs' }, function() {
|
||||
this.route('staffActionLogs', { path: '/staff_action_logs' });
|
||||
this.route('screenedEmails', { path: '/screened_emails' });
|
||||
this.route('screenedIpAddresses', { path: '/screened_ip_addresses' });
|
||||
this.route('screenedUrls', { path: '/screened_urls' });
|
||||
});
|
||||
|
||||
this.resource('adminGroups', { path: '/groups'}, function() {
|
||||
this.resource('adminGroup', { path: '/:name' });
|
||||
});
|
||||
|
||||
this.resource('adminUsers', { path: '/users' }, function() {
|
||||
this.resource('adminUser', { path: '/:username' }, function() {
|
||||
this.route('badges');
|
||||
this.route('tl3Requirements', { path: '/tl3_requirements' });
|
||||
});
|
||||
this.resource('adminUsersList', { path: '/list' }, function() {
|
||||
_.each(['active', 'new', 'pending', 'admins', 'moderators', 'blocked', 'suspended',
|
||||
'newuser', 'basicuser', 'regular', 'leaders', 'elders'], function(x) {
|
||||
this.route(x, { path: '/' + x });
|
||||
}, this);
|
||||
});
|
||||
});
|
||||
|
||||
this.resource('adminBadges', { path: '/badges' }, function() {
|
||||
this.route('show', { path: '/:badge_id' });
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@ -1,131 +0,0 @@
|
||||
/**
|
||||
Handles the route that deals with listing users
|
||||
|
||||
@class AdminUsersListRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListRoute = Discourse.Route.extend({
|
||||
renderTemplate: function() {
|
||||
this.render('admin/templates/users_list', {into: 'admin/templates/admin'});
|
||||
},
|
||||
|
||||
actions: {
|
||||
exportUsers: function() {
|
||||
Discourse.ExportCsv.exportUserList();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Index should just redirect to active
|
||||
|
||||
@class AdminUsersIndexRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListIndexRoute = Discourse.Route.extend({
|
||||
redirect: function() {
|
||||
this.transitionTo('adminUsersList.active');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists active users.
|
||||
|
||||
@class AdminUsersListActiveRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListActiveRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('active');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists new users.
|
||||
|
||||
@class AdminUsersListNewRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListNewRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('new');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists pending users.
|
||||
|
||||
@class AdminUsersListPendingRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListPendingRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('pending');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists admin users.
|
||||
|
||||
@class AdminUsersListAdminsRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListAdminsRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('admins');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists moderators.
|
||||
|
||||
@class AdminUsersListModeratorsRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListModeratorsRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('moderators');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists blocked users.
|
||||
|
||||
@class AdminUsersListBlockedRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListBlockedRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('blocked');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists suspended users.
|
||||
|
||||
@class AdminUsersListSuspendedRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListSuspendedRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('suspended');
|
||||
}
|
||||
});
|
||||
@ -1,69 +0,0 @@
|
||||
/**
|
||||
Handles the route that lists users at trust level 0.
|
||||
|
||||
@class AdminUsersListNewuserRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListNewuserRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('newuser');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists users at trust level 1.
|
||||
|
||||
@class AdminUsersListBasicuserRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListBasicuserRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('basic');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists users at trust level 2.
|
||||
|
||||
@class AdminUsersListRegularRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListRegularRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('regular');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists users at trust level 3.
|
||||
|
||||
@class AdminUsersListLeadersRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListLeadersRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('leader');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Handles the route that lists users at trust level 4.
|
||||
|
||||
@class AdminUsersListEldersRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.AdminUsersListEldersRoute = Discourse.Route.extend({
|
||||
setupController: function() {
|
||||
return this.controllerFor('adminUsersList').show('elder');
|
||||
}
|
||||
});
|
||||
@ -4,25 +4,27 @@
|
||||
<div class="full-width">
|
||||
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'admin.dashboard'}}{{i18n admin.dashboard.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='admin.dashboard' label='admin.dashboard.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
<li>{{#link-to 'adminSiteSettings'}}{{i18n admin.site_settings.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminSiteSettings' label='admin.site_settings.title'}}
|
||||
{{/if}}
|
||||
<li>{{#link-to 'adminUsersList'}}{{i18n admin.users.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminUsersList' label='admin.users.title'}}
|
||||
{{#if showBadges}}
|
||||
<li>{{#link-to 'adminBadges.index'}}{{i18n admin.badges.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminBadges.index' label='admin.badges.title'}}
|
||||
{{/if}}
|
||||
{{#if currentUser.admin}}
|
||||
<li>{{#link-to 'adminGroups.index'}}{{i18n admin.groups.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminGroups' label='admin.groups.title'}}
|
||||
{{/if}}
|
||||
<li>{{#link-to 'adminEmail'}}{{i18n admin.email.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminFlags'}}{{i18n admin.flags.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminLogs'}}{{i18n admin.logs.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminEmail' label='admin.email.title'}}
|
||||
{{admin-nav-item route='adminFlags' label='admin.flags.title'}}
|
||||
{{admin-nav-item route='adminLogs' label='admin.logs.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'admin.api'}}{{i18n admin.api.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'admin.backups'}}{{i18n admin.backups.title}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='adminCustomize.colors' label='admin.customize.title'}}
|
||||
{{admin-nav-item route='admin.api' label='admin.api.title'}}
|
||||
{{admin-nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{/if}}
|
||||
{{admin-nav-item route='adminPlugins' label='admin.plugins.title'}}
|
||||
{{plugin-outlet "admin-menu" tagName="li"}}
|
||||
</ul>
|
||||
|
||||
<div class='boxed white admin-content'>
|
||||
@ -34,4 +36,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
{{#if model}}
|
||||
<table class='api-keys'>
|
||||
<tr>
|
||||
<th>{{i18n admin.api.key}}</th>
|
||||
<th>{{i18n admin.api.user}}</th>
|
||||
<th>{{i18n 'admin.api.key'}}</th>
|
||||
<th>{{i18n 'admin.api.user'}}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{#each model}}
|
||||
{{#each k in model}}
|
||||
<tr>
|
||||
<td class='key'>{{key}}</td>
|
||||
<td class='key'>{{k.key}}</td>
|
||||
<td>
|
||||
{{#if user}}
|
||||
{{#link-to 'adminUser' user}}
|
||||
{{avatar user imageSize="small"}}
|
||||
{{#if k.user}}
|
||||
{{#link-to 'adminUser' k.user}}
|
||||
{{avatar k.user imageSize="small"}}
|
||||
{{/link-to}}
|
||||
{{else}}
|
||||
{{i18n admin.api.all_users}}
|
||||
{{i18n 'admin.api.all_users'}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
<button class='btn' {{action "regenerateKey" this}}><i class="fa fa-undo"></i>{{i18n admin.api.regenerate}}</button>
|
||||
<button class='btn' {{action "revokeKey" this}}><i class="fa fa-times"></i>{{i18n admin.api.revoke}}</button>
|
||||
<button class='btn' {{action "regenerateKey" k}}><i class="fa fa-undo"></i>{{i18n 'admin.api.regenerate'}}</button>
|
||||
<button class='btn' {{action "revokeKey" k}}><i class="fa fa-times"></i>{{i18n 'admin.api.revoke'}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n admin.api.none}}</p>
|
||||
<p>{{i18n 'admin.api.none'}}</p>
|
||||
{{/if}}
|
||||
|
||||
{{#unless hasMasterKey}}
|
||||
<button class='btn' {{action "generateMasterKey"}}><i class="fa fa-key"></i>{{i18n admin.api.generate_master}}</button>
|
||||
<button class='btn' {{action "generateMasterKey"}}><i class="fa fa-key"></i>{{i18n 'admin.api.generate_master'}}</button>
|
||||
{{/unless }}
|
||||
|
||||
@ -1,18 +1,31 @@
|
||||
<div class="admin-controls">
|
||||
<div class="span15">
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to "admin.backups.index"}}{{i18n admin.backups.menu.backups}}{{/link-to}}</li>
|
||||
<li>{{#link-to "admin.backups.logs"}}{{i18n admin.backups.menu.logs}}{{/link-to}}</li>
|
||||
{{admin-nav-item route='admin.backups.index' label='admin.backups.menu.backups'}}
|
||||
{{admin-nav-item route='admin.backups.logs' label='admin.backups.menu.logs'}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
{{#if canRollback}}
|
||||
<button {{action "rollback"}} class="btn btn-rollback" title="{{i18n admin.backups.operations.rollback.title}}" {{bind-attr disabled="rollbackDisabled"}}><i class="fa fa-ambulance fa-flip-horizontal"></i>{{i18n admin.backups.operations.rollback.text}}</button>
|
||||
{{d-button action="rollback"
|
||||
class="btn-rollback"
|
||||
label="admin.backups.operations.rollback.text"
|
||||
title="admin.backups.operations.rollback.title"
|
||||
icon="ambulance"
|
||||
disabled=rollbackDisabled}}
|
||||
{{/if}}
|
||||
{{#if isOperationRunning}}
|
||||
<button {{action "cancelOperation"}} class="btn btn-danger" title="{{i18n admin.backups.operations.cancel.title}}"><i class="fa fa-times"></i>{{i18n admin.backups.operations.cancel.text}}</button>
|
||||
{{d-button action="cancelOperation"
|
||||
class="btn-danger"
|
||||
title="admin.backups.operations.cancel.title"
|
||||
label="admin.backups.operations.cancel.text"
|
||||
icon="times"}}
|
||||
{{else}}
|
||||
<button {{action "startBackup"}} class="btn btn-primary" title="{{i18n admin.backups.operations.backup.title}}"><i class="fa fa-rocket"></i>{{i18n admin.backups.operations.backup.text}}</button>
|
||||
{{d-button action="startBackup"
|
||||
class="btn-primary"
|
||||
title="admin.backups.operations.backup.title"
|
||||
label="admin.backups.operations.backup.text"
|
||||
icon="rocket"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<table>
|
||||
<tr>
|
||||
<th width="55%">{{i18n admin.backups.columns.filename}}</th>
|
||||
<th width="10%">{{i18n admin.backups.columns.size}}</th>
|
||||
<th width="55%">{{i18n 'admin.backups.columns.filename'}}</th>
|
||||
<th width="10%">{{i18n 'admin.backups.columns.size'}}</th>
|
||||
<th>
|
||||
<div class="pull-right">
|
||||
{{resumable-upload target="/admin/backups/upload" success="uploadSuccess" error="uploadError" uploadText=uploadText}}
|
||||
@ -15,15 +15,15 @@
|
||||
<td>{{human-size backup.size}}</td>
|
||||
<td>
|
||||
<div class="pull-right">
|
||||
<a {{bind-attr href="backup.link"}} class="btn download" title="{{i18n admin.backups.operations.download.title}}"><i class="fa fa-download"></i>{{i18n admin.backups.operations.download.text}}</a>
|
||||
<a {{bind-attr href="backup.link"}} class="btn download" title="{{i18n 'admin.backups.operations.download.title'}}"><i class="fa fa-download"></i>{{i18n 'admin.backups.operations.download.text'}}</a>
|
||||
<button {{action "destroyBackup" backup}} class="btn btn-danger no-text" {{bind-attr disabled="destroyDisabled" title="destroyTitle"}}><i class="fa fa-trash-o"></i></button>
|
||||
<button {{action "startRestore" backup}} class="btn" {{bind-attr disabled="restoreDisabled" title="restoreTitle"}}><i class="fa fa-play"></i>{{i18n admin.backups.operations.restore.text}}</button>
|
||||
<button {{action "startRestore" backup}} class="btn" {{bind-attr disabled="restoreDisabled" title="restoreTitle"}}><i class="fa fa-play"></i>{{i18n 'admin.backups.operations.restore.text'}}</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<td>{{i18n admin.backups.none}}</td>
|
||||
<td>{{i18n 'admin.backups.none'}}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<div class='span13'>
|
||||
<p>{{i18n admin.badges.none_selected}}</p>
|
||||
<p>{{i18n 'admin.badges.none_selected'}}</p>
|
||||
|
||||
<div>
|
||||
{{#link-to 'adminBadges.show' 'new' class="btn"}}
|
||||
{{fa-icon "plus"}} {{i18n admin.badges.new}}
|
||||
{{fa-icon "plus"}} {{i18n 'admin.badges.new'}}
|
||||
{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,52 +1,52 @@
|
||||
<div class='current-badge span13'>
|
||||
<form class="form-horizontal">
|
||||
<div>
|
||||
<label for="name">{{i18n admin.badges.name}}</label>
|
||||
<label for="name">{{i18n 'admin.badges.name'}}</label>
|
||||
{{input type="text" name="name" value=buffered.name}}
|
||||
</div>
|
||||
|
||||
{{#if showDisplayName}}
|
||||
<div>
|
||||
<strong>{{i18n admin.badges.display_name}}</strong>
|
||||
<strong>{{i18n 'admin.badges.display_name'}}</strong>
|
||||
{{buffered.displayName}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<label for="name">{{i18n admin.badges.icon}}</label>
|
||||
<label for="name">{{i18n 'admin.badges.icon'}}</label>
|
||||
{{input type="text" name="name" value=buffered.icon}}
|
||||
<p class='help'>{{i18n admin.badges.icon_help}}</p>
|
||||
<p class='help'>{{i18n 'admin.badges.icon_help'}}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="name">{{i18n admin.badges.image}}</label>
|
||||
<label for="name">{{i18n 'admin.badges.image'}}</label>
|
||||
{{input type="text" name="name" value=buffered.image}}
|
||||
<p class='help'>{{i18n admin.badges.icon_help}}</p>
|
||||
<p class='help'>{{i18n 'admin.badges.icon_help'}}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="badge_type_id">{{i18n admin.badges.badge_type}}</label>
|
||||
{{view Ember.Select name="badge_type_id"
|
||||
value=buffered.badge_type_id
|
||||
content=badgeTypes
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
disabled=readOnly}}
|
||||
<label for="badge_type_id">{{i18n 'admin.badges.badge_type'}}</label>
|
||||
{{view "select" name="badge_type_id"
|
||||
value=buffered.badge_type_id
|
||||
content=badgeTypes
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
disabled=readOnly}}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="badge_grouping_id">{{i18n admin.badges.badge_grouping}}</label>
|
||||
{{view Ember.Select name="badge_grouping_id"
|
||||
value=buffered.badge_grouping_id
|
||||
content=badgeGroupings
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"}}
|
||||
<label for="badge_grouping_id">{{i18n 'admin.badges.badge_grouping'}}</label>
|
||||
{{view "select" name="badge_grouping_id"
|
||||
value=buffered.badge_grouping_id
|
||||
content=badgeGroupings
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"}}
|
||||
<button {{action "editGroupings"}} class='btn'>{{fa-icon 'pencil'}}</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<label for="description">{{i18n admin.badges.description}}</label>
|
||||
<label for="description">{{i18n 'admin.badges.description'}}</label>
|
||||
{{#if canEditDescription}}
|
||||
{{textarea name="description" value=buffered.description}}
|
||||
{{else}}
|
||||
@ -55,83 +55,83 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="query">{{i18n admin.badges.query}}</label>
|
||||
<label for="query">{{i18n 'admin.badges.query'}}</label>
|
||||
{{textarea name="query" value=buffered.query disabled=readOnly}}
|
||||
</div>
|
||||
|
||||
{{#if hasQuery}}
|
||||
<a href {{action "preview" buffered "false"}}>{{i18n admin.badges.preview.link_text}}</a>
|
||||
<a href {{action "preview" buffered "false"}}>{{i18n 'admin.badges.preview.link_text'}}</a>
|
||||
|
|
||||
<a href {{action "preview" buffered "true"}}>{{i18n admin.badges.preview.plan_text}}</a>
|
||||
<a href {{action "preview" buffered "true"}}>{{i18n 'admin.badges.preview.plan_text'}}</a>
|
||||
{{#if preview_loading}}
|
||||
{{i18n loading}}...
|
||||
{{i18n 'loading'}}...
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.auto_revoke disabled=readOnly}}
|
||||
{{i18n admin.badges.auto_revoke}}
|
||||
{{i18n 'admin.badges.auto_revoke'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.target_posts disabled=readOnly}}
|
||||
{{i18n admin.badges.target_posts}}
|
||||
{{i18n 'admin.badges.target_posts'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="trigger">{{i18n admin.badges.trigger}}</label>
|
||||
{{view Ember.Select name="trigger"
|
||||
value=buffered.trigger
|
||||
content=badgeTriggers
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
disabled=readOnly}}
|
||||
<label for="trigger">{{i18n 'admin.badges.trigger'}}</label>
|
||||
{{view "select" name="trigger"
|
||||
value=buffered.trigger
|
||||
content=badgeTriggers
|
||||
optionValuePath="content.id"
|
||||
optionLabelPath="content.name"
|
||||
disabled=readOnly}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.allow_title}}
|
||||
{{i18n admin.badges.allow_title}}
|
||||
{{i18n 'admin.badges.allow_title'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.multiple_grant disabled=readOnly}}
|
||||
{{i18n admin.badges.multiple_grant}}
|
||||
{{i18n 'admin.badges.multiple_grant'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.listable disabled=readOnly}}
|
||||
{{i18n admin.badges.listable}}
|
||||
{{i18n 'admin.badges.listable'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.show_posts disabled=readOnly}}
|
||||
{{i18n admin.badges.show_posts}}
|
||||
{{i18n 'admin.badges.show_posts'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=buffered.enabled}}
|
||||
{{i18n admin.badges.enabled}}
|
||||
{{i18n 'admin.badges.enabled'}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled=saving}} class='btn btn-primary'>{{i18n admin.badges.save}}</button>
|
||||
<button {{action "save"}} {{bind-attr disabled=saving}} class='btn btn-primary'>{{i18n 'admin.badges.save'}}</button>
|
||||
<span class='saving'>{{savingStatus}}</span>
|
||||
{{#unless readOnly}}
|
||||
<a {{action "destroy"}} class='delete-link'>{{i18n admin.badges.delete}}</a>
|
||||
<a {{action "destroy"}} class='delete-link'>{{i18n 'admin.badges.delete'}}</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</form>
|
||||
@ -140,7 +140,7 @@
|
||||
{{#if grant_count}}
|
||||
<div class="span13 current-badge-actions">
|
||||
<div>
|
||||
{{#link-to 'badges.show' this}}{{i18n badges.granted count=grant_count}}{{/link-to}}
|
||||
{{#link-to 'badges.show' this}}{{i18n 'badges.granted' count=grant_count}}{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
<div class="badges">
|
||||
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n admin.badges.title}}</h3>
|
||||
<h3>{{i18n 'admin.badges.title'}}</h3>
|
||||
<ul>
|
||||
{{#each}}
|
||||
{{#each badge in model}}
|
||||
<li>
|
||||
{{#link-to 'adminBadges.show' id}}
|
||||
{{badge-button badge=this}}
|
||||
{{#if newBadge}}
|
||||
<span class="list-badge">{{i18n filters.new.lower_title}}</span>
|
||||
{{#link-to 'adminBadges.show' badge.id}}
|
||||
{{badge-button badge=badge}}
|
||||
{{#if badge.newBadge}}
|
||||
<span class="list-badge">{{i18n 'filters.new.lower_title'}}</span>
|
||||
{{/if}}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{#link-to 'adminBadges.show' 'new' class="btn"}}
|
||||
{{fa-icon "plus"}} {{i18n admin.badges.new}}
|
||||
{{fa-icon "plus"}} {{i18n 'admin.badges.new'}}
|
||||
{{/link-to}}
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
{{#if routeParam}}
|
||||
{{#link-to route routeParam}}{{i18n label}}{{/link-to}}
|
||||
{{else}}
|
||||
{{#if route}}
|
||||
{{#link-to route}}{{i18n label}}{{/link-to}}
|
||||
{{else}}
|
||||
<a href="{{unbound href}}" data-auto-route="true">{{i18n label}}</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
@ -0,0 +1,7 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
{{yield}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,13 +1,10 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.colors.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminCustomize.css_html'}}{{i18n admin.customize.css_html.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminSiteText'}}{{i18n admin.site_text.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminUserFields'}}{{i18n admin.user_fields.title}}{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminCustomize.colors' label='admin.customize.colors.title'}}
|
||||
{{admin-nav-item route='adminCustomize.css_html' label='admin.customize.css_html.title'}}
|
||||
{{admin-nav-item route='adminSiteText' label='admin.site_text.title'}}
|
||||
{{admin-nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{admin-nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
|
||||
@ -1,35 +1,33 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n admin.customize.colors.long_title}}</h3>
|
||||
<h3>{{i18n 'admin.customize.colors.long_title'}}</h3>
|
||||
<ul>
|
||||
{{#each model}}
|
||||
{{#unless is_base}}
|
||||
<li><a {{action "selectColorScheme" this}} {{bind-attr class="selected:active"}}>{{description}}</a></li>
|
||||
{{#each scheme in model}}
|
||||
{{#unless scheme.is_base}}
|
||||
<li><a {{action "selectColorScheme" scheme}} {{bind-attr class="scheme.selected:active"}}>{{scheme.description}}</a></li>
|
||||
{{/unless}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
<button {{action "newColorScheme"}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.customize.new}}</button>
|
||||
<button {{action "newColorScheme"}} class='btn'><i class="fa fa-plus"></i>{{i18n 'admin.customize.new'}}</button>
|
||||
</div>
|
||||
|
||||
{{#if selectedItem}}
|
||||
<div class="current-style color-scheme">
|
||||
<div class="admin-container">
|
||||
{{#with selectedItem}}
|
||||
<h1>{{text-field class="style-name" value=name}}</h1>
|
||||
<h1>{{text-field class="style-name" value=selectedItem.name}}</h1>
|
||||
|
||||
<div class="controls">
|
||||
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
|
||||
<button {{action "toggleEnabled"}} {{bind-attr disabled="disableEnable"}} class="btn">
|
||||
{{#if enabled}}
|
||||
{{i18n disable}}
|
||||
{{else}}
|
||||
{{i18n enable}}
|
||||
{{/if}}
|
||||
</button>
|
||||
<button {{action "copy" this}} class='btn'><i class="fa fa-copy"></i> {{i18n admin.customize.copy}}</button>
|
||||
<button {{action "destroy"}} class='btn btn-danger'><i class="fa fa-trash-o"></i> {{i18n admin.customize.delete}}</button>
|
||||
<span {{bind-attr class=":saving savingStatus::hidden" }}>{{savingStatus}}</span>
|
||||
</div>
|
||||
{{/with}}
|
||||
<div class="controls">
|
||||
<button {{action "save"}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n 'admin.customize.save'}}</button>
|
||||
<button {{action "toggleEnabled"}} {{bind-attr disabled="selectedItem.disableEnable"}} class="btn">
|
||||
{{#if selectedItem.enabled}}
|
||||
{{i18n 'disable'}}
|
||||
{{else}}
|
||||
{{i18n 'enable'}}
|
||||
{{/if}}
|
||||
</button>
|
||||
<button {{action "copy" selectedItem}} class='btn'><i class="fa fa-copy"></i> {{i18n 'admin.customize.copy'}}</button>
|
||||
<button {{action "destroy"}} class='btn btn-danger'><i class="fa fa-trash-o"></i> {{i18n 'admin.customize.delete'}}</button>
|
||||
<span {{bind-attr class=":saving selectedItem.savingStatus::hidden" }}>{{selectedItem.savingStatus}}</span>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -37,7 +35,7 @@
|
||||
<div class='search controls'>
|
||||
<label>
|
||||
{{input type="checkbox" checked=onlyOverridden}}
|
||||
{{i18n admin.site_settings.show_overriden}}
|
||||
{{i18n 'admin.site_settings.show_overriden'}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -47,34 +45,34 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="hex">{{i18n admin.customize.color}}</th>
|
||||
<th class="hex">{{i18n 'admin.customize.color'}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each colors}}
|
||||
<tr {{bind-attr class="changed valid:valid:invalid"}}>
|
||||
<td class="name" {{bind-attr title="name"}}>
|
||||
<b>{{translatedName}}</b>
|
||||
{{#each c in colors}}
|
||||
<tr {{bind-attr class="c.changed c.valid:valid:invalid"}}>
|
||||
<td class="name" {{bind-attr title="c.name"}}>
|
||||
<b>{{c.translatedName}}</b>
|
||||
<br/>
|
||||
<span class="description">{{description}}</span>
|
||||
<span class="description">{{c.description}}</span>
|
||||
</td>
|
||||
<td class="hex">{{color-input hexValue=hex brightnessValue=brightness valid=valid}}</td>
|
||||
<td class="hex">{{color-input hexValue=c.hex brightnessValue=c.brightness valid=c.valid}}</td>
|
||||
<td class="actions">
|
||||
<button {{bind-attr class=":btn :revert savedIsOverriden::invisible"}} {{action "revert" this}} title="{{i18n admin.customize.colors.revert_title}}">{{i18n revert}}</button>
|
||||
<button {{bind-attr class=":btn :undo changed::invisible"}} {{action "undo" this}} title="{{i18n admin.customize.colors.undo_title}}">{{i18n undo}}</button>
|
||||
<button {{bind-attr class=":btn :revert c.savedIsOverriden::invisible"}} {{action "revert" c}} title="{{i18n 'admin.customize.colors.revert_title'}}">{{i18n 'revert'}}</button>
|
||||
<button {{bind-attr class=":btn :undo c.changed::invisible"}} {{action "undo" c}} title="{{i18n 'admin.customize.colors.undo_title'}}">{{i18n 'undo'}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n search.no_results}}</p>
|
||||
<p>{{i18n 'search.no_results'}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="about">{{i18n admin.customize.colors.about}}</p>
|
||||
<p class="about">{{i18n 'admin.customize.colors.about'}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@ -1,59 +1,80 @@
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n admin.customize.css_html.long_title}}</h3>
|
||||
<h3>{{i18n 'admin.customize.css_html.long_title'}}</h3>
|
||||
<ul>
|
||||
{{#each model}}
|
||||
<li><a {{action "selectStyle" this}} {{bind-attr class="this.selected:active"}}>{{this.description}}</a></li>
|
||||
{{#each style in model}}
|
||||
<li><a {{action "selectStyle" style}} {{bind-attr class="style.selected:active"}}>{{style.description}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<button {{action "newCustomization"}} class='btn'>
|
||||
{{fa-icon "plus"}}{{i18n admin.customize.new}}
|
||||
{{fa-icon "plus"}}{{i18n 'admin.customize.new'}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{#if selectedItem}}
|
||||
<div class='current-style'>
|
||||
{{#with selectedItem}}
|
||||
{{text-field class="style-name" value=name}}
|
||||
<div {{bind-attr class=":current-style view.maximized:maximized"}}>
|
||||
<div class='wrapper'>
|
||||
{{text-field class="style-name" value=selectedItem.name}}
|
||||
|
||||
<div class='admin-controls'>
|
||||
<ul class="nav nav-pills">
|
||||
<li><a {{bind-attr class="view.stylesheetActive:active"}} {{action "selectStylesheet" target="view"}}>{{i18n admin.customize.css}}</a></li>
|
||||
<li><a {{bind-attr class="view.headerActive:active"}} {{action "selectHeader" target="view"}}>{{i18n admin.customize.header}}</a></li>
|
||||
<li><a {{bind-attr class="view.footerActive:active"}} {{action "selectFooter" target="view"}}>{{i18n admin.customize.footer}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileStylesheetActive:active"}} {{action "selectMobileStylesheet" target="view"}}>{{fa-icon "mobile"}} {{i18n admin.customize.css}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileHeaderActive:active"}} {{action "selectMobileHeader" target="view"}}>{{fa-icon "mobile"}} {{i18n admin.customize.header}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileFooterActive:active"}} {{action "selectMobileFooter" target="view"}}>{{fa-icon "mobile"}} {{i18n admin.customize.footer}}</a></li>
|
||||
{{#if view.mobile}}
|
||||
<li><a {{bind-attr class="view.mobileStylesheetActive:active"}} {{action "select" "mobile_stylesheet" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.css'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileHeaderActive:active"}} {{action "select" "mobile_header" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.header'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileTopActive:active"}} {{action "select" "mobile_top" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.top'}}</a></li>
|
||||
<li><a {{bind-attr class="view.mobileFooterActive:active"}} {{action "select" "mobile_footer" target="view"}}>{{fa-icon "mobile"}} {{i18n 'admin.customize.footer'}}</a></li>
|
||||
{{else}}
|
||||
<li><a {{bind-attr class="view.stylesheetActive:active"}} {{action "select" "stylesheet" target="view"}}>{{i18n 'admin.customize.css'}}</a></li>
|
||||
<li><a {{bind-attr class="view.headerActive:active"}} {{action "select" "header" target="view"}}>{{i18n 'admin.customize.header'}}</a></li>
|
||||
<li><a {{bind-attr class="view.topActive:active"}} {{action "select" "top" target="view"}}>{{i18n 'admin.customize.top'}}</a></li>
|
||||
<li><a {{bind-attr class="view.footerActive:active"}} {{action "select" "footer" target="view"}}>{{i18n 'admin.customize.footer'}}</a></li>
|
||||
<li><a {{bind-attr class="view.headTagActive:active"}} {{action "select" "head_tag" target="view"}} title="{{i18n 'admin.customize.head_tag.title'}}">{{fa-icon "file-text-o"}} {{i18n 'admin.customize.head_tag.text'}}</a></li>
|
||||
<li><a {{bind-attr class="view.bodyTagActive:active"}} {{action "select" "body_tag" target="view"}} title="{{i18n 'admin.customize.body_tag.title'}}">{{fa-icon "file-text-o"}} {{i18n 'admin.customize.body_tag.text'}}</a></li>
|
||||
{{/if}}
|
||||
<li class='toggle-mobile'>
|
||||
<a {{bind-attr class="view.mobile:active"}} {{action "toggleMobile" target="view"}}>{{fa-icon "mobile"}}</a>
|
||||
</li>
|
||||
<li class='toggle-maximize'><a {{action "toggleMaximize" target="view"}}>
|
||||
{{#if view.maximized}}
|
||||
{{fa-icon "compress"}}
|
||||
{{else}}
|
||||
{{fa-icon "expand"}}
|
||||
{{/if}}
|
||||
</a>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="admin-container">
|
||||
{{#if view.stylesheetActive}}{{aceEditor content=stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.headerActive}}{{aceEditor content=header mode="html"}}{{/if}}
|
||||
{{#if view.footerActive}}{{aceEditor content=footer mode="html"}}{{/if}}
|
||||
{{#if view.mobileStylesheetActive}}{{aceEditor content=mobile_stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.mobileHeaderActive}}{{aceEditor content=mobile_header mode="html"}}{{/if}}
|
||||
{{#if view.mobileFooterActive}}{{aceEditor content=mobile_footer mode="html"}}{{/if}}
|
||||
{{#if view.stylesheetActive}}{{aceEditor content=selectedItem.stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.headerActive}}{{aceEditor content=selectedItem.header mode="html"}}{{/if}}
|
||||
{{#if view.topActive}}{{aceEditor content=selectedItem.top mode="html"}}{{/if}}
|
||||
{{#if view.footerActive}}{{aceEditor content=selectedItem.footer mode="html"}}{{/if}}
|
||||
{{#if view.headTagActive}}{{aceEditor content=selectedItem.head_tag mode="html"}}{{/if}}
|
||||
{{#if view.bodyTagActive}}{{aceEditor content=selectedItem.body_tag mode="html"}}{{/if}}
|
||||
{{#if view.mobileStylesheetActive}}{{aceEditor content=selectedItem.mobile_stylesheet mode="scss"}}{{/if}}
|
||||
{{#if view.mobileHeaderActive}}{{aceEditor content=selectedItem.mobile_header mode="html"}}{{/if}}
|
||||
{{#if view.mobileTopActive}}{{aceEditor content=selectedItem.mobile_top mode="html"}}{{/if}}
|
||||
{{#if view.mobileFooterActive}}{{aceEditor content=selectedItem.mobile_footer mode="html"}}{{/if}}
|
||||
</div>
|
||||
{{/with}}
|
||||
<br>
|
||||
<div class='status-actions'>
|
||||
<span>{{i18n admin.customize.override_default}} {{view Ember.Checkbox checkedBinding="selectedItem.override_default_style"}}</span>
|
||||
<span>{{i18n admin.customize.enabled}} {{view Ember.Checkbox checkedBinding="selectedItem.enabled"}}</span>
|
||||
{{#unless selectedItem.changed}}
|
||||
<a class='preview-link' {{bind-attr href="selectedItem.previewUrl"}} target='_blank' title="{{i18n admin.customize.explain_preview}}">{{i18n admin.customize.preview}}</a>
|
||||
|
|
||||
<a href="/?preview-style=" target='_blank' title="{{i18n admin.customize.explain_undo_preview}}">{{i18n admin.customize.undo_preview}}</a>
|
||||
|
|
||||
<a href="/?preview-style=default" target='_blank' title="{{i18n admin.customize.explain_rescue_preview}}">{{i18n admin.customize.rescue_preview}}</a><br>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<div class='admin-footer'>
|
||||
<div class='status-actions'>
|
||||
<span>{{i18n 'admin.customize.enabled'}} {{input type="checkbox" checked=selectedItem.enabled}}</span>
|
||||
{{#unless selectedItem.changed}}
|
||||
<a class='preview-link' {{bind-attr href="selectedItem.previewUrl"}} target='_blank' title="{{i18n 'admin.customize.explain_preview'}}">{{i18n 'admin.customize.preview'}}</a>
|
||||
|
|
||||
<a href="/?preview-style=" target='_blank' title="{{i18n 'admin.customize.explain_undo_preview'}}">{{i18n 'admin.customize.undo_preview'}}</a>
|
||||
|
|
||||
<a href="/?preview-style=default" target='_blank' title="{{i18n 'admin.customize.explain_rescue_preview'}}">{{i18n 'admin.customize.rescue_preview'}}</a><br>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
|
||||
<span class='saving'>{{selectedItem.savingStatus}}</span>
|
||||
<a {{action "destroy"}} class='delete-link'>{{i18n admin.customize.delete}}</a>
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled="selectedItem.disableSave"}} class='btn'>{{i18n 'admin.customize.save'}}</button>
|
||||
<span class='saving'>{{selectedItem.savingStatus}}</span>
|
||||
<a {{action "destroy"}} class='delete-link'>{{i18n 'admin.customize.delete'}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="about">{{i18n admin.customize.about}}</p>
|
||||
<p class="about">{{i18n 'admin.customize.about'}}</p>
|
||||
{{/if}}
|
||||
|
||||
@ -24,16 +24,16 @@
|
||||
<div class="dashboard-stats totals">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="title"><i class='fa fa-shield'></i> {{i18n admin.dashboard.admins}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.admins'}}{{admins}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-ban'></i> {{i18n admin.dashboard.suspended}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.suspended'}}{{suspended}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-shield'></i> {{i18n 'admin.dashboard.admins'}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.show' 'admins'}}{{admins}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-ban'></i> {{i18n 'admin.dashboard.suspended'}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.show' 'suspended'}}{{suspended}}{{/link-to}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title"><i class='fa fa-shield'></i> {{i18n admin.dashboard.moderators}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.moderators'}}{{moderators}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-ban'></i> {{i18n admin.dashboard.blocked}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.blocked'}}{{blocked}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-shield'></i> {{i18n 'admin.dashboard.moderators'}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.show' 'moderators'}}{{moderators}}{{/link-to}}</td>
|
||||
<td class="title"><i class='fa fa-ban'></i> {{i18n 'admin.dashboard.blocked'}}</td>
|
||||
<td class="value">{{#link-to 'adminUsersList.show' 'blocked'}}{{blocked}}{{/link-to}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@ -43,21 +43,21 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>{{i18n admin.dashboard.reports.today}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.yesterday}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.last_7_days}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.last_30_days}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.all}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.today'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_30_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.all'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{ render 'admin/templates/reports/per_day_counts_report' visits tagName="tbody"}}
|
||||
{{ render 'admin_report_counts' signups }}
|
||||
{{ render 'admin_report_counts' topics }}
|
||||
{{ render 'admin_report_counts' posts }}
|
||||
{{ render 'admin_report_counts' likes }}
|
||||
{{ render 'admin_report_counts' flags }}
|
||||
{{ render 'admin_report_counts' bookmarks }}
|
||||
{{ render 'admin_report_counts' starred }}
|
||||
{{ render 'admin_report_counts' emails }}
|
||||
{{/unless}}
|
||||
</table>
|
||||
@ -67,12 +67,34 @@
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title" title="{{i18n admin.dashboard.private_messages_title}}"><i class="fa fa-envelope"></i> {{i18n admin.dashboard.private_messages_short}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.today}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.yesterday}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.last_7_days}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.last_30_days}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.all}}</th>
|
||||
<th class="title" title="{{i18n 'admin.dashboard.page_views'}}">{{i18n 'admin.dashboard.page_views_short'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.today'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_30_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.all'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{ render 'admin_report_counts' page_view_anon_reqs }}
|
||||
{{ render 'admin_report_counts' page_view_logged_in_reqs }}
|
||||
{{ render 'admin_report_counts' page_view_crawler_reqs }}
|
||||
{{ render 'admin_report_counts' page_view_total_reqs }}
|
||||
{{/unless}}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="dashboard-stats">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title" title="{{i18n 'admin.dashboard.private_messages_title'}}"><i class="fa fa-envelope"></i> {{i18n 'admin.dashboard.private_messages_short'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.today'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_30_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.all'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
@ -90,17 +112,54 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>{{i18n admin.dashboard.reports.today}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.yesterday}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.7_days_ago}}</th>
|
||||
<th>{{i18n admin.dashboard.reports.30_days_ago}}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{ render 'admin/templates/reports/per_day_counts_report' visits tagName="tbody"}}
|
||||
{{/unless}}
|
||||
<tbody>
|
||||
{{#unless loading}}
|
||||
<tr>
|
||||
<td>{{i18n 'admin.dashboard.uploads'}}</td>
|
||||
<td>{{disk_space.uploads_used}} ({{i18n 'admin.dashboard.space_free' size=disk_space.uploads_free}})</td>
|
||||
<td><a href="/admin/backups">{{i18n 'admin.dashboard.backups'}}</a></td>
|
||||
<td>{{disk_space.backups_used}} ({{i18n 'admin.dashboard.space_free' size=disk_space.backups_free}})</td>
|
||||
</tr>
|
||||
{{/unless}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{#unless loading}}
|
||||
{{#if showTrafficReport}}
|
||||
<div class="dashboard-stats">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title" title="{{i18n 'admin.dashboard.traffic'}}">{{i18n 'admin.dashboard.traffic_short'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.today'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.yesterday'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_7_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.last_30_days'}}</th>
|
||||
<th>{{i18n 'admin.dashboard.reports.all'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{ render 'admin_report_counts' http_2xx_reqs }}
|
||||
{{ render 'admin_report_counts' http_3xx_reqs}}
|
||||
{{ render 'admin_report_counts' http_4xx_reqs}}
|
||||
{{ render 'admin_report_counts' http_5xx_reqs}}
|
||||
{{ render 'admin_report_counts' http_background_reqs }}
|
||||
{{ render 'admin_report_counts' http_total_reqs }}
|
||||
{{/unless}}
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="dashboard-stats">
|
||||
<a href {{action showTrafficReport}}>{{i18n 'admin.dashboard.show_traffic_report'}}</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
<div class="dashboard-right">
|
||||
@ -110,7 +169,7 @@
|
||||
<div class="look-here"><i class="fa fa-exclamation-triangle"></i></div>
|
||||
<div class="problem-messages">
|
||||
<p {{bind-attr class="loadingProblems:invisible"}}>
|
||||
{{i18n admin.dashboard.problems_found}}
|
||||
{{i18n 'admin.dashboard.problems_found'}}
|
||||
<ul {{bind-attr class="loadingProblems:invisible"}}>
|
||||
{{#each problem in problems}}
|
||||
<li>{{{problem}}}</li>
|
||||
@ -118,8 +177,8 @@
|
||||
</ul>
|
||||
</p>
|
||||
<p class="actions">
|
||||
<small>{{i18n admin.dashboard.last_checked}}: {{problemsTimestamp}}</small>
|
||||
<button {{action "refreshProblems"}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
|
||||
<small>{{i18n 'admin.dashboard.last_checked'}}: {{problemsTimestamp}}</small>
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
@ -130,8 +189,8 @@
|
||||
<div class="look-here"> </div>
|
||||
<div class="problem-messages">
|
||||
<p>
|
||||
{{i18n admin.dashboard.no_problems}}
|
||||
<button {{action "refreshProblems"}} class="btn btn-small"><i class="fa fa-refresh"></i>{{i18n admin.dashboard.refresh_problems}}</button>
|
||||
{{i18n 'admin.dashboard.no_problems'}}
|
||||
{{d-button action="refreshProblems" class="btn-small" icon="refresh" label="admin.dashboard.refresh_problems"}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
@ -143,7 +202,7 @@
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title">{{top_referred_topics.title}} ({{i18n admin.dashboard.reports.last_30_days}})</th>
|
||||
<th class="title">{{top_referred_topics.title}} ({{i18n 'admin.dashboard.reports.last_30_days'}})</th>
|
||||
<th>{{top_referred_topics.ytitles.num_clicks}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -170,18 +229,18 @@
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title">{{top_traffic_sources.title}} ({{i18n admin.dashboard.reports.last_30_days}})</th>
|
||||
<th class="title">{{top_traffic_sources.title}} ({{i18n 'admin.dashboard.reports.last_30_days'}})</th>
|
||||
<th>{{top_traffic_sources.ytitles.num_clicks}}</th>
|
||||
<th>{{top_traffic_sources.ytitles.num_topics}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{#each top_traffic_sources.data}}
|
||||
{{#each s in top_traffic_sources.data}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">{{domain}}</td>
|
||||
<td class="value">{{num_clicks}}</td>
|
||||
<td class="value">{{num_topics}}</td>
|
||||
<td class="title">{{s.domain}}</td>
|
||||
<td class="value">{{s.num_clicks}}</td>
|
||||
<td class="value">{{s.num_topics}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{{/each}}
|
||||
@ -193,18 +252,18 @@
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title">{{top_referrers.title}} ({{i18n admin.dashboard.reports.last_30_days}})</th>
|
||||
<th class="title">{{top_referrers.title}} ({{i18n 'admin.dashboard.reports.last_30_days'}})</th>
|
||||
<th>{{top_referrers.ytitles.num_clicks}}</th>
|
||||
<th>{{top_referrers.ytitles.num_topics}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#unless loading}}
|
||||
{{#each top_referrers.data}}
|
||||
{{#each r in top_referrers.data}}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">{{#link-to 'adminUser' this}}{{unbound username}}{{/link-to}}</td>
|
||||
<td class="value">{{num_clicks}}</td>
|
||||
<td class="value">{{num_topics}}</td>
|
||||
<td class="title">{{#link-to 'adminUser' r}}{{unbound r.username}}{{/link-to}}</td>
|
||||
<td class="value">{{r.num_clicks}}</td>
|
||||
<td class="value">{{r.num_topics}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{{/each}}
|
||||
@ -215,7 +274,7 @@
|
||||
<div class='clearfix'></div>
|
||||
|
||||
<div class="dashboard-stats pull-right">
|
||||
<div class="pull-right">{{i18n admin.dashboard.last_updated}} {{updatedTimestamp}}</div>
|
||||
<div class="pull-right">{{i18n 'admin.dashboard.last_updated'}} {{updatedTimestamp}}</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
<div class='clearfix'></div>
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminEmail.index'}}{{i18n admin.email.settings}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminEmail.all'}}{{i18n admin.email.all}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminEmail.sent'}}{{i18n admin.email.sent}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminEmail.skipped'}}{{i18n admin.email.skipped}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminEmail.previewDigest'}}{{i18n admin.email.preview_digest}}{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminEmail.index' label='admin.email.settings'}}
|
||||
{{admin-nav-item route='adminEmail.all' label='admin.email.all'}}
|
||||
{{admin-nav-item route='adminEmail.sent' label='admin.email.sent'}}
|
||||
{{admin-nav-item route='adminEmail.skipped' label='admin.email.skipped'}}
|
||||
{{admin-nav-item route='adminEmail.previewDigest' label='admin.email.preview_digest'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
<table class='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n admin.email.time}}</th>
|
||||
<th>{{i18n admin.email.user}}</th>
|
||||
<th>{{i18n admin.email.to_address}}</th>
|
||||
<th>{{i18n admin.email.email_type}}</th>
|
||||
<th>{{i18n admin.email.skipped_reason}}</th>
|
||||
<th>{{i18n 'admin.email.time'}}</th>
|
||||
<th>{{i18n 'admin.email.user'}}</th>
|
||||
<th>{{i18n 'admin.email.to_address'}}</th>
|
||||
<th>{{i18n 'admin.email.email_type'}}</th>
|
||||
<th>{{i18n 'admin.email.skipped_reason'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr class="filters">
|
||||
<td>{{i18n admin.email.logs.filters.title}}</td>
|
||||
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
|
||||
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each model}}
|
||||
{{#each l in model}}
|
||||
<tr>
|
||||
<td>{{format-date created_at}}</td>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
{{#if user}}
|
||||
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' user}}{{user.username}}{{/link-to}}
|
||||
{{#if l.user}}
|
||||
{{#link-to 'adminUser' l.user}}{{avatar l.user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' l.user}}{{l.user.username}}{{/link-to}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
</td>
|
||||
<td><a href='mailto:{{unbound to_address}}'>{{to_address}}</a></td>
|
||||
<td>{{email_type}}</td>
|
||||
<td>{{skipped_reason}}</td>
|
||||
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
|
||||
<td>{{l.email_type}}</td>
|
||||
<td>{{l.skipped_reason}}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="5">{{i18n admin.email.logs.none}}</td></tr>
|
||||
<tr><td colspan="5">{{i18n 'admin.email.logs.none'}}</td></tr>
|
||||
{{/each}}
|
||||
|
||||
</table>
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{i18n admin.email.delivery_method}}</th>
|
||||
<td>{{model.delivery_method}}</td>
|
||||
<th>{{i18n 'admin.email.delivery_method'}}</th>
|
||||
<td>{{delivery_method}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each model.settings}}
|
||||
{{#each s in model.settings}}
|
||||
<tr>
|
||||
<th style='width: 25%'>{{name}}</th>
|
||||
<td>{{value}}</td>
|
||||
<th style='width: 25%'>{{s.name}}</th>
|
||||
<td>{{s.value}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
|
||||
<div class='admin-controls'>
|
||||
{{#if sendingEmail}}
|
||||
<div class='span15 controls'>{{i18n admin.email.sending_test}}</div>
|
||||
<div class='span15 controls'>{{i18n 'admin.email.sending_test'}}</div>
|
||||
{{else}}
|
||||
<div class='controls'>
|
||||
{{text-field value=testEmailAddress placeholderKey="admin.email.test_email_address"}}
|
||||
</div>
|
||||
<div class='span10 controls'>
|
||||
<button class='btn btn-primary' {{action "sendTestEmail"}} {{bind-attr disabled="sendTestEmailDisabled"}}>{{i18n admin.email.send_test}}</button>
|
||||
{{#if sentTestEmail}}<span class='result-message'>{{i18n admin.email.sent_test}}</span>{{/if}}
|
||||
<button class='btn btn-primary' {{action "sendTestEmail"}} {{bind-attr disabled="sendTestEmailDisabled"}}>{{i18n 'admin.email.send_test'}}</button>
|
||||
{{#if sentTestEmail}}<span class='result-message'>{{i18n 'admin.email.sent_test'}}</span>{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
<p>{{i18n admin.email.preview_digest_desc}}</p>
|
||||
<p>{{i18n 'admin.email.preview_digest_desc'}}</p>
|
||||
|
||||
<div class='admin-controls'>
|
||||
<div class='span7 controls'>
|
||||
<label for='last-seen'>{{i18n admin.email.last_seen_user}}</label>
|
||||
<label for='last-seen'>{{i18n 'admin.email.last_seen_user'}}</label>
|
||||
{{input type="date" value=lastSeen id="last-seen"}}
|
||||
</div>
|
||||
<div>
|
||||
<button class='btn' {{action "refresh"}}>{{i18n admin.email.refresh}}</button>
|
||||
<button class='btn' {{action "refresh"}}>{{i18n 'admin.email.refresh'}}</button>
|
||||
</div>
|
||||
<div class="span7 toggle">
|
||||
<label>{{i18n admin.email.format}}</label>
|
||||
<label>{{i18n 'admin.email.format'}}</label>
|
||||
{{#if showHtml}}
|
||||
<span>{{i18n admin.email.html}}</span> | <a href='#' {{action "toggleShowHtml"}}>{{i18n admin.email.text}}</a>
|
||||
<span>{{i18n 'admin.email.html'}}</span> | <a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.text'}}</a>
|
||||
{{else}}
|
||||
<a href='#' {{action "toggleShowHtml"}}>{{i18n admin.email.html}}</a> | <span>{{i18n admin.email.text}}</span>
|
||||
<a href='#' {{action "toggleShowHtml"}}>{{i18n 'admin.email.html'}}</a> | <span>{{i18n 'admin.email.text'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
<table class='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n admin.email.sent_at}}</th>
|
||||
<th>{{i18n admin.email.user}}</th>
|
||||
<th>{{i18n admin.email.to_address}}</th>
|
||||
<th>{{i18n admin.email.email_type}}</th>
|
||||
<th>{{i18n admin.email.reply_key}}</th>
|
||||
<th>{{i18n 'admin.email.sent_at'}}</th>
|
||||
<th>{{i18n 'admin.email.user'}}</th>
|
||||
<th>{{i18n 'admin.email.to_address'}}</th>
|
||||
<th>{{i18n 'admin.email.email_type'}}</th>
|
||||
<th>{{i18n 'admin.email.reply_key'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr class="filters">
|
||||
<td>{{i18n admin.email.logs.filters.title}}</td>
|
||||
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
|
||||
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.reply_key placeholderKey="admin.email.logs.filters.reply_key_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each model}}
|
||||
{{#each l in model}}
|
||||
<tr>
|
||||
<td>{{format-date created_at}}</td>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
{{#if user}}
|
||||
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' user}}{{user.username}}{{/link-to}}
|
||||
{{#if l.user}}
|
||||
{{#link-to 'adminUser' l.user}}{{avatar l.user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' l.user}}{{l.user.username}}{{/link-to}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
</td>
|
||||
<td><a href='mailto:{{unbound to_address}}'>{{to_address}}</a></td>
|
||||
<td>{{email_type}}</td>
|
||||
<td>{{reply_key}}</td>
|
||||
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
|
||||
<td>{{l.email_type}}</td>
|
||||
<td>{{l.reply_key}}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="5">{{i18n admin.email.logs.none}}</td></tr>
|
||||
<tr><td colspan="5">{{i18n 'admin.email.logs.none'}}</td></tr>
|
||||
{{/each}}
|
||||
|
||||
</table>
|
||||
|
||||
@ -1,39 +1,39 @@
|
||||
<table class='table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n admin.email.time}}</th>
|
||||
<th>{{i18n admin.email.user}}</th>
|
||||
<th>{{i18n admin.email.to_address}}</th>
|
||||
<th>{{i18n admin.email.email_type}}</th>
|
||||
<th>{{i18n admin.email.skipped_reason}}</th>
|
||||
<th>{{i18n 'admin.email.time'}}</th>
|
||||
<th>{{i18n 'admin.email.user'}}</th>
|
||||
<th>{{i18n 'admin.email.to_address'}}</th>
|
||||
<th>{{i18n 'admin.email.email_type'}}</th>
|
||||
<th>{{i18n 'admin.email.skipped_reason'}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr class="filters">
|
||||
<td>{{i18n admin.email.logs.filters.title}}</td>
|
||||
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
|
||||
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
||||
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
|
||||
</tr>
|
||||
|
||||
{{#each model}}
|
||||
{{#each l in model}}
|
||||
<tr>
|
||||
<td>{{format-date created_at}}</td>
|
||||
<td>{{format-date l.created_at}}</td>
|
||||
<td>
|
||||
{{#if user}}
|
||||
{{#link-to 'adminUser' user}}{{avatar user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' user}}{{user.username}}{{/link-to}}
|
||||
{{#if l.user}}
|
||||
{{#link-to 'adminUser' l.user}}{{avatar l.user imageSize="tiny"}}{{/link-to}}
|
||||
{{#link-to 'adminUser' l.user}}{{l.user.username}}{{/link-to}}
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
</td>
|
||||
<td><a href='mailto:{{unbound to_address}}'>{{to_address}}</a></td>
|
||||
<td>{{email_type}}</td>
|
||||
<td>{{skipped_reason}}</td>
|
||||
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
|
||||
<td>{{l.email_type}}</td>
|
||||
<td>{{l.skipped_reason}}</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr><td colspan="5">{{i18n admin.email.logs.none}}</td></tr>
|
||||
<tr><td colspan="5">{{i18n 'admin.email.logs.none'}}</td></tr>
|
||||
{{/each}}
|
||||
|
||||
</table>
|
||||
|
||||
30
app/assets/javascripts/admin/templates/emojis.hbs
Normal file
30
app/assets/javascripts/admin/templates/emojis.hbs
Normal file
@ -0,0 +1,30 @@
|
||||
<div class='emoji'>
|
||||
<h2>{{i18n 'admin.emoji.title'}}</h2>
|
||||
|
||||
<p class="desc">{{i18n 'admin.emoji.help'}}</p>
|
||||
|
||||
<p>{{emoji-uploader done="emojiUploaded"}}</p>
|
||||
|
||||
{{#if controller}}
|
||||
<div class="span8">
|
||||
<table id="custom_emoji">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "admin.emoji.image"}}</th>
|
||||
<th>{{i18n "admin.emoji.name"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each e in controller}}
|
||||
<tr>
|
||||
<th><img class="emoji" src="{{unbound e.url}}" title="{{unbound e.name}}"></th>
|
||||
<th>:{{e.name}}:</th>
|
||||
<th><button {{action "destroy" e}} class='btn btn-danger no-text pull-right'>{{fa-icon 'trash-o'}} </button></th>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@ -4,8 +4,8 @@
|
||||
<tr>
|
||||
<th class='user'></th>
|
||||
<th class='excerpt'></th>
|
||||
<th class='flaggers'>{{i18n admin.flags.flagged_by}}</th>
|
||||
<th class='flaggers'>{{#if adminOldFlagsView}}{{i18n admin.flags.resolved_by}}{{/if}}</th>
|
||||
<th class='flaggers'>{{i18n 'admin.flags.flagged_by'}}</th>
|
||||
<th class='flaggers'>{{#if adminOldFlagsView}}{{i18n 'admin.flags.resolved_by'}}{{/if}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -16,12 +16,12 @@
|
||||
{{#if flaggedPost.postAuthorFlagged}}
|
||||
{{#if flaggedPost.user}}
|
||||
{{#link-to 'adminUser' flaggedPost.user}}{{avatar flaggedPost.user imageSize="small"}}{{/link-to}}
|
||||
{{#if flaggedPost.wasEdited}}<i class="fa fa-pencil" title="{{i18n admin.flags.was_edited}}"></i>{{/if}}
|
||||
{{#if flaggedPost.wasEdited}}<i class="fa fa-pencil" title="{{i18n 'admin.flags.was_edited'}}"></i>{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if adminActiveFlagsView}}
|
||||
{{#if flaggedPost.previous_flags_count}}
|
||||
<span title="{{i18n admin.flags.previous_flags_count count=flaggedPost.previous_flags_count}}" class="badge-notification flagged-posts">{{flaggedPost.previous_flags_count}}</span>
|
||||
<span title="{{i18n 'admin.flags.previous_flags_count' count=flaggedPost.previous_flags_count}}" class="badge-notification flagged-posts">{{flaggedPost.previous_flags_count}}</span>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</td>
|
||||
@ -29,7 +29,7 @@
|
||||
<td class='excerpt'>
|
||||
<h3>
|
||||
{{#if flaggedPost.topic.isPrivateMessage}}
|
||||
<span class="private-message-glyph">{{fa-icon envelope}}</span>
|
||||
<span class="private-message-glyph">{{fa-icon "envelope"}}</span>
|
||||
{{/if}}
|
||||
{{topic-status topic=flaggedPost.topic}}
|
||||
<a href='{{unbound flaggedPost.url}}'>{{flaggedPost.topic.title}}</a>
|
||||
@ -42,20 +42,20 @@
|
||||
<td class='flaggers'>
|
||||
<table>
|
||||
<tbody>
|
||||
{{#each flaggedPost.flaggers}}
|
||||
{{#each flagger in flaggedPost.flaggers}}
|
||||
<tr>
|
||||
<td class='avatar'>
|
||||
{{#link-to 'adminUser' user}}
|
||||
{{avatar user imageSize="small"}}
|
||||
{{#link-to 'adminUser' flagger.user}}
|
||||
{{avatar flagger.user imageSize="small"}}
|
||||
{{/link-to}}
|
||||
</td>
|
||||
<td>
|
||||
{{#link-to 'adminUser' user}}
|
||||
{{user.username}}
|
||||
{{#link-to 'adminUser' flagger.user}}
|
||||
{{flagger.user.username}}
|
||||
{{/link-to}}
|
||||
{{format-age flaggedAt}}
|
||||
{{format-age flagger.flaggedAt}}
|
||||
<br />
|
||||
{{flagType}}
|
||||
{{flagger.flagType}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
@ -67,18 +67,18 @@
|
||||
{{#if adminOldFlagsView}}
|
||||
<table>
|
||||
<tbody>
|
||||
{{#each flaggedPost.flaggers}}
|
||||
{{#each flagger in flaggedPost.flaggers}}
|
||||
<tr>
|
||||
<td class='avatar'>
|
||||
{{#link-to 'adminUser' disposedBy}}
|
||||
{{avatar disposedBy imageSize="small"}}
|
||||
{{#link-to 'adminUser' flagger.disposedBy}}
|
||||
{{avatar flagger.disposedBy imageSize="small"}}
|
||||
{{/link-to}}
|
||||
</td>
|
||||
<td>
|
||||
{{format-age disposedAt}}
|
||||
{{{dispositionIcon}}}
|
||||
{{#if tookAction}}
|
||||
<i class='fa fa-gavel' title='{{i18n admin.flags.took_action}}'></i>
|
||||
{{format-age flagger.disposedAt}}
|
||||
{{{flagger.dispositionIcon}}}
|
||||
{{#if flagger.tookAction}}
|
||||
<i class='fa fa-gavel' title='{{i18n 'admin.flags.took_action'}}'></i>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -95,31 +95,31 @@
|
||||
<td></td>
|
||||
<td colspan="3">
|
||||
<div>
|
||||
{{{i18n admin.flags.topic_flagged}}} <a href='{{unbound flaggedPost.url}}' class="btn">{{i18n admin.flags.visit_topic}}</a>
|
||||
{{{i18n 'admin.flags.topic_flagged'}}} <a href='{{unbound flaggedPost.url}}' class="btn">{{i18n 'admin.flags.visit_topic'}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
|
||||
{{#each flaggedPost.conversations}}
|
||||
{{#each c in flaggedPost.conversations}}
|
||||
<tr class='message'>
|
||||
<td></td>
|
||||
<td colspan="3">
|
||||
<div>
|
||||
{{#if response}}
|
||||
{{#if c.response}}
|
||||
<p>
|
||||
{{#link-to 'adminUser' response.user}}{{avatar response.user imageSize="small"}}{{/link-to}} {{{response.excerpt}}}
|
||||
{{#link-to 'adminUser' c.response.user}}{{avatar c.response.user imageSize="small"}}{{/link-to}} {{{c.response.excerpt}}}
|
||||
</p>
|
||||
{{#if reply}}
|
||||
{{#if c.reply}}
|
||||
<p>
|
||||
{{#link-to 'adminUser' reply.user}}{{avatar reply.user imageSize="small"}}{{/link-to}} {{{reply.excerpt}}}
|
||||
{{#if hasMore}}
|
||||
<a href="{{unbound permalink}}">{{i18n admin.flags.more}}</a>
|
||||
{{#link-to 'adminUser' c.reply.user}}{{avatar c.reply.user imageSize="small"}}{{/link-to}} {{{c.reply.excerpt}}}
|
||||
{{#if c.hasMore}}
|
||||
<a href="{{unbound c.permalink}}">{{i18n 'admin.flags.more'}}</a>
|
||||
{{/if}}
|
||||
</p>
|
||||
{{/if}}
|
||||
<a href="{{unbound permalink}}">
|
||||
<button class='btn btn-reply'><i class="fa fa-reply"></i> {{i18n admin.flags.reply_message}}</button>
|
||||
<a href="{{unbound c.permalink}}">
|
||||
<button class='btn btn-reply'><i class="fa fa-reply"></i> {{i18n 'admin.flags.reply_message'}}</button>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
@ -130,14 +130,14 @@
|
||||
<tr>
|
||||
<td colspan="4" class="action">
|
||||
{{#if adminActiveFlagsView}}
|
||||
<button title='{{i18n admin.flags.agree_title}}' class='btn' {{action "showAgreeFlagModal" flaggedPost}}><i class="fa fa-thumbs-o-up"></i>{{i18n admin.flags.agree}}…</button>
|
||||
<button title='{{i18n 'admin.flags.agree_title'}}' class='btn' {{action "showAgreeFlagModal" flaggedPost}}><i class="fa fa-thumbs-o-up"></i>{{i18n 'admin.flags.agree'}}…</button>
|
||||
{{#if flaggedPost.postHidden}}
|
||||
<button title='{{i18n admin.flags.disagree_flag_unhide_post_title}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag_unhide_post}}</button>
|
||||
<button title='{{i18n 'admin.flags.disagree_flag_unhide_post_title'}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n 'admin.flags.disagree_flag_unhide_post'}}</button>
|
||||
{{else}}
|
||||
<button title='{{i18n admin.flags.disagree_flag_title}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n admin.flags.disagree_flag}}</button>
|
||||
<button title='{{i18n 'admin.flags.disagree_flag_title'}}' class='btn' {{action "disagreeFlags" flaggedPost}}><i class="fa fa-thumbs-o-down"></i>{{i18n 'admin.flags.disagree_flag'}}</button>
|
||||
{{/if}}
|
||||
<button title='{{i18n admin.flags.defer_flag_title}}' class='btn' {{action "deferFlags" flaggedPost}}><i class="fa fa-external-link"></i>{{i18n admin.flags.defer_flag}}</button>
|
||||
<button title='{{i18n admin.flags.delete_title}}' class='btn btn-danger' {{action "showDeleteFlagModal" flaggedPost}}><i class="fa fa-trash-o"></i>{{i18n admin.flags.delete}}…</button>
|
||||
<button title='{{i18n 'admin.flags.defer_flag_title'}}' class='btn' {{action "deferFlags" flaggedPost}}><i class="fa fa-external-link"></i>{{i18n 'admin.flags.defer_flag'}}</button>
|
||||
<button title='{{i18n 'admin.flags.delete_title'}}' class='btn btn-danger' {{action "showDeleteFlagModal" flaggedPost}}><i class="fa fa-trash-o"></i>{{i18n 'admin.flags.delete'}}…</button>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
@ -149,5 +149,5 @@
|
||||
|
||||
{{loading-spinner condition=view.loading}}
|
||||
{{else}}
|
||||
<p>{{i18n admin.flags.no_results}}</p>
|
||||
<p>{{i18n 'admin.flags.no_results'}}</p>
|
||||
{{/if}}
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminFlags.list' 'active'}}{{i18n admin.flags.active}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminFlags.list' 'old'}}{{i18n admin.flags.old}}{{/link-to}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminFlags.list' routeParam='active' label='admin.flags.active'}}
|
||||
{{admin-nav-item route='adminFlags.list' routeParam='old' label='admin.flags.old'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
|
||||
@ -1,29 +1,64 @@
|
||||
{{#if automatic}}
|
||||
<h3>{{name}}</h3>
|
||||
{{else}}
|
||||
{{text-field value=name placeholderKey="admin.groups.name_placeholder"}}
|
||||
{{/if}}
|
||||
<form class="form-horizontal">
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n admin.groups.group_members}}</label>
|
||||
<div class="controls">
|
||||
{{user-selector usernames=usernames id="group-users" placeholderKey="admin.groups.selector_placeholder" tabindex="1" disabled=automatic}}
|
||||
<div>
|
||||
{{#if automatic}}
|
||||
<h3>{{name}}</h3>
|
||||
{{else}}
|
||||
<label for="name">{{i18n 'admin.groups.name'}}</label>
|
||||
{{text-field name="name" value=name placeholderKey="admin.groups.name_placeholder"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{input type="checkbox" checked=visible}} {{i18n groups.visible}}
|
||||
|
||||
{{#if id}}
|
||||
<div>
|
||||
<label>{{i18n 'admin.groups.group_members'}} ({{user_count}})</label>
|
||||
<div>
|
||||
<a {{bind-attr class=":previous showingFirst:disabled"}} {{action "previous"}}>{{fa-icon "fast-backward"}}</a>
|
||||
{{currentPage}}/{{totalPages}}
|
||||
<a {{bind-attr class=":next showingLast:disabled"}} {{action "next"}}>{{fa-icon "fast-forward"}}</a>
|
||||
</div>
|
||||
<div class="ac-wrap clearfix">
|
||||
{{each member in members itemView="group-member"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#unless automatic}}
|
||||
<div>
|
||||
<label for="user-selector">{{i18n 'admin.groups.add_members'}}</label>
|
||||
{{user-selector usernames=usernames placeholderKey="admin.groups.selector_placeholder" id="user-selector"}}
|
||||
<button {{action "addMembers"}} class='btn add'>{{fa-icon "plus"}} {{i18n 'admin.groups.add'}}</button>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<label>
|
||||
{{input type="checkbox" checked=visible}}
|
||||
{{i18n 'groups.visible'}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{i18n groups.alias_levels.title}}</label>
|
||||
<div class="controls">
|
||||
{{combo-box valueAttribute="value" value=alias_level content=aliasLevelOptions}}
|
||||
|
||||
<div>
|
||||
<label for="alias">{{i18n 'groups.alias_levels.title'}}</label>
|
||||
{{combo-box name="alias" valueAttribute="value" value=alias_level content=aliasLevelOptions}}
|
||||
</div>
|
||||
</div>
|
||||
<div class='controls'>
|
||||
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn'>{{i18n admin.customize.save}}</button>
|
||||
|
||||
{{#unless automatic}}
|
||||
<button {{action "destroy"}} class='btn btn-danger'><i class="fa fa-trash-o"></i>{{i18n admin.customize.delete}}</button>
|
||||
<div>
|
||||
<label for="automatic_membership">{{i18n 'admin.groups.automatic_membership_email_domains'}}</label>
|
||||
{{list-setting name="automatic_membership" settingValue=emailDomains}}
|
||||
<label>
|
||||
{{input type="checkbox" checked=automatic_membership_retroactive}}
|
||||
{{i18n 'admin.groups.automatic_membership_retroactive'}}
|
||||
</label>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
<div class='buttons'>
|
||||
<button {{action "save"}} {{bind-attr disabled="disableSave"}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>
|
||||
{{#unless automatic}}
|
||||
<button {{action "destroy"}} class='btn btn-danger'>{{fa-icon "trash-o"}}{{i18n 'admin.customize.delete'}}</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
1
app/assets/javascripts/admin/templates/group_member.hbs
Normal file
1
app/assets/javascripts/admin/templates/group_member.hbs
Normal file
@ -0,0 +1 @@
|
||||
{{avatar member imageSize="small"}} {{member.username}} {{#unless automatic}}<a class='remove' {{action "removeMember" member}}>{{fa-icon "times"}}</a>{{/unless}}
|
||||
@ -1,20 +1,8 @@
|
||||
<div class='row groups'>
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n admin.groups.edit}}</h3>
|
||||
<ul>
|
||||
{{#each group in arrangedContent}}
|
||||
<li>
|
||||
<a href='#' {{action "showGroup" group}}>{{group.name}} <span class="count">{{group.userCountDisplay}}</span></a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<div class='controls'>
|
||||
<button class='btn' {{bind-attr disabled="refreshingAutoGroups"}} {{action "refreshAutoGroups"}}><i class="fa fa-refresh"></i>{{i18n admin.groups.refresh}}</button>
|
||||
<button class='btn' {{action "newGroup"}}><i class="fa fa-plus"></i>{{i18n admin.groups.new}}</button>
|
||||
</div>
|
||||
</div>
|
||||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminGroupsType' routeParam='custom' label='admin.groups.custom'}}
|
||||
{{admin-nav-item route='adminGroupsType' routeParam='automatic' label='admin.groups.automatic'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class='content-editor'>
|
||||
{{outlet}}
|
||||
</div>
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{{i18n admin.groups.about}}
|
||||
20
app/assets/javascripts/admin/templates/groups_type.hbs
Normal file
20
app/assets/javascripts/admin/templates/groups_type.hbs
Normal file
@ -0,0 +1,20 @@
|
||||
<div class='row groups'>
|
||||
<div class='content-list span6'>
|
||||
<h3>{{i18n 'admin.groups.edit'}}</h3>
|
||||
<ul>
|
||||
{{#each group in controller}}
|
||||
<li>
|
||||
{{#link-to "adminGroup" group.type group.name}}{{group.name}} <span class="count">{{group.userCountDisplay}}</span>{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<div class='controls'>
|
||||
{{d-button action="newGroup" icon="plus" label="admin.groups.new"}}
|
||||
{{d-button action="refreshAutoGroups" icon="refresh" label="admin.groups.refresh" disabled=refreshingAutoGroups}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='content-editor'>
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
@ -1,14 +1,12 @@
|
||||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
<li>{{#link-to 'adminLogs.staffActionLogs'}}{{i18n admin.logs.staff_actions.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminLogs.screenedEmails'}}{{i18n admin.logs.screened_emails.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminLogs.screenedIpAddresses'}}{{i18n admin.logs.screened_ips.title}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'adminLogs.screenedUrls'}}{{i18n admin.logs.screened_urls.title}}{{/link-to}}</li>
|
||||
<li><a href="/logs" data-auto-route="true">{{i18n admin.logs.logster.title}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminLogs.staffActionLogs' label='admin.logs.staff_actions.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedEmails' label='admin.logs.screened_emails.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedIpAddresses' label='admin.logs.screened_ips.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedUrls' label='admin.logs.screened_urls.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{admin-nav-item href='/logs' label='admin.logs.logster.title'}}
|
||||
{{/if}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.css}}</b>:
|
||||
<b>{{i18n 'admin.customize.css'}}</b>:
|
||||
{{#if stylesheet}}
|
||||
({{i18n character_count count=stylesheet.length}})
|
||||
({{i18n 'character_count' count=stylesheet.length}})
|
||||
{{/if}}
|
||||
<br/>
|
||||
{{textarea value=stylesheet class="plain"}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.header}}</b>:
|
||||
<b>{{i18n 'admin.customize.header'}}</b>:
|
||||
{{#if header}}
|
||||
({{i18n character_count count=header.length}})
|
||||
({{i18n 'character_count' count=header.length}})
|
||||
{{/if}}
|
||||
<br/>
|
||||
{{textarea value=header class="plain"}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.enabled}}</b>: {{enabled}}
|
||||
</section>
|
||||
<section class="field">
|
||||
<b>{{i18n admin.customize.override_default}}</b>: {{override_default_style}}
|
||||
<b>{{i18n 'admin.customize.enabled'}}</b>: {{enabled}}
|
||||
</section>
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
<pre>{{details}}</pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n close}}</button>
|
||||
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n 'close'}}</button>
|
||||
</div>
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
<p>{{i18n admin.logs.screened_emails.description}}</p>
|
||||
<p>
|
||||
{{i18n 'admin.logs.screened_emails.description'}}
|
||||
<button class="btn pull-right" {{action "exportScreenedEmailList"}} title="{{i18n 'admin.export_csv.button_title.screened_email'}}">{{fa-icon "download"}}{{i18n 'admin.export_csv.button_text'}}</button>
|
||||
</p>
|
||||
</br>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
|
||||
<div class='table screened-emails'>
|
||||
<div class="heading-container">
|
||||
<div class="col heading first email">{{i18n admin.logs.screened_emails.email}}</div>
|
||||
<div class="col heading action">{{i18n admin.logs.action}}</div>
|
||||
<div class="col heading match_count">{{i18n admin.logs.match_count}}</div>
|
||||
<div class="col heading last_match_at">{{i18n admin.logs.last_match_at}}</div>
|
||||
<div class="col heading created_at">{{i18n admin.logs.created_at}}</div>
|
||||
<div class="col heading ip_address">{{i18n admin.logs.ip_address}}</div>
|
||||
<div class="col heading first email">{{i18n 'admin.logs.screened_emails.email'}}</div>
|
||||
<div class="col heading action">{{i18n 'admin.logs.action'}}</div>
|
||||
<div class="col heading match_count">{{i18n 'admin.logs.match_count'}}</div>
|
||||
<div class="col heading last_match_at">{{i18n 'admin.logs.last_match_at'}}</div>
|
||||
<div class="col heading created_at">{{i18n 'admin.logs.created_at'}}</div>
|
||||
<div class="col heading ip_address">{{i18n 'admin.logs.ip_address'}}</div>
|
||||
<div class="col heading action"></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
@ -19,6 +23,6 @@
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
{{i18n search.no_results}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
|
||||
@ -6,5 +6,5 @@
|
||||
<div class="col last_match_at">{{age-with-tooltip last_match_at}}</div>
|
||||
<div class="col created_at">{{age-with-tooltip created_at}}</div>
|
||||
<div class="col ip_address">{{ip_address}}</div>
|
||||
<div class="col action"><button class="btn" {{action "clearBlock" this}}><i class='fa fa-check'></i> {{i18n admin.logs.screened_emails.actions.allow}}</button></div>
|
||||
<div class="col action"><button class="btn" {{action "clearBlock" this}}><i class='fa fa-check'></i> {{i18n 'admin.logs.screened_emails.actions.allow'}}</button></div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
<p>{{i18n admin.logs.screened_ips.description}}</p>
|
||||
|
||||
<p>{{i18n 'admin.logs.screened_ips.description'}}</p>
|
||||
<div class="pull-right">
|
||||
{{text-field value=filter class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.filter" autocorrect="off" autocapitalize="off"}}
|
||||
<button class="btn" {{action "rollUp"}} title="{{i18n 'admin.logs.screened_ips.roll_up.title'}}">{{i18n 'admin.logs.screened_ips.roll_up.text'}}</button>
|
||||
<button class="btn" {{action "exportScreenedIpList"}} title="{{i18n 'admin.export_csv.button_title.screened_ip'}}">{{fa-icon "download"}}{{i18n 'admin.export_csv.button_text'}}</button>
|
||||
</div>
|
||||
{{screened-ip-address-form action="recordAdded"}}
|
||||
<br/>
|
||||
|
||||
@ -8,11 +12,11 @@
|
||||
|
||||
<div class='table admin-logs-table screened-ip-addresses'>
|
||||
<div class="heading-container">
|
||||
<div class="col heading first ip_address">{{i18n admin.logs.ip_address}}</div>
|
||||
<div class="col heading action">{{i18n admin.logs.action}}</div>
|
||||
<div class="col heading match_count">{{i18n admin.logs.match_count}}</div>
|
||||
<div class="col heading last_match_at">{{i18n admin.logs.last_match_at}}</div>
|
||||
<div class="col heading created_at">{{i18n admin.logs.created_at}}</div>
|
||||
<div class="col heading first ip_address">{{i18n 'admin.logs.ip_address'}}</div>
|
||||
<div class="col heading action">{{i18n 'admin.logs.action'}}</div>
|
||||
<div class="col heading match_count">{{i18n 'admin.logs.match_count'}}</div>
|
||||
<div class="col heading last_match_at">{{i18n 'admin.logs.last_match_at'}}</div>
|
||||
<div class="col heading created_at">{{i18n 'admin.logs.created_at'}}</div>
|
||||
<div class="col heading actions"></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
@ -21,6 +25,6 @@
|
||||
</div>
|
||||
|
||||
{{else}}
|
||||
{{i18n search.no_results}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
|
||||
@ -2,7 +2,13 @@
|
||||
{{#if editing}}
|
||||
{{text-field value=ip_address autofocus="autofocus"}}
|
||||
{{else}}
|
||||
<span {{action "edit" this}}>{{ip_address}}</span>
|
||||
<span {{action "edit" this}}>
|
||||
{{#if isRange}}
|
||||
<strong>{{ip_address}}</strong>
|
||||
{{else}}
|
||||
{{ip_address}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="col action">
|
||||
@ -21,13 +27,13 @@
|
||||
<button class="btn btn-danger" {{action "destroy" this}}><i class="fa fa-trash-o"></i></button>
|
||||
<button class="btn" {{action "edit" this}}><i class="fa fa-pencil"></i></button>
|
||||
{{#if isBlocked}}
|
||||
<button class="btn" {{action "allow" this}}><i {{bind-attr class=":fa doNothingIcon"}}></i> {{i18n admin.logs.screened_ips.actions.do_nothing}}</button>
|
||||
<button class="btn" {{action "allow" this}}><i {{bind-attr class=":fa doNothingIcon"}}></i> {{i18n 'admin.logs.screened_ips.actions.do_nothing'}}</button>
|
||||
{{else}}
|
||||
<button class="btn" {{action "block" this}}><i {{bind-attr class=":fa blockIcon"}}></i> {{i18n admin.logs.screened_ips.actions.block}}</button>
|
||||
<button class="btn" {{action "block" this}}><i {{bind-attr class=":fa blockIcon"}}></i> {{i18n 'admin.logs.screened_ips.actions.block'}}</button>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<button class="btn" {{action "save" this}}>{{i18n admin.logs.save}}</button>
|
||||
<a {{action "cancel" this}}>{{i18n cancel}}</a>
|
||||
<button class="btn" {{action "save" this}}>{{i18n 'admin.logs.save'}}</button>
|
||||
<a {{action "cancel" this}}>{{i18n 'cancel'}}</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@ -1,20 +1,24 @@
|
||||
<p>{{i18n admin.logs.screened_urls.description}}</p>
|
||||
<p>
|
||||
{{i18n 'admin.logs.screened_urls.description'}}
|
||||
<button class="btn pull-right" {{action "exportScreenedUrlList"}} title="{{i18n 'admin.export_csv.button_title.screened_url'}}">{{fa-icon "download"}}{{i18n 'admin.export_csv.button_text'}}</button>
|
||||
</p>
|
||||
</br>
|
||||
|
||||
{{#loading-spinner condition=loading}}
|
||||
{{#if model.length}}
|
||||
<div class='table screened-urls'>
|
||||
<div class="heading-container">
|
||||
<div class="col heading first domain">{{i18n admin.logs.screened_urls.domain}}</div>
|
||||
<div class="col heading action">{{i18n admin.logs.action}}</div>
|
||||
<div class="col heading match_count">{{i18n admin.logs.match_count}}</div>
|
||||
<div class="col heading last_match_at">{{i18n admin.logs.last_match_at}}</div>
|
||||
<div class="col heading created_at">{{i18n admin.logs.created_at}}</div>
|
||||
<div class="col heading first domain">{{i18n 'admin.logs.screened_urls.domain'}}</div>
|
||||
<div class="col heading action">{{i18n 'admin.logs.action'}}</div>
|
||||
<div class="col heading match_count">{{i18n 'admin.logs.match_count'}}</div>
|
||||
<div class="col heading last_match_at">{{i18n 'admin.logs.last_match_at'}}</div>
|
||||
<div class="col heading created_at">{{i18n 'admin.logs.created_at'}}</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
{{view 'screened-urls-list' content=controller}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{i18n search.no_results}}
|
||||
{{i18n 'search.no_results'}}
|
||||
{{/if}}
|
||||
{{/loading-spinner}}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<div>
|
||||
<ul class="nav nav-pills">
|
||||
<li {{bind-attr class="newSelected:active"}}>
|
||||
<a href="#" {{action "selectNew"}}>{{i18n admin.logs.staff_actions.new_value}}</a>
|
||||
<a href="#" {{action "selectNew"}}>{{i18n 'admin.logs.staff_actions.new_value'}}</a>
|
||||
</li>
|
||||
<li {{bind-attr class="previousSelected:active"}}>
|
||||
<a href="#" {{action "selectPrevious"}}>{{i18n admin.logs.staff_actions.previous_value}}</a>
|
||||
<a href="#" {{action "selectPrevious"}}>{{i18n 'admin.logs.staff_actions.previous_value'}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="modal-body">
|
||||
@ -14,7 +14,7 @@
|
||||
{{partial "admin/templates/logs/site_customization_change_details"}}
|
||||
{{/with}}
|
||||
{{else}}
|
||||
{{i18n admin.logs.staff_actions.deleted}}
|
||||
{{i18n 'admin.logs.staff_actions.deleted'}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div {{bind-attr class=":modal-tab :previous-tab previousSelected::invisible"}}>
|
||||
@ -23,11 +23,11 @@
|
||||
{{partial "admin/templates/logs/site_customization_change_details"}}
|
||||
{{/with}}
|
||||
{{else}}
|
||||
{{i18n admin.logs.staff_actions.no_previous}}
|
||||
{{i18n 'admin.logs.staff_actions.no_previous'}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n close}}</button>
|
||||
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n 'close'}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user