diff --git a/.gitignore b/.gitignore index 9dfa377bcf8..25f45fa7f7d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,14 @@ ._.DS_Store dump.rdb +bin/* + .sass-cache/* public/csv/* public/plugins/* public/tombstone/* # Ignore bundler config -/bin /.bundle /.vagrant /.vagrantfile @@ -29,9 +30,9 @@ config/discourse.pill config/discourse.conf # Ignore the default SQLite database and db dumps +*.sql +*.sql.gz /db/*.sqlite3 -/dbs/*.sql -/dbs/*.sql.gz /db/structure.sql # Ignore all logfiles and tempfiles. @@ -108,3 +109,6 @@ bundler_stubs/* vendor/bundle/* *.db + +#ignore jetbrains ide file +*.iml diff --git a/.ruby-version.sample b/.ruby-version.sample index 95a5ad2d548..276cbf9e285 100644 --- a/.ruby-version.sample +++ b/.ruby-version.sample @@ -1 +1 @@ -ruby-2.0.0-p195 +2.3.0 diff --git a/.travis.yml b/.travis.yml index 129da18869a..ed1f7d20b12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ env: - "RAILS_MASTER=1" addons: - postgresql: 9.3 + postgresql: 9.5 apt: packages: - gifsicle @@ -38,6 +38,10 @@ cache: before_install: - gem install bundler + - git clone --depth=1 https://github.com/discourse/discourse-backup-uploads-to-s3.git plugins/discourse-backup-uploads-to-s3 + - git clone --depth=1 https://github.com/discourse/discourse-spoiler-alert.git plugins/discourse-spoiler-alert + - git clone --depth=1 https://github.com/discourse/discourse-cakeday.git plugins/discourse-cakeday + - git clone --depth=1 https://github.com/discourse/discourse-canned-replies.git plugins/discourse-canned-replies - npm i -g eslint babel-eslint - eslint app/assets/javascripts - eslint --ext .es6 app/assets/javascripts @@ -49,7 +53,7 @@ before_script: - bundle exec rake db:create db:migrate install: - - bash -c "if [ '$RAILS_MASTER' == '1' ]; then bundle update --retry=3 --jobs=3 arel rails rails-observers seed-fu; fi" + - bash -c "if [ '$RAILS_MASTER' == '1' ]; then bundle update --retry=3 --jobs=3 arel rails seed-fu; fi" - bash -c "if [ '$RAILS_MASTER' == '0' ]; then bundle install --without development --deployment --retry=3 --jobs=3; fi" -script: 'bundle exec rspec && bundle exec rake plugin:spec && bundle exec rake qunit:test' +script: "bundle exec rspec && bundle exec rake plugin:spec && bundle exec rake qunit:test['200000']" diff --git a/Gemfile b/Gemfile index e23b919a510..a0a84196212 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,6 @@ end 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/rails/rails-observers.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else # Rails 5 is going to ship with Action Cable, we have no use for it as @@ -29,8 +28,6 @@ else # gem 'railties' # gem 'sprockets-rails' gem 'rails', '~> 4.2' - - gem 'rails-observers' gem 'seed-fu', '~> 2.3.5' end @@ -48,7 +45,8 @@ gem 'onebox' gem 'http_accept_language', '~>2.0.5', require: false gem 'ember-rails', '0.18.5' -gem 'ember-source', '1.12.2' +gem 'ember-source', '2.10.0' +gem 'ember-handlebars-template', '0.7.5' gem 'barber' gem 'babel-transpiler' @@ -66,7 +64,7 @@ gem 'aws-sdk', require: false gem 'excon', require: false gem 'unf', require: false -gem 'email_reply_trimmer', '0.1.3' +gem 'email_reply_trimmer', '0.1.6' # note: for image_optim to correctly work you need to follow # https://github.com/toy/image_optim @@ -122,6 +120,7 @@ end group :test do gem 'fakeweb', '~> 1.3.0', require: false gem 'minitest', require: false + gem 'timecop' end group :test, :development do @@ -137,9 +136,6 @@ group :test, :development do gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false gem 'rspec-rails', require: false gem 'shoulda', require: false - gem 'simplecov', require: false - gem 'timecop' - gem 'rspec-given' gem 'rspec-html-matchers' gem 'spork-rails' gem 'pry-nav' @@ -150,7 +146,6 @@ group :development do gem 'bullet', require: !!ENV['BULLET'] gem 'better_errors' gem 'binding_of_caller' - gem 'librarian', '>= 0.0.25', require: false gem 'annotate' gem 'foreman', require: false end @@ -169,35 +164,21 @@ gem 'htmlentities', require: false # 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 'fast_stack', require: false, platform: [:mri_20] gem 'flamegraph', require: false gem 'rack-mini-profiler', require: false gem 'unicorn', require: false gem 'puma', require: false gem 'rbtrace', require: false, platform: :mri +gem 'gc_tracer', require: false, platform: :mri # required for feed importing and embedding # gem 'ruby-readability', require: false - gem 'simple-rss', require: false -gem 'gctools', require: false, platform: :mri_21 - -begin - gem 'stackprof', require: false, platform: [:mri_21, :mri_22, :mri_23] - gem 'memory_profiler', require: false, platform: [:mri_21, :mri_22, :mri_23] -rescue Bundler::GemfileError - begin - STDERR.puts "You are running an old version of bundler, please upgrade bundler ASAP, if you are using Discourse docker, rebuild your container." - gem 'stackprof', require: false, platform: [:mri_21, :mri_22] - gem 'memory_profiler', require: false, platform: [:mri_21, :mri_22] - rescue Bundler::GemfileError - gem 'stackprof', require: false, platform: [:mri_21] - gem 'memory_profiler', require: false, platform: [:mri_21] - end -end +gem 'stackprof', require: false, platform: :mri +gem 'memory_profiler', require: false, platform: :mri gem 'rmmseg-cpp', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 597ba655393..0371a8438b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,38 +1,38 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.7) - actionpack (= 4.2.7) - actionview (= 4.2.7) - activejob (= 4.2.7) + actionmailer (4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.7) - actionview (= 4.2.7) - activesupport (= 4.2.7) + actionpack (4.2.7.1) + actionview (= 4.2.7.1) + activesupport (= 4.2.7.1) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.7) - activesupport (= 4.2.7) + actionview (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) active_model_serializers (0.8.3) activemodel (>= 3.0) - activejob (4.2.7) - activesupport (= 4.2.7) + activejob (4.2.7.1) + activesupport (= 4.2.7.1) globalid (>= 0.3.0) - activemodel (4.2.7) - activesupport (= 4.2.7) + activemodel (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) - activerecord (4.2.7) - activemodel (= 4.2.7) - activesupport (= 4.2.7) + activerecord (4.2.7.1) + activemodel (= 4.2.7.1) + activesupport (= 4.2.7.1) arel (~> 6.0) - activesupport (4.2.7) + activesupport (4.2.7.1) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -42,17 +42,17 @@ GEM activerecord (>= 3.2, < 6.0) rake (>= 10.4, < 12.0) arel (6.0.3) - aws-sdk (2.3.22) - aws-sdk-resources (= 2.3.22) - aws-sdk-core (2.3.22) + aws-sdk (2.5.3) + aws-sdk-resources (= 2.5.3) + aws-sdk-core (2.5.3) jmespath (~> 1.0) - aws-sdk-resources (2.3.22) - aws-sdk-core (= 2.3.22) + aws-sdk-resources (2.5.3) + aws-sdk-core (= 2.5.3) babel-source (5.8.34) babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) - barber (0.11.1) + barber (0.11.2) ember-source (>= 1.0, < 3) execjs (>= 1.2, < 3) better_errors (2.1.1) @@ -62,28 +62,27 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) - bullet (5.0.0) + bullet (5.4.2) activesupport (>= 3.0.0) - uniform_notifier (~> 1.9.0) - byebug (8.2.1) + uniform_notifier (~> 1.10.0) + byebug (9.0.6) certified (1.0.0) - coderay (1.1.0) + coderay (1.1.1) concurrent-ruby (1.0.2) connection_pool (2.2.0) crass (1.0.2) - daemons (1.2.3) + daemons (1.2.4) debug_inspector (0.0.2) diff-lcs (1.2.5) discourse-qunit-rails (0.0.9) railties discourse_fastimage (2.0.3) - docile (1.1.5) domain_name (0.5.25) unf (>= 0.0.5, < 1.0.0) - email_reply_trimmer (0.1.3) - ember-data-source (1.0.0.beta.16.1) - ember-source (~> 1.8) - ember-handlebars-template (0.7.3) + email_reply_trimmer (0.1.6) + ember-data-source (2.2.1) + ember-source (>= 1.8, < 3.0) + ember-handlebars-template (0.7.5) barber (>= 0.11.0) sprockets (>= 3.3, < 4) ember-rails (0.18.5) @@ -93,10 +92,10 @@ GEM ember-source (>= 1.1.0) jquery-rails (>= 1.0.17) railties (>= 3.1) - ember-source (1.12.2) + ember-source (2.10.0) erubis (2.7.0) eventmachine (1.2.0.1) - excon (0.45.4) + excon (0.53.0) execjs (2.7.0) exifr (1.2.4) fabrication (2.9.8) @@ -104,7 +103,6 @@ GEM faraday (0.9.2) multipart-post (>= 1.2, < 3) fast_blank (1.0.0) - fast_stack (0.2.0) fast_xor (1.1.3) rake rake-compiler @@ -114,10 +112,8 @@ GEM foreman (0.82.0) thor (~> 0.19.1) fspath (2.1.1) - gctools (0.2.3) - given_core (3.7.1) - sorcerer (>= 0.3.7) - globalid (0.3.6) + gc_tracer (1.5.1) + globalid (0.3.7) activesupport (>= 4.1.0) guess_html_encoding (0.0.11) hashie (3.4.4) @@ -136,18 +132,15 @@ GEM progress (~> 3.0, >= 3.0.1) image_size (1.4.1) in_threads (1.3.1) - jmespath (1.3.0) - jquery-rails (4.0.5) - rails-dom-testing (~> 1.0) + jmespath (1.3.1) + jquery-rails (4.2.1) + rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) jwt (1.5.2) kgio (2.10.0) - librarian (0.1.2) - highline - thor (~> 0.15) - libv8 (5.3.332.38.1) + libv8 (5.3.332.38.3) listen (0.7.3) logster (1.2.5) loofah (2.0.3) @@ -155,8 +148,8 @@ GEM lru_redux (1.1.0) mail (2.6.4) mime-types (>= 1.16, < 4) - memory_profiler (0.9.6) - message_bus (2.0.1) + memory_profiler (0.9.7) + message_bus (2.0.2) rack (>= 1.1.3) metaclass (0.0.4) method_source (0.8.2) @@ -164,7 +157,7 @@ GEM mini_portile2 (2.1.0) mini_racer (0.1.7) libv8 (~> 5.3) - minitest (5.9.0) + minitest (5.9.1) mocha (1.1.0) metaclass (~> 0.0.1) mock_redis (0.15.4) @@ -175,9 +168,8 @@ GEM multipart-post (2.0.0) mustache (1.0.3) netrc (0.11.0) - nokogiri (1.6.8) + nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) - pkg-config (~> 1.1.7) nokogumbo (1.4.7) nokogiri oauth (0.4.7) @@ -187,7 +179,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) - oj (2.14.3) + oj (2.17.5) omniauth (1.3.1) hashie (>= 1.2, < 4) rack (>= 1.0, < 3) @@ -216,7 +208,7 @@ GEM omniauth-twitter (1.2.1) json (~> 1.3) omniauth-oauth (~> 1.1) - onebox (1.6.7) + onebox (1.7.2) fast_blank (>= 1.0.0) htmlentities (~> 4.3.4) moneta (~> 0.8) @@ -226,10 +218,9 @@ GEM openid-redis-store (0.0.2) redis ruby-openid - pg (0.18.4) - pkg-config (1.1.7) + pg (0.19.0) progress (3.1.1) - pry (0.10.3) + pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) @@ -237,9 +228,9 @@ GEM pry (>= 0.9.10, < 0.11.0) pry-rails (0.3.4) pry (>= 0.9.10) - puma (3.2.0) + puma (3.6.0) r2 (0.2.6) - rack (1.6.4) + rack (1.6.5) rack-mini-profiler (0.10.1) rack (>= 1.2.0) rack-openid (1.3.1) @@ -249,16 +240,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.7) - actionmailer (= 4.2.7) - actionpack (= 4.2.7) - actionview (= 4.2.7) - activejob (= 4.2.7) - activemodel (= 4.2.7) - activerecord (= 4.2.7) - activesupport (= 4.2.7) + rails (4.2.7.1) + actionmailer (= 4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) + activemodel (= 4.2.7.1) + activerecord (= 4.2.7.1) + activesupport (= 4.2.7.1) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.7) + railties (= 4.2.7.1) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -268,15 +259,14 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - rails-observers (0.1.2) - activemodel (~> 4.0) - rails_multisite (1.0.4) - railties (4.2.7) - actionpack (= 4.2.7) - activesupport (= 4.2.7) + rails_multisite (1.0.6) + rails (> 4.2, < 5) + railties (4.2.7.1) + actionpack (= 4.2.7.1) + activesupport (= 4.2.7.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - raindrops (0.16.0) + raindrops (0.17.0) rake (11.2.2) rake-compiler (0.9.9) rake @@ -287,7 +277,7 @@ GEM ffi (>= 1.0.6) msgpack (>= 0.4.3) trollop (>= 1.16.2) - redis (3.3.0) + redis (3.3.1) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) rest-client (1.8.0) @@ -305,9 +295,6 @@ GEM rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.4.0) - rspec-given (3.7.1) - given_core (= 3.7.1) - rspec (>= 2.14.0) rspec-html-matchers (0.7.0) nokogiri (~> 1) rspec (~> 3) @@ -345,27 +332,22 @@ GEM shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) - shoulda-context (1.2.1) + shoulda-context (1.2.2) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) - sidekiq (4.1.2) + sidekiq (4.2.4) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) + rack-protection (>= 1.5.0) redis (~> 3.2, >= 3.2.1) sidekiq-statistic (1.2.0) sidekiq (>= 3.3.4, < 5) simple-rss (1.3.1) - simplecov (0.11.1) - docile (~> 1.1.0) - json (~> 1.8) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.0) sinatra (1.4.6) rack (~> 1.4) rack-protection (~> 1.4) tilt (>= 1.3, < 3) slop (3.6.0) - sorcerer (1.0.2) spork (1.0.0rc4) spork-rails (4.0.0) rails (>= 3.0.0, < 5) @@ -377,27 +359,27 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - stackprof (0.2.9) - thin (1.6.4) + stackprof (0.2.10) + thin (1.7.0) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) - rack (~> 1.0) + rack (>= 1, < 3) thor (0.19.1) thread_safe (0.3.5) - tilt (2.0.2) - timecop (0.8.0) + tilt (2.0.5) + timecop (0.8.1) trollop (2.1.2) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.0) + uglifier (3.0.2) execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext unf_ext (0.0.7.1) - unicorn (5.1.0) + unicorn (5.2.0) kgio (~> 2.6) raindrops (~> 0.7) - uniform_notifier (1.9.0) + uniform_notifier (1.10.0) PLATFORMS ruby @@ -415,26 +397,25 @@ DEPENDENCIES certified discourse-qunit-rails discourse_fastimage (= 2.0.3) - email_reply_trimmer (= 0.1.3) + email_reply_trimmer (= 0.1.6) + ember-handlebars-template (= 0.7.5) ember-rails (= 0.18.5) - ember-source (= 1.12.2) + ember-source (= 2.10.0) excon execjs fabrication (= 2.9.8) fakeweb (~> 1.3.0) fast_blank - fast_stack fast_xor fast_xs flamegraph foreman - gctools + gc_tracer highline hiredis htmlentities http_accept_language (~> 2.0.5) image_optim (= 0.20.2) - librarian (>= 0.0.25) listen (= 0.7.3) logster lru_redux @@ -468,7 +449,6 @@ DEPENDENCIES rack-mini-profiler rack-protection rails (~> 4.2) - rails-observers rails_multisite rake rb-fsevent @@ -480,7 +460,6 @@ DEPENDENCIES rinku rmmseg-cpp rspec - rspec-given rspec-html-matchers rspec-rails rtlit @@ -493,7 +472,6 @@ DEPENDENCIES sidekiq sidekiq-statistic simple-rss - simplecov sinatra spork-rails stackprof @@ -504,4 +482,4 @@ DEPENDENCIES unicorn BUNDLED WITH - 1.13.6 + 1.13.7 diff --git a/README.md b/README.md index 6cdf4c101b8..717ad14f23e 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ To learn more about the philosophy and goals of the project, [visit **discourse. ## Screenshots - - - + + + Atom   Soylent diff --git a/app/assets/images/favicons/google_branding/logo_docs_128px.png b/app/assets/images/favicons/google_branding/logo_docs_128px.png deleted file mode 100644 index a1c4e5f7bd5..00000000000 Binary files a/app/assets/images/favicons/google_branding/logo_docs_128px.png and /dev/null differ diff --git a/app/assets/images/favicons/google_branding/logo_docs_48px.png b/app/assets/images/favicons/google_branding/logo_docs_48px.png new file mode 100644 index 00000000000..f1fe798f0ef Binary files /dev/null and b/app/assets/images/favicons/google_branding/logo_docs_48px.png differ diff --git a/app/assets/images/favicons/google_branding/logo_drive_128px.png b/app/assets/images/favicons/google_branding/logo_drive_128px.png deleted file mode 100644 index 0eb48a7469f..00000000000 Binary files a/app/assets/images/favicons/google_branding/logo_drive_128px.png and /dev/null differ diff --git a/app/assets/images/favicons/google_branding/logo_drive_48px.png b/app/assets/images/favicons/google_branding/logo_drive_48px.png new file mode 100644 index 00000000000..ff595ca1e70 Binary files /dev/null and b/app/assets/images/favicons/google_branding/logo_drive_48px.png differ diff --git a/app/assets/images/favicons/google_branding/logo_forms_128px.png b/app/assets/images/favicons/google_branding/logo_forms_128px.png deleted file mode 100644 index 621321b0cf7..00000000000 Binary files a/app/assets/images/favicons/google_branding/logo_forms_128px.png and /dev/null differ diff --git a/app/assets/images/favicons/google_branding/logo_forms_48px.png b/app/assets/images/favicons/google_branding/logo_forms_48px.png new file mode 100644 index 00000000000..4ba7be23df4 Binary files /dev/null and b/app/assets/images/favicons/google_branding/logo_forms_48px.png differ diff --git a/app/assets/images/favicons/google_branding/logo_sheets_128px.png b/app/assets/images/favicons/google_branding/logo_sheets_128px.png deleted file mode 100644 index a99181d743d..00000000000 Binary files a/app/assets/images/favicons/google_branding/logo_sheets_128px.png and /dev/null differ diff --git a/app/assets/images/favicons/google_branding/logo_sheets_48px.png b/app/assets/images/favicons/google_branding/logo_sheets_48px.png new file mode 100644 index 00000000000..0a3cdc3c502 Binary files /dev/null and b/app/assets/images/favicons/google_branding/logo_sheets_48px.png differ diff --git a/app/assets/images/favicons/google_branding/logo_slides_128px.png b/app/assets/images/favicons/google_branding/logo_slides_128px.png deleted file mode 100644 index 538226c80f4..00000000000 Binary files a/app/assets/images/favicons/google_branding/logo_slides_128px.png and /dev/null differ diff --git a/app/assets/images/favicons/google_branding/logo_slides_48px.png b/app/assets/images/favicons/google_branding/logo_slides_48px.png new file mode 100644 index 00000000000..66b5155d690 Binary files /dev/null and b/app/assets/images/favicons/google_branding/logo_slides_48px.png differ diff --git a/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 b/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 new file mode 100644 index 00000000000..122070ce3e4 --- /dev/null +++ b/app/assets/javascripts/admin/adapters/web-hook-event.js.es6 @@ -0,0 +1,7 @@ +import RESTAdapter from 'discourse/adapters/rest'; + +export default RESTAdapter.extend({ + basePath() { + return '/admin/api/'; + } +}); diff --git a/app/assets/javascripts/admin/adapters/web-hook.js.es6 b/app/assets/javascripts/admin/adapters/web-hook.js.es6 new file mode 100644 index 00000000000..122070ce3e4 --- /dev/null +++ b/app/assets/javascripts/admin/adapters/web-hook.js.es6 @@ -0,0 +1,7 @@ +import RESTAdapter from 'discourse/adapters/rest'; + +export default RESTAdapter.extend({ + basePath() { + return '/admin/api/'; + } +}); diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index f9be6416406..a03865c40ce 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -1,6 +1,5 @@ -/* global ace:true */ import loadScript from 'discourse/lib/load-script'; -import { escapeExpression } from 'discourse/lib/utilities'; +import { observes } from 'ember-addons/ember-computed-decorators'; export default Ember.Component.extend({ mode: 'css', @@ -8,18 +7,11 @@ export default Ember.Component.extend({ _editor: null, _skipContentChangeEvent: null, - contentChanged: function() { + @observes('content') + contentChanged() { if (this._editor && !this._skipContentChangeEvent) { this._editor.getSession().setValue(this.get('content')); } - }.observes('content'), - - render(buffer) { - buffer.push("
"); - if (this.get('content')) { - buffer.push(escapeExpression(this.get('content'))); - } - buffer.push("
"); }, _destroyEditor: function() { @@ -39,31 +31,31 @@ export default Ember.Component.extend({ } }, - _initEditor: function() { - const self = this; + didInsertElement() { + this._super(); - loadScript("/javascripts/ace/ace.js", { scriptTag: true }).then(function() { - ace.require(['ace/ace'], function(loadedAce) { - const editor = loadedAce.edit(self.$('.ace')[0]); + loadScript("/javascripts/ace/ace.js", { scriptTag: true }).then(() => { + window.ace.require(['ace/ace'], loadedAce => { + if (!this.element || this.isDestroying || this.isDestroyed) { return; } + const editor = loadedAce.edit(this.$('.ace')[0]); editor.setTheme("ace/theme/chrome"); editor.setShowPrintMargin(false); - editor.getSession().setMode("ace/mode/" + self.get('mode')); - editor.on('change', function() { - self._skipContentChangeEvent = true; - self.set('content', editor.getSession().getValue()); - self._skipContentChangeEvent = false; + editor.getSession().setMode("ace/mode/" + this.get('mode')); + editor.on('change', () => { + this._skipContentChangeEvent = true; + this.set('content', editor.getSession().getValue()); + this._skipContentChangeEvent = false; }); editor.$blockScrolling = Infinity; - self.$().data('editor', editor); - self._editor = editor; - if (self.appEvents) { + this.$().data('editor', editor); + this._editor = editor; + if (this.appEvents) { // xxx: don't run during qunit tests - self.appEvents.on('ace:resize', self, self.resize); + this.appEvents.on('ace:resize', self, self.resize); } }); }); - - }.on('didInsertElement') + } }); diff --git a/app/assets/javascripts/admin/views/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 similarity index 76% rename from app/assets/javascripts/admin/views/admin-backups-logs.js.es6 rename to app/assets/javascripts/admin/components/admin-backups-logs.js.es6 index 1929abf5a22..01f4547b17e 100644 --- a/app/assets/javascripts/admin/views/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 @@ -1,18 +1,27 @@ import debounce from 'discourse/lib/debounce'; import { renderSpinner } from 'discourse/helpers/loading-spinner'; import { escapeExpression } from 'discourse/lib/utilities'; +import { bufferedRender } from 'discourse-common/lib/buffered-render'; -export default Ember.View.extend({ +export default Ember.Component.extend(bufferedRender({ classNames: ["admin-backups-logs"], - _initialize: function() { this._reset(); }.on("init"), + init() { + this._super(); + this._reset(); + }, _reset() { this.setProperties({ formattedLogs: "", index: 0 }); }, + _scrollDown() { + const $div = this.$()[0]; + $div.scrollTop = $div.scrollHeight; + }, + _updateFormattedLogs: debounce(function() { - const logs = this.get("controller.model"); + const logs = this.get("logs"); if (logs.length === 0) { this._reset(); // reset the cached logs whenever the model is reset } else { @@ -26,11 +35,12 @@ export default Ember.View.extend({ // update the formatted logs & cache index this.setProperties({ formattedLogs: formattedLogs, index: logs.length }); // force rerender - this.rerender(); + this.rerenderBuffer(); } - }, 150).observes("controller.model.[]"), + Ember.run.scheduleOnce('afterRender', this, this._scrollDown); + }, 150).observes("logs.[]").on('init'), - render(buffer) { + buildBuffer(buffer) { const formattedLogs = this.get("formattedLogs"); if (formattedLogs && formattedLogs.length > 0) { buffer.push("
");
@@ -40,14 +50,8 @@ export default Ember.View.extend({
       buffer.push("

" + I18n.t("admin.backups.logs.none") + "

"); } // add a loading indicator - if (this.get("controller.status.model.isOperationRunning")) { + if (this.get("status.isOperationRunning")) { buffer.push(renderSpinner('small')); } - }, - - _forceScrollToBottom: function() { - const $div = this.$()[0]; - $div.scrollTop = $div.scrollHeight; - }.on("didInsertElement") - -}); + } +})); diff --git a/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 new file mode 100644 index 00000000000..976b483995e --- /dev/null +++ b/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 @@ -0,0 +1,42 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + classNames: ['hook-event'], + typeName: Ember.computed.alias('type.name'), + + @computed('typeName') + name(typeName) { + return I18n.t(`admin.web_hooks.${typeName}_event.name`); + }, + + @computed('typeName') + details(typeName) { + return I18n.t(`admin.web_hooks.${typeName}_event.details`); + }, + + @computed('model.[]', 'typeName') + eventTypeExists(eventTypes, typeName) { + return eventTypes.any(event => event.name === typeName); + }, + + @computed('eventTypeExists') + enabled: { + get(eventTypeExists) { + return eventTypeExists; + }, + set(value, eventTypeExists) { + const type = this.get('type'); + const model = this.get('model'); + // add an association when not exists + if (value !== eventTypeExists) { + if (value) { + model.addObject(type); + } else { + model.removeObjects(model.filter(eventType => eventType.name === type.name)); + } + } + + return value; + } + } +}); diff --git a/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 new file mode 100644 index 00000000000..264e827da61 --- /dev/null +++ b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 @@ -0,0 +1,78 @@ +import computed from 'ember-addons/ember-computed-decorators'; +import { ajax } from 'discourse/lib/ajax'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; +import { ensureJSON, plainJSON, prettyJSON } from 'discourse/lib/formatter'; + +export default Ember.Component.extend({ + tagName: 'li', + expandDetails: null, + + @computed('model.status') + statusColorClasses(status) { + if (!status) return ''; + + if (status >= 200 && status <= 299) { + return 'text-successful'; + } else { + return 'text-danger'; + } + }, + + @computed('model.created_at') + createdAt(createdAt) { + return moment(createdAt).format('YYYY-MM-DD HH:mm:ss'); + }, + + @computed('model.duration') + completion(duration) { + const seconds = Math.floor(duration / 10.0) / 100.0; + return I18n.t('admin.web_hooks.events.completed_in', { count: seconds }); + }, + + actions: { + redeliver() { + return bootbox.confirm(I18n.t('admin.web_hooks.events.redeliver_confirm'), I18n.t('no_value'), I18n.t('yes_value'), result => { + if (result) { + ajax(`/admin/api/web_hooks/${this.get('model.web_hook_id')}/events/${this.get('model.id')}/redeliver`, { type: 'POST' }).then(json => { + this.set('model', json.web_hook_event); + }).catch(popupAjaxError); + } + }); + }, + + toggleRequest() { + const expandDetailsKey = 'request'; + + if (this.get('expandDetails') !== expandDetailsKey) { + let headers = _.extend({ + 'Request URL': this.get('model.request_url'), + 'Request method': 'POST' + }, ensureJSON(this.get('model.headers'))); + this.setProperties({ + headers: plainJSON(headers), + body: prettyJSON(this.get('model.payload')), + expandDetails: expandDetailsKey, + bodyLabel: I18n.t('admin.web_hooks.events.payload') + }); + } else { + this.set('expandDetails', null); + } + }, + + toggleResponse() { + const expandDetailsKey = 'response'; + + if (this.get('expandDetails') !== expandDetailsKey) { + this.setProperties({ + headers: plainJSON(this.get('model.response_headers')), + body: this.get('model.response_body'), + expandDetails: expandDetailsKey, + bodyLabel: I18n.t('admin.web_hooks.events.body') + }); + } else { + this.set('expandDetails', null); + } + } + } + +}); diff --git a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 new file mode 100644 index 00000000000..d176b5a40ab --- /dev/null +++ b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 @@ -0,0 +1,28 @@ +import computed from 'ember-addons/ember-computed-decorators'; +import { iconHTML } from 'discourse-common/helpers/fa-icon'; +import { bufferedRender } from 'discourse-common/lib/buffered-render'; + +export default Ember.Component.extend(bufferedRender({ + classes: ["text-muted", "text-danger", "text-successful"], + icons: ["circle-o", "times-circle", "circle"], + + @computed('deliveryStatuses', 'model.last_delivery_status') + status(deliveryStatuses, lastDeliveryStatus) { + return deliveryStatuses.find(s => s.id === lastDeliveryStatus); + }, + + @computed('status.id', 'icons') + icon(statusId, icons) { + return icons[statusId - 1]; + }, + + @computed('status.id', 'classes') + class(statusId, classes) { + return classes[statusId - 1]; + }, + + buildBuffer(buffer) { + buffer.push(iconHTML(this.get('icon'), { class: this.get('class') })); + buffer.push(I18n.t(`admin.web_hooks.delivery_status.${this.get('status.name')}`)); + } +})); diff --git a/app/assets/javascripts/admin/components/customize-link.js.es6 b/app/assets/javascripts/admin/components/customize-link.js.es6 index 79d8cc26f4a..0600f6b5cdb 100644 --- a/app/assets/javascripts/admin/components/customize-link.js.es6 +++ b/app/assets/javascripts/admin/components/customize-link.js.es6 @@ -1,6 +1,8 @@ +import { getOwner } from 'discourse-common/lib/get-owner'; + export default Ember.Component.extend({ router: function() { - return this.container.lookup('router:main'); + return getOwner(this).lookup('router:main'); }.property(), active: function() { diff --git a/app/assets/javascripts/admin/views/admin.js.es6 b/app/assets/javascripts/admin/components/disable-custom-stylesheets.js.es6 similarity index 53% rename from app/assets/javascripts/admin/views/admin.js.es6 rename to app/assets/javascripts/admin/components/disable-custom-stylesheets.js.es6 index fc4a611fe47..f4d86899d08 100644 --- a/app/assets/javascripts/admin/views/admin.js.es6 +++ b/app/assets/javascripts/admin/components/disable-custom-stylesheets.js.es6 @@ -1,12 +1,14 @@ -export default Ember.View.extend({ - _disableCustomStylesheets: function() { +export default Ember.Component.extend({ + willInsertElement() { + this._super(); if (this.session.get("disableCustomCSS")) { $("link.custom-css").attr("rel", ""); this.session.set("disableCustomCSS", false); } - }.on("willInsertElement"), + }, - _enableCustomStylesheets: function() { + willDestroyElement() { + this._super(); $("link.custom-css").attr("rel", "stylesheet"); - }.on("willDestroyElement") + } }); diff --git a/app/assets/javascripts/admin/components/embeddable-host.js.es6 b/app/assets/javascripts/admin/components/embeddable-host.js.es6 index f33c7509657..2a5d7c030b4 100644 --- a/app/assets/javascripts/admin/components/embeddable-host.js.es6 +++ b/app/assets/javascripts/admin/components/embeddable-host.js.es6 @@ -30,10 +30,11 @@ export default Ember.Component.extend(bufferedProperty('host'), { save() { if (this.get('cantSave')) { return; } - const props = this.get('buffered').getProperties('host'); + const props = this.get('buffered').getProperties('host', 'path_whitelist'); props.category_id = this.get('categoryId'); const host = this.get('host'); + host.save(props).then(() => { host.set('category', Discourse.Category.findById(this.get('categoryId'))); this.set('editToggled', false); diff --git a/app/assets/javascripts/admin/components/permalinks-list.js.es6 b/app/assets/javascripts/admin/components/permalinks-list.js.es6 deleted file mode 100644 index c4254376862..00000000000 --- a/app/assets/javascripts/admin/components/permalinks-list.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import ListView from 'ember-addons/list-view'; -import ListItemView from 'ember-addons/list-item-view'; - -export default ListView.extend({ - height: 700, - rowHeight: 32, - itemViewClass: ListItemView.extend({templateName: "admin/templates/permalinks_list_item"}) -}); diff --git a/app/assets/javascripts/admin/components/resumable-upload.js.es6 b/app/assets/javascripts/admin/components/resumable-upload.js.es6 index ea2f02cfa05..73a46eded3c 100644 --- a/app/assets/javascripts/admin/components/resumable-upload.js.es6 +++ b/app/assets/javascripts/admin/components/resumable-upload.js.es6 @@ -1,3 +1,5 @@ +import { bufferedRender } from 'discourse-common/lib/buffered-render'; + /*global Resumable:true */ /** @@ -10,7 +12,7 @@ uploadText="UPLOAD" }} **/ -const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer, { +export default Ember.Component.extend(bufferedRender({ tagName: "button", classNames: ["btn", "ru"], classNameBindings: ["isUploading"], @@ -36,9 +38,9 @@ const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer, } }.property("isUploading", "progress"), - renderString: function(buffer) { - var icon = this.get("isUploading") ? "times" : "upload"; - buffer.push(""); + buildBuffer(buffer) { + const icon = this.get("isUploading") ? "times" : "upload"; + buffer.push(``); buffer.push("" + this.get("text") + ""); buffer.push(""); }, @@ -117,6 +119,4 @@ const ResumableUploadComponent = Ember.Component.extend(Discourse.StringBuffer, } }.on("willDestroyElement") -}); - -export default ResumableUploadComponent; +})); diff --git a/app/assets/javascripts/admin/components/screened-emails-list.js.es6 b/app/assets/javascripts/admin/components/screened-emails-list.js.es6 deleted file mode 100644 index 1b32fb36fe9..00000000000 --- a/app/assets/javascripts/admin/components/screened-emails-list.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import ListView from 'ember-addons/list-view'; -import ListItemView from 'ember-addons/list-item-view'; - -export default ListView.extend({ - height: 700, - rowHeight: 32, - itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_emails_list_item"}) -}); diff --git a/app/assets/javascripts/admin/components/screened-ip-addresses-list.js.es6 b/app/assets/javascripts/admin/components/screened-ip-addresses-list.js.es6 deleted file mode 100644 index 0d30fc6d48d..00000000000 --- a/app/assets/javascripts/admin/components/screened-ip-addresses-list.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import ListView from 'ember-addons/list-view'; -import ListItemView from 'ember-addons/list-item-view'; - -export default ListView.extend({ - height: 700, - rowHeight: 32, - itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_ip_addresses_list_item"}) -}); diff --git a/app/assets/javascripts/admin/components/screened-urls-list.js.es6 b/app/assets/javascripts/admin/components/screened-urls-list.js.es6 deleted file mode 100644 index b9d8b76667e..00000000000 --- a/app/assets/javascripts/admin/components/screened-urls-list.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import ListView from 'ember-addons/list-view'; -import ListItemView from 'ember-addons/list-item-view'; - -export default ListView.extend({ - height: 700, - rowHeight: 32, - itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/screened_urls_list_item"}) -}); diff --git a/app/assets/javascripts/admin/components/site-setting.js.es6 b/app/assets/javascripts/admin/components/site-setting.js.es6 index 8b6601b4d37..662e4ef684c 100644 --- a/app/assets/javascripts/admin/components/site-setting.js.es6 +++ b/app/assets/javascripts/admin/components/site-setting.js.es6 @@ -1,12 +1,11 @@ import BufferedContent from 'discourse/mixins/buffered-content'; -import ScrollTop from 'discourse/mixins/scroll-top'; import SiteSetting from 'admin/models/site-setting'; import { propertyNotEqual } from 'discourse/lib/computed'; import computed from 'ember-addons/ember-computed-decorators'; const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list', 'category_list', 'value_list']; -export default Ember.Component.extend(BufferedContent, ScrollTop, { +export default Ember.Component.extend(BufferedContent, { classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'], content: Ember.computed.alias('setting'), dirty: propertyNotEqual('buffered.value', 'setting.value'), diff --git a/app/assets/javascripts/admin/components/staff-action-logs-list.js.es6 b/app/assets/javascripts/admin/components/staff-action-logs-list.js.es6 deleted file mode 100644 index cec82dba432..00000000000 --- a/app/assets/javascripts/admin/components/staff-action-logs-list.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import ListView from 'ember-addons/list-view'; -import ListItemView from 'ember-addons/list-item-view'; - -export default ListView.extend({ - height: 700, - rowHeight: 75, - itemViewClass: ListItemView.extend({templateName: "admin/templates/logs/staff_action_logs_list_item"}) -}); diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 new file mode 100644 index 00000000000..529538263c8 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 @@ -0,0 +1,32 @@ +import ApiKey from 'admin/models/api-key'; + +export default Ember.Controller.extend({ + + actions: { + generateMasterKey() { + ApiKey.generateMasterKey().then(key => this.get('model').pushObject(key)); + }, + + regenerateKey(key) { + bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), result => { + if (result) { + key.regenerate(); + } + }); + }, + + revokeKey(key) { + bootbox.confirm(I18n.t("admin.api.confirm_revoke"), I18n.t("no_value"), I18n.t("yes_value"), result => { + if (result) { + key.revoke().then(() => this.get('model').removeObject(key)); + } + }); + } + }, + + // Has a master key already been generated? + hasMasterKey: function() { + return !!this.get('model').findBy('user', null); + }.property('model.[]') + +}); diff --git a/app/assets/javascripts/admin/controllers/admin-api.js.es6 b/app/assets/javascripts/admin/controllers/admin-api.js.es6 deleted file mode 100644 index 82366d3bd78..00000000000 --- a/app/assets/javascripts/admin/controllers/admin-api.js.es6 +++ /dev/null @@ -1,68 +0,0 @@ -import ApiKey from 'admin/models/api-key'; - -/** - This controller supports the interface for dealing with API keys - - @class AdminApiController - @extends Ember.ArrayController - @namespace Discourse - @module Discourse -**/ -export default Ember.ArrayController.extend({ - - actions: { - /** - Generates a master api key - - @method generateMasterKey - **/ - generateMasterKey: function() { - var self = this; - ApiKey.generateMasterKey().then(function (key) { - self.get('model').pushObject(key); - }); - }, - - /** - Creates an API key instance with internal user object - - @method regenerateKey - @param {ApiKey} key the key to regenerate - **/ - regenerateKey: function(key) { - bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { - if (result) { - key.regenerate(); - } - }); - }, - - /** - Revokes an API key - - @method revokeKey - @param {ApiKey} key the key to revoke - **/ - revokeKey: function(key) { - var self = this; - bootbox.confirm(I18n.t("admin.api.confirm_revoke"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { - if (result) { - key.revoke().then(function() { - self.get('model').removeObject(key); - }); - } - }); - } - }, - - /** - Has a master key already been generated? - - @property hasMasterKey - @type {Boolean} - **/ - hasMasterKey: function() { - return !!this.get('model').findBy('user', null); - }.property('model.[]') - -}); diff --git a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 index 98f76405a2f..558b9b4973e 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 @@ -1,19 +1,21 @@ +import DiscourseURL from 'discourse/lib/url'; import { ajax } from 'discourse/lib/ajax'; -export default Ember.ArrayController.extend({ - needs: ["adminBackups"], - status: Ember.computed.alias("controllers.adminBackups"), + +export default Ember.Controller.extend({ + adminBackups: Ember.inject.controller(), + status: Ember.computed.alias('adminBackups.model'), uploadLabel: function() { return I18n.t("admin.backups.upload.label"); }.property(), restoreTitle: function() { - if (!this.get('status.model.allowRestore')) { + if (!this.get('status.allowRestore')) { return "admin.backups.operations.restore.is_disabled"; - } else if (this.get("status.model.isOperationRunning")) { + } else if (this.get("status.isOperationRunning")) { return "admin.backups.operations.is_running"; } else { return "admin.backups.operations.restore.title"; } - }.property("status.model.{allowRestore,isOperationRunning}"), + }.property("status.{allowRestore,isOperationRunning}"), actions: { @@ -34,8 +36,11 @@ export default Ember.ArrayController.extend({ } else { this._toggleReadOnlyMode(false); } - } + }, + download(backup) { + DiscourseURL.redirectTo(backup.get('link')); + } }, _toggleReadOnlyMode(enable) { diff --git a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 index 1b3d90346a1..38bdd6f5713 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 @@ -1,4 +1,5 @@ -export default Ember.ArrayController.extend({ - needs: ["adminBackups"], - status: Em.computed.alias("controllers.adminBackups") +export default Ember.Controller.extend({ + logs: [], + adminBackups: Ember.inject.controller(), + status: Em.computed.alias("adminBackups.model") }); diff --git a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 index 5ec2cb45410..7ddc6f3ac4e 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 @@ -3,14 +3,14 @@ import BufferedContent from 'discourse/mixins/buffered-content'; import { propertyNotEqual } from 'discourse/lib/computed'; export default Ember.Controller.extend(BufferedContent, { - needs: ['admin-badges'], + adminBadges: Ember.inject.controller(), saving: false, savingStatus: '', - badgeTypes: Em.computed.alias('controllers.admin-badges.badgeTypes'), - badgeGroupings: Em.computed.alias('controllers.admin-badges.badgeGroupings'), - badgeTriggers: Em.computed.alias('controllers.admin-badges.badgeTriggers'), - protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'), + badgeTypes: Ember.computed.alias('adminBadges.badgeTypes'), + badgeGroupings: Ember.computed.alias('adminBadges.badgeGroupings'), + badgeTriggers: Ember.computed.alias('adminBadges.badgeTriggers'), + protectedSystemFields: Ember.computed.alias('adminBadges.protectedSystemFields'), readOnly: Ember.computed.alias('buffered.system'), showDisplayName: propertyNotEqual('name', 'displayName'), @@ -30,16 +30,15 @@ export default Ember.Controller.extend(BufferedContent, { }.observes('model.id'), actions: { - save: function() { + save() { if (!this.get('saving')) { - var fields = ['allow_title', 'multiple_grant', - 'listable', 'auto_revoke', - 'enabled', 'show_posts', - 'target_posts', 'name', 'description', - 'long_description', - 'icon', 'image', 'query', 'badge_grouping_id', - 'trigger', 'badge_type_id'], - self = this; + let fields = ['allow_title', 'multiple_grant', + 'listable', 'auto_revoke', + 'enabled', 'show_posts', + 'target_posts', 'name', 'description', + 'long_description', + 'icon', 'image', 'query', 'badge_grouping_id', + 'trigger', 'badge_type_id']; if (this.get('buffered.system')){ var protectedFields = this.get('protectedSystemFields'); @@ -51,54 +50,55 @@ export default Ember.Controller.extend(BufferedContent, { this.set('saving', true); this.set('savingStatus', I18n.t('saving')); - var boolFields = ['allow_title', 'multiple_grant', - 'listable', 'auto_revoke', - 'enabled', 'show_posts', - 'target_posts' ]; + const boolFields = ['allow_title', 'multiple_grant', + 'listable', 'auto_revoke', + 'enabled', 'show_posts', + 'target_posts' ]; - var data = {}, - buffered = this.get('buffered'); + const data = {}; + const buffered = this.get('buffered'); fields.forEach(function(field){ var d = buffered.get(field); if (_.include(boolFields, field)) { d = !!d; } data[field] = d; }); - var newBadge = !this.get('id'), - model = this.get('model'); - this.get('model').save(data).then(function() { + const newBadge = !this.get('id'); + const model = this.get('model'); + this.get('model').save(data).then(() => { if (newBadge) { - var adminBadgesController = self.get('controllers.admin-badges'); - if (!adminBadgesController.contains(model)) adminBadgesController.pushObject(model); - self.transitionToRoute('adminBadges.show', model.get('id')); + const adminBadges = this.get('adminBadges.model'); + if (!adminBadges.includes(model)) { + adminBadges.pushObject(model); + } + this.transitionToRoute('adminBadges.show', model.get('id')); } else { - self.commitBuffer(); - self.set('savingStatus', I18n.t('saved')); + this.commitBuffer(); + this.set('savingStatus', I18n.t('saved')); } - }).catch(popupAjaxError).finally(function() { - self.set('saving', false); - self.set('savingStatus', ''); + }).catch(popupAjaxError).finally(() => { + this.set('saving', false); + this.set('savingStatus', ''); }); } }, - destroy: function() { - var self = this, - adminBadgesController = this.get('controllers.admin-badges'), - model = this.get('model'); + destroy() { + const adminBadges = this.get('adminBadges.model'); + const model = this.get('model'); if (!model.get('id')) { - self.transitionToRoute('adminBadges.index'); + this.transitionToRoute('adminBadges.index'); return; } - return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { + return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { if (result) { - model.destroy().then(function() { - adminBadgesController.removeObject(model); - self.transitionToRoute('adminBadges.index'); - }).catch(function() { + model.destroy().then(() => { + adminBadges.removeObject(model); + this.transitionToRoute('adminBadges.index'); + }).catch(() => { bootbox.alert(I18n.t('generic_error')); }); } diff --git a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges.js.es6 index 24c4c051390..77c79b724a7 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges.js.es6 @@ -1 +1 @@ -export default Ember.ArrayController.extend(); +export default Ember.Controller.extend(); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 index 4a6a58021bb..ae253aec843 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 @@ -1,4 +1,4 @@ -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ onlyOverridden: false, baseColorScheme: function() { @@ -13,8 +13,8 @@ export default Ember.ArrayController.extend({ return baseColorsHash; }.property('baseColorScheme'), - removeSelected: function() { - this.removeObject(this.get('selectedItem')); + removeSelected() { + this.get('model').removeObject(this.get('selectedItem')); this.set('selectedItem', null); }, @@ -26,8 +26,7 @@ export default Ember.ArrayController.extend({ return; } - var matches = Em.A(); - + const matches = []; _.each(this.get('selectedItem.colors'), function(color){ if (color.get('overridden')) matches.pushObject(color); }); @@ -58,10 +57,10 @@ export default Ember.ArrayController.extend({ this.filterContent(); }, - newColorScheme: function() { - var newColorScheme = Em.copy(this.get('baseColorScheme'), true); + newColorScheme() { + const newColorScheme = Em.copy(this.get('baseColorScheme'), true); newColorScheme.set('name', I18n.t('admin.customize.colors.new_name')); - this.pushObject(newColorScheme); + this.get('model').pushObject(newColorScheme); this.send('selectColorScheme', newColorScheme); this.set('onlyOverridden', false); }, @@ -86,10 +85,10 @@ export default Ember.ArrayController.extend({ this.updateEnabled(); }, - copy: function(colorScheme) { + copy(colorScheme) { var newColorScheme = Em.copy(colorScheme, true); newColorScheme.set('name', I18n.t('admin.customize.colors.copy_name_prefix') + ' ' + colorScheme.get('name')); - this.pushObject(newColorScheme); + this.get('model').pushObject(newColorScheme); this.send('selectColorScheme', newColorScheme); }, diff --git a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 index 03c855a969c..47cf280ae6c 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 @@ -33,7 +33,7 @@ export default Ember.Controller.extend(activeSections, { return !this.get('model.changed') || this.get('model.isSaving'); }.property('model.changed', 'model.isSaving'), - needs: ['adminCustomizeCssHtml'], + adminCustomizeCssHtml: Ember.inject.controller(), undoPreviewUrl: url('/?preview-style='), defaultStyleUrl: url('/?preview-style=default'), @@ -44,13 +44,12 @@ export default Ember.Controller.extend(activeSections, { }, destroy() { - const self = this; - return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { + return bootbox.confirm(I18n.t("admin.customize.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { if (result) { - const model = self.get('model'); - model.destroyRecord().then(function() { - self.get('controllers.adminCustomizeCssHtml').get('model').removeObject(model); - self.transitionToRoute('adminCustomizeCssHtml'); + const model = this.get('model'); + model.destroyRecord().then(() => { + this.get('adminCustomizeCssHtml').get('model').removeObject(model); + this.transitionToRoute('adminCustomizeCssHtml'); }); } }); diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 index 82cedfee59b..2e39c158802 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 @@ -22,7 +22,7 @@ export default Ember.Controller.extend({ @computed('problems.length') foundProblems(problemsLength) { - return this.currentUser.get('admin') && (problemsLength || 0) > 1; + return this.currentUser.get('admin') && (problemsLength || 0) > 0; }, @computed('foundProblems') diff --git a/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 index 160f998365b..5da4b0afb58 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 @@ -1,12 +1,23 @@ import EmailPreview from 'admin/models/email-preview'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; export default Ember.Controller.extend({ + emailEmpty: Em.computed.empty('email'), + sendEmailDisabled: Em.computed.or('emailEmpty', 'sendingEmail'), + showSendEmailForm: Em.computed.notEmpty('model.html_content'), + htmlEmpty: Em.computed.empty('model.html_content'), + + iframeSrc: function() { + return ('data:text/html;charset=utf-8,' + encodeURI(this.get('model.html_content'))); + }.property('model.html_content'), + actions: { refresh() { const model = this.get('model'); this.set('loading', true); + this.set('sentEmail', false); EmailPreview.findDigest(this.get('lastSeen'), this.get('username')).then(email => { model.setProperties(email.getProperties('html_content', 'text_content')); this.set('loading', false); @@ -15,6 +26,23 @@ export default Ember.Controller.extend({ toggleShowHtml() { this.toggleProperty('showHtml'); + }, + + sendEmail() { + this.set('sendingEmail', true); + this.set('sentEmail', false); + + const self = this; + + EmailPreview.sendDigest(this.get('lastSeen'), this.get('username'), this.get('email')).then(result => { + if (result.errors) { + bootbox.alert(result.errors); + } else { + self.set('sentEmail', true); + } + }).catch(popupAjaxError).finally(function() { + self.set('sendingEmail', false); + }); } } diff --git a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 index 780c61f3f91..266aa6975e6 100644 --- a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 @@ -9,7 +9,7 @@ export default Ember.Controller.extend({ @computed('embedding.embeddable_hosts.@each.isCreated') showSecondary() { const hosts = this.get('embedding.embeddable_hosts'); - return hosts.length && hosts.findProperty('isCreated'); + return hosts.length && hosts.findBy('isCreated'); }, @computed('embedding.base_url') @@ -38,9 +38,7 @@ export default Ember.Controller.extend({ const updates = embedding.getProperties(embedding.get('fields')); this.set('saved', false); - this.get('embedding').update(updates).then(() => { - this.set('saved', true); - }).catch(popupAjaxError); + this.get('embedding').update(updates).then(() => this.set('saved', true)).catch(popupAjaxError); }, addHost() { diff --git a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 index b111a5952ba..29aecc47734 100644 --- a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 @@ -1,23 +1,23 @@ import { ajax } from 'discourse/lib/ajax'; -export default Ember.ArrayController.extend({ - sortProperties: ["name"], +export default Ember.Controller.extend({ + sortedEmojis: Ember.computed.sort('model', 'emojiSorting'), + emojiSorting: ['name'], actions: { emojiUploaded(emoji) { emoji.url += "?t=" + new Date().getTime(); - this.pushObject(Ember.Object.create(emoji)); + this.get('model').pushObject(Ember.Object.create(emoji)); }, destroy(emoji) { - const self = this; return bootbox.confirm( I18n.t("admin.emoji.delete_confirm", { name: emoji.get("name") }), I18n.t("no_value"), I18n.t("yes_value"), - function(destroy) { + destroy => { if (destroy) { - return ajax("/admin/customize/emojis/" + emoji.get("name"), { type: "DELETE" }).then(function() { - self.removeObject(emoji); + return ajax("/admin/customize/emojis/" + emoji.get("name"), { type: "DELETE" }).then(() => { + this.get('model').removeObject(emoji); }); } } diff --git a/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6 b/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6 index 0c85749775a..e3101e2fa32 100644 --- a/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-flags-list.js.es6 @@ -1,6 +1,6 @@ import FlaggedPost from 'admin/models/flagged-post'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ query: null, adminOldFlagsView: Em.computed.equal("query", "old"), @@ -8,18 +8,16 @@ export default Ember.ArrayController.extend({ actions: { disagreeFlags(flaggedPost) { - var self = this; - flaggedPost.disagreeFlags().then(function () { - self.removeObject(flaggedPost); + flaggedPost.disagreeFlags().then(() => { + this.get('model').removeObject(flaggedPost); }, function () { bootbox.alert(I18n.t("admin.flags.error")); }); }, deferFlags(flaggedPost) { - var self = this; - flaggedPost.deferFlags().then(function () { - self.removeObject(flaggedPost); + flaggedPost.deferFlags().then(() => { + this.get('model').removeObject(flaggedPost); }, function () { bootbox.alert(I18n.t("admin.flags.error")); }); @@ -29,7 +27,7 @@ export default Ember.ArrayController.extend({ this.send("disagreeFlags", item); }, - loadMore(){ + loadMore() { const flags = this.get('model'); return FlaggedPost.findAll(this.get('query'), flags.length+1).then(data => { if (data.length===0) { diff --git a/app/assets/javascripts/admin/controllers/admin-group.js.es6 b/app/assets/javascripts/admin/controllers/admin-group.js.es6 index e477ba4b0a1..6c3da11d7f7 100644 --- a/app/assets/javascripts/admin/controllers/admin-group.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-group.js.es6 @@ -1,24 +1,11 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; -import { propertyEqual } from 'discourse/lib/computed'; +import computed from 'ember-addons/ember-computed-decorators'; export default Ember.Controller.extend({ - needs: ['adminGroupsType'], + adminGroupsType: Ember.inject.controller(), disableSave: false, savingStatus: '', - currentPage: function() { - if (this.get("model.user_count") === 0) { return 0; } - return Math.floor(this.get("model.offset") / this.get("model.limit")) + 1; - }.property("model.limit", "model.offset", "model.user_count"), - - totalPages: function() { - if (this.get("model.user_count") === 0) { return 0; } - return Math.floor(this.get("model.user_count") / this.get("model.limit")) + 1; - }.property("model.limit", "model.user_count"), - - showingFirst: Em.computed.lte("currentPage", 1), - showingLast: propertyEqual("currentPage", "totalPages"), - aliasLevelOptions: function() { return [ { name: I18n.t("groups.alias_levels.nobody"), value: 0 }, @@ -35,39 +22,17 @@ export default Ember.Controller.extend({ ]; }.property(), + @computed('model.visible', 'model.public', 'model.alias_level') + disableMembershipRequestSetting(visible, publicGroup) { + return !visible || publicGroup || !this.get('model.canEveryoneMention'); + }, + + @computed('model.visible', 'model.allow_membership_requests') + disablePublicSetting(visible, allowMembershipRequests) { + return !visible || allowMembershipRequests; + }, + actions: { - next() { - if (this.get("showingLast")) { return; } - - const 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() { - if (this.get("showingFirst")) { return; } - - const group = this.get("model"), - offset = Math.max(group.get("offset") - group.get("limit"), 0); - - group.set("offset", offset); - - return group.findMembers(); - }, - - removeMember(member) { - const self = this, - message = I18n.t("admin.groups.delete_member_confirm", { username: member.get("username"), group: this.get("model.name") }); - return bootbox.confirm(message, I18n.t("no_value"), I18n.t("yes_value"), function(confirm) { - if (confirm) { - self.get("model").removeMember(member); - } - }); - }, - removeOwner(member) { const self = this, message = I18n.t("admin.groups.delete_owner_confirm", { username: member.get("username"), group: this.get("model.name") }); @@ -84,21 +49,15 @@ export default Ember.Controller.extend({ this.set("model.ownerUsernames", null); }, - addMembers() { - if (Em.isEmpty(this.get("model.usernames"))) { return; } - this.get("model").addMembers(this.get("model.usernames")).catch(popupAjaxError); - this.set("model.usernames", null); - }, - save() { const group = this.get('model'), - groupsController = this.get("controllers.adminGroupsType"), + groupsController = this.get("adminGroupsType"), groupType = groupsController.get("type"); this.set('disableSave', true); this.set('savingStatus', I18n.t('saving')); - let promise = group.get("id") ? group.save() : group.create().then(() => groupsController.addObject(group)); + let promise = group.get("id") ? group.save() : group.create().then(() => groupsController.get('model').addObject(group)); promise.then(() => { this.transitionToRoute("adminGroup", groupType, group.get('name')); @@ -109,7 +68,7 @@ export default Ember.Controller.extend({ destroy() { const group = this.get('model'), - groupsController = this.get('controllers.adminGroupsType'), + groupsController = this.get('adminGroupsType'), self = this; if (!group.get('id')) { diff --git a/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6 b/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6 index 9a5962cccfa..10d7ad01cfe 100644 --- a/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-groups-type.js.es6 @@ -1,18 +1,18 @@ import { ajax } from 'discourse/lib/ajax'; -export default Ember.ArrayController.extend({ - sortProperties: ['name'], +export default Ember.Controller.extend({ + sortedGroups: Ember.computed.sort('model', 'groupSorting'), + groupSorting: ['name'], + refreshingAutoGroups: false, - isAuto: function(){ - return this.get('type') === 'automatic'; - }.property('type'), + + isAuto: Ember.computed.equal('type', 'automatic'), actions: { - refreshAutoGroups: function(){ - var self = this; + refreshAutoGroups() { this.set('refreshingAutoGroups', true); - ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(function() { - self.transitionToRoute("adminGroupsType", "automatic").then(function() { - self.set('refreshingAutoGroups', false); + ajax('/admin/groups/refresh_automatic_groups', {type: 'POST'}).then(() => { + this.transitionToRoute("adminGroupsType", "automatic").then(() => { + this.set('refreshingAutoGroups', false); }); }); } diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 index fe158a33aba..13685f16b95 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 @@ -2,12 +2,12 @@ import { exportEntity } from 'discourse/lib/export-csv'; import { outputExportResult } from 'discourse/lib/export-result'; import ScreenedEmail from 'admin/models/screened-email'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ loading: false, actions: { clearBlock(row){ - row.clearBlock().then(function(){ + row.clearBlock().then(function() { // feeling lazy window.location.reload(); }); @@ -19,11 +19,10 @@ export default Ember.ArrayController.extend({ }, show() { - var self = this; - self.set('loading', true); - ScreenedEmail.findAll().then(function(result) { - self.set('model', result); - self.set('loading', false); + this.set('loading', true); + ScreenedEmail.findAll().then(result => { + this.set('model', result); + this.set('loading', false); }); } }); diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 index 88f46d6ccbc..b654e6d65f7 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 @@ -3,7 +3,7 @@ import { outputExportResult } from 'discourse/lib/export-result'; import { exportEntity } from 'discourse/lib/export-csv'; import ScreenedIpAddress from 'admin/models/screened-ip-address'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ loading: false, filter: null, savedIpAddress: null, @@ -63,16 +63,15 @@ export default Ember.ArrayController.extend({ }, destroy(record) { - const self = this; return bootbox.confirm( I18n.t("admin.logs.screened_ips.delete_confirm", { ip_address: record.get('ip_address') }), I18n.t("no_value"), I18n.t("yes_value"), - function (result) { + result => { if (result) { record.destroy().then(deleted => { if (deleted) { - self.get("content").removeObject(record); + this.get("model").removeObject(record); } else { bootbox.alert(I18n.t("generic_error")); } diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 index 5f5e3339608..d57a151d219 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 @@ -2,15 +2,14 @@ import { exportEntity } from 'discourse/lib/export-csv'; import { outputExportResult } from 'discourse/lib/export-result'; import ScreenedUrl from 'admin/models/screened-url'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ loading: false, show() { - const self = this; - self.set('loading', true); - ScreenedUrl.findAll().then(function(result) { - self.set('model', result); - self.set('loading', false); + this.set('loading', true); + ScreenedUrl.findAll().then(result => { + this.set('model', result); + this.set('loading', false); }); }, diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 index 956a737e578..98f135dc57c 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 @@ -2,7 +2,7 @@ import { exportEntity } from 'discourse/lib/export-csv'; import { outputExportResult } from 'discourse/lib/export-result'; import StaffActionLog from 'admin/models/staff-action-log'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ loading: false, filters: null, diff --git a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 index 9c5ab4bb3e8..6bfcc669227 100644 --- a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 @@ -1,16 +1,14 @@ import debounce from 'discourse/lib/debounce'; import Permalink from 'admin/models/permalink'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ loading: false, filter: null, show: debounce(function() { - var self = this; - self.set('loading', true); - Permalink.findAll(self.get("filter")).then(function(result) { - self.set('model', result); - self.set('loading', false); + Permalink.findAll(this.get("filter")).then(result => { + this.set('model', result); + this.set('loading', false); }); }, 250).observes("filter"), @@ -20,12 +18,11 @@ export default Ember.ArrayController.extend({ }, destroy: function(record) { - const self = this; - return bootbox.confirm(I18n.t("admin.permalink.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { + return bootbox.confirm(I18n.t("admin.permalink.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { if (result) { - record.destroy().then(function(deleted) { + record.destroy().then(deleted => { if (deleted) { - self.removeObject(record); + this.get('model').removeObject(record); } else { bootbox.alert(I18n.t("generic_error")); } diff --git a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 index b2eb1335ed8..5393a27c8f6 100644 --- a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 @@ -1,10 +1,9 @@ -export default Ember.ArrayController.extend({ - +export default Ember.Controller.extend({ adminRoutes: function() { - return this.get('model').map(function(p) { - if (p.get('enabled')) { - return p.admin_route; - } + return this.get('model').map(p => { + if (p.get('enabled')) { + return p.admin_route; + } }).compact(); }.property() }); diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 index b16db34e3e6..df0738bed18 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 @@ -1,16 +1,16 @@ export default Ember.Controller.extend({ categoryNameKey: null, - needs: ['adminSiteSettings'], + adminSiteSettings: Ember.inject.controller(), filteredContent: function() { if (!this.get('categoryNameKey')) { return []; } - const category = this.get('controllers.adminSiteSettings.content').findProperty('nameKey', this.get('categoryNameKey')); + const category = (this.get('adminSiteSettings.model') || []).findBy('nameKey', this.get('categoryNameKey')); if (category) { return category.siteSettings; } else { return []; } - }.property('controllers.adminSiteSettings.content', 'categoryNameKey') + }.property('adminSiteSettings.model', 'categoryNameKey') }); diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 index b7c4302e87c..9cd65adf101 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 @@ -1,6 +1,7 @@ import debounce from 'discourse/lib/debounce'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ + queryParams: ["filter"], filter: null, onlyOverridden: false, filtered: Ember.computed.notEmpty('filter'), diff --git a/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 index 0c770bd06bd..bc2147e9232 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 @@ -1,38 +1,14 @@ -import { default as computed } from 'ember-addons/ember-computed-decorators'; - let lastSearch; +let lastOverridden; export default Ember.Controller.extend({ - _q: null, searching: false, siteTexts: null, preferred: false, - _overridden: null, queryParams: ['q', 'overridden'], - @computed - overridden: { - set(value) { - if (!value || value === "false") { value = false; } - this._overridden = value; - return value; - }, - get() { - return this._overridden; - } - }, - - @computed - q: { - set(value) { - if (Ember.isEmpty(value)) { value = null; } - this._q = value; - return value; - }, - get() { - return this._q; - } - }, + q: null, + overridden: null, _performSearch() { this.store.find('site-text', this.getProperties('q', 'overridden')).then(results => { @@ -46,11 +22,14 @@ export default Ember.Controller.extend({ }, search(overridden) { + this.set('overridden', overridden); + const q = this.get('q'); - if (q !== lastSearch || overridden) { + if (q !== lastSearch || overridden !== lastOverridden) { this.set('searching', true); Ember.run.debounce(this, this._performSearch, 400); lastSearch = q; + lastOverridden = overridden; } } } diff --git a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 index c8c0ba6219e..a2b7c94f175 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 @@ -1,10 +1,11 @@ import UserBadge from 'discourse/models/user-badge'; -export default Ember.ArrayController.extend({ - needs: ["adminUser"], - user: Em.computed.alias('controllers.adminUser.model'), - sortProperties: ['granted_at'], - sortAscending: false, +export default Ember.Controller.extend({ + adminUser: Ember.inject.controller(), + user: Ember.computed.alias('adminUser.model'), + + sortedBadges: Ember.computed.sort('model', 'badgeSortOrder'), + badgeSortOrder: ['granted_at:desc'], groupedBadges: function(){ const allBadges = this.get('model'); @@ -38,8 +39,6 @@ export default Ember.ArrayController.extend({ }); return _(expanded).sortBy(group => group.granted_at).reverse().value(); - - }.property('model', 'model.[]', 'model.expandedBadges.[]'), /** @@ -80,22 +79,15 @@ export default Ember.ArrayController.extend({ model.get('expandedBadges').pushObject(userBadge.badge.id); }, - /** - Grant the selected badge to the user. - - @method grantBadge - @param {Integer} badgeId id of the badge we want to grant. - **/ - grantBadge: function(badgeId) { - var self = this; - UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) { - self.set('badgeReason', ''); - self.pushObject(userBadge); - Ember.run.next(function() { + grantBadge(badgeId) { + UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(userBadge => { + this.set('badgeReason', ''); + this.get('model').pushObject(userBadge); + Ember.run.next(() => { // Update the selected badge ID after the combobox has re-rendered. - var newSelectedBadge = self.get('grantableBadges')[0]; + const newSelectedBadge = this.get('grantableBadges')[0]; if (newSelectedBadge) { - self.set('selectedBadgeId', newSelectedBadge.get('id')); + this.set('selectedBadgeId', newSelectedBadge.get('id')); } }); }, function() { @@ -104,12 +96,11 @@ export default Ember.ArrayController.extend({ }); }, - revokeBadge: function(userBadge) { - var self = this; - return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { + revokeBadge(userBadge) { + return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { if (result) { - userBadge.revoke().then(function() { - self.get('model').removeObject(userBadge); + userBadge.revoke().then(() => { + this.get('model').removeObject(userBadge); }); } }); diff --git a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 index 70963a147e5..6b106b075d8 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 @@ -6,12 +6,8 @@ export default Ember.Controller.extend({ fieldTypes: null, createDisabled: Em.computed.gte('model.length', MAX_FIELDS), - arrangedContent: function() { - return Ember.ArrayProxy.extend(Ember.SortableMixin).create({ - sortProperties: ['position'], - content: this.get('model') - }); - }.property('model'), + fieldSortOrder: ['position'], + sortedFields: Ember.computed.sort('model', 'fieldSortOrder'), actions: { createField() { @@ -20,9 +16,9 @@ export default Ember.Controller.extend({ }, moveUp(f) { - const idx = this.get('arrangedContent').indexOf(f); + const idx = this.get('sortedFields').indexOf(f); if (idx) { - const prev = this.get('arrangedContent').objectAt(idx-1); + const prev = this.get('sortedFields').objectAt(idx-1); const prevPos = prev.get('position'); prev.update({ position: f.get('position') }); @@ -31,9 +27,9 @@ export default Ember.Controller.extend({ }, moveDown(f) { - const idx = this.get('arrangedContent').indexOf(f); + const idx = this.get('sortedFields').indexOf(f); if (idx > -1) { - const next = this.get('arrangedContent').objectAt(idx+1); + const next = this.get('sortedFields').objectAt(idx+1); const nextPos = next.get('position'); next.update({ position: f.get('position') }); diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index 0c1cb7abb37..14bc031c0a3 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -31,6 +31,29 @@ export default Ember.Controller.extend(CanCheckEmails, { }.property('model.user_fields.[]'), actions: { + + impersonate() { return this.get("model").impersonate(); }, + logOut() { return this.get("model").logOut(); }, + resetBounceScore() { return this.get("model").resetBounceScore(); }, + refreshBrowsers() { return this.get("model").refreshBrowsers(); }, + approve() { return this.get("model").approve(); }, + deactivate() { return this.get("model").deactivate(); }, + sendActivationEmail() { return this.get("model").sendActivationEmail(); }, + activate() { return this.get("model").activate(); }, + revokeAdmin() { return this.get("model").revokeAdmin(); }, + grantAdmin() { return this.get("model").grantAdmin(); }, + revokeModeration() { return this.get("model").revokeModeration(); }, + grantModeration() { return this.get("model").grantModeration(); }, + saveTrustLevel() { return this.get("model").saveTrustLevel(); }, + restoreTrustLevel() { return this.get("model").restoreTrustLevel(); }, + lockTrustLevel(locked) { return this.get("model").lockTrustLevel(locked); }, + unsuspend() { return this.get("model").unsuspend(); }, + unblock() { return this.get("model").unblock(); }, + block() { return this.get("model").block(); }, + deleteAllPosts() { return this.get("model").deleteAllPosts(); }, + anonymize() { return this.get('model').anonymize(); }, + destroy() { return this.get('model').destroy(); }, + toggleTitleEdit() { this.set('userTitleValue', this.get('model.title')); this.toggleProperty('editingTitle'); @@ -39,7 +62,7 @@ export default Ember.Controller.extend(CanCheckEmails, { saveTitle() { const self = this; - return ajax("/users/" + this.get('model.username').toLowerCase(), { + return ajax(`/users/${this.get('model.username').toLowerCase()}.json`, { data: {title: this.get('userTitleValue')}, type: 'PUT' }).catch(function(e) { @@ -107,14 +130,6 @@ export default Ember.Controller.extend(CanCheckEmails, { if (result) { self.get('model').revokeApiKey(); } } ); - }, - - anonymize() { - this.get('model').anonymize(); - }, - - destroy() { - this.get('model').destroy(); } } diff --git a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 index af4a0297ef6..1d877dadaf5 100644 --- a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 @@ -2,7 +2,7 @@ import debounce from 'discourse/lib/debounce'; import { i18n } from 'discourse/lib/computed'; import AdminUser from 'admin/models/admin-user'; -export default Ember.ArrayController.extend({ +export default Ember.Controller.extend({ query: null, showEmails: false, refreshing: false, @@ -19,7 +19,7 @@ export default Ember.ArrayController.extend({ selectedCount: function() { var model = this.get('model'); if (!model || !model.length) return 0; - return model.filterProperty('selected').length; + return model.filterBy('selected').length; }.property('model.@each.selected'), selectAllChanged: function() { @@ -52,14 +52,14 @@ export default Ember.ArrayController.extend({ actions: { approveUsers: function() { - AdminUser.bulkApprove(this.get('model').filterProperty('selected')); + AdminUser.bulkApprove(this.get('model').filterBy('selected')); this._refreshUsers(); }, rejectUsers: function() { var maxPostAge = this.siteSettings.delete_user_max_post_age; var controller = this; - AdminUser.bulkReject(this.get('model').filterProperty('selected')).then(function(result){ + AdminUser.bulkReject(this.get('model').filterBy('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}); diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 new file mode 100644 index 00000000000..6ef4411702e --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 @@ -0,0 +1,65 @@ +import { ajax } from 'discourse/lib/ajax'; +import { popupAjaxError } from 'discourse/lib/ajax-error'; +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Controller.extend({ + pingDisabled: false, + incomingEventIds: [], + incomingCount: Ember.computed.alias("incomingEventIds.length"), + + @computed('incomingCount') + hasIncoming(incomingCount) { + return incomingCount > 0; + }, + + subscribe() { + this.messageBus.subscribe(`/web_hook_events/${this.get('model.extras.web_hook_id')}`, data => { + if (data.event_type === 'ping') { + this.set('pingDisabled', false); + } + this._addIncoming(data.web_hook_event_id); + }); + }, + + unsubscribe() { + this.messageBus.unsubscribe('/web_hook_events/*'); + }, + + _addIncoming(eventId) { + const incomingEventIds = this.get("incomingEventIds"); + + if (incomingEventIds.indexOf(eventId) === -1) { + incomingEventIds.pushObject(eventId); + } + }, + + actions: { + loadMore() { + this.get('model').loadMore(); + }, + + ping() { + this.set('pingDisabled', true); + + ajax(`/admin/api/web_hooks/${this.get('model.extras.web_hook_id')}/ping`, { + type: 'POST' + }).catch(error => { + this.set('pingDisabled', false); + popupAjaxError(error); + }); + }, + + showInserted() { + const webHookId = this.get('model.extras.web_hook_id'); + + ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, { + type: 'GET', + data: { ids: this.get('incomingEventIds') } + }).then(data => { + const objects = data.map(event => this.store.createRecord('web-hook-event', event)); + this.get("model").unshiftObjects(objects); + this.set("incomingEventIds", []); + }); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 new file mode 100644 index 00000000000..53d8370403b --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 @@ -0,0 +1,98 @@ +import { popupAjaxError } from 'discourse/lib/ajax-error'; +import { extractDomainFromUrl } from 'discourse/lib/utilities'; +import computed from 'ember-addons/ember-computed-decorators'; +import InputValidation from 'discourse/models/input-validation'; + +export default Ember.Controller.extend({ + adminWebHooks: Ember.inject.controller(), + eventTypes: Ember.computed.alias('adminWebHooks.eventTypes'), + defaultEventTypes: Ember.computed.alias('adminWebHooks.defaultEventTypes'), + contentTypes: Ember.computed.alias('adminWebHooks.contentTypes'), + + @computed('model.isSaving', 'saved', 'saveButtonDisabled') + savingStatus(isSaving, saved, saveButtonDisabled) { + if (isSaving) { + return I18n.t('saving'); + } else if (!saveButtonDisabled && saved) { + return I18n.t('saved'); + } + // Use side effect of validation to clear saved text + this.set('saved', false); + return ''; + }, + + @computed('model.isNew') + saveButtonText(isNew) { + return isNew ? I18n.t('admin.web_hooks.create') : I18n.t('admin.web_hooks.save'); + }, + + @computed('model.secret') + secretValidation(secret) { + if (!Ember.isEmpty(secret)) { + if (secret.indexOf(' ') !== -1) { + return InputValidation.create({ + failed: true, + reason: I18n.t('admin.web_hooks.secret_invalid') + }); + } + + if (secret.length < 12) { + return InputValidation.create({ + failed: true, + reason: I18n.t('admin.web_hooks.secret_too_short') + }); + } + } + }, + + @computed('model.wildcard_web_hook', 'model.web_hook_event_types.[]') + eventTypeValidation(isWildcard, eventTypes) { + if (!isWildcard && Ember.isEmpty(eventTypes)) { + return InputValidation.create({ + failed: true, + reason: I18n.t('admin.web_hooks.event_type_missing') + }); + } + }, + + @computed('model.isSaving', 'secretValidation', 'eventTypeValidation') + saveButtonDisabled(isSaving, secretValidation, eventTypeValidation) { + return isSaving ? false : secretValidation || eventTypeValidation; + }, + + actions: { + save() { + this.set('saved', false); + const url = extractDomainFromUrl(this.get('model.payload_url')); + const model = this.get('model'); + const saveWebHook = () => { + return model.save().then(() => { + this.set('saved', true); + this.get('adminWebHooks').get('model').addObject(model); + }).catch(popupAjaxError); + }; + + if (url === 'localhost' || url.match(/192\.168\.\d+\.\d+/) || url.match(/127\.\d+\.\d+\.\d+/) || url === Discourse.BaseUrl) { + return bootbox.confirm(I18n.t('admin.web_hooks.warn_local_payload_url'), I18n.t('no_value'), I18n.t('yes_value'), result => { + if (result) { + return saveWebHook(); + } + }); + } + + return saveWebHook(); + }, + + destroy() { + return bootbox.confirm(I18n.t('admin.web_hooks.delete_confirm'), I18n.t('no_value'), I18n.t('yes_value'), result => { + if (result) { + const model = this.get('model'); + model.destroyRecord().then(() => { + this.get('adminWebHooks').get('model').removeObject(model); + this.transitionToRoute('adminWebHooks'); + }).catch(popupAjaxError); + } + }); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 new file mode 100644 index 00000000000..50b8b370f3a --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 @@ -0,0 +1,19 @@ +import { popupAjaxError } from 'discourse/lib/ajax-error'; + +export default Ember.Controller.extend({ + actions: { + destroy(webhook) { + return bootbox.confirm(I18n.t('admin.web_hooks.delete_confirm'), I18n.t('no_value'), I18n.t('yes_value'), result => { + if (result) { + webhook.destroyRecord().then(() => { + this.get('model').removeObject(webhook); + }).catch(popupAjaxError); + } + }); + }, + + loadMore() { + this.get('model').loadMore(); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 index 2924eb66998..7f1f4f2e49a 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 @@ -1,16 +1,15 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; export default Ember.Controller.extend(ModalFunctionality, { - needs: ["admin-flags-list"], + adminFlagsList: Ember.inject.controller(), _agreeFlag: function (actionOnPost) { - var adminFlagController = this.get("controllers.admin-flags-list"); - var post = this.get("content"); - var self = this; + const adminFlagController = this.get("adminFlagsList"); + const post = this.get("content"); - return post.agreeFlags(actionOnPost).then(function () { - adminFlagController.removeObject(post); - self.send("closeModal"); + return post.agreeFlags(actionOnPost).then(() => { + adminFlagController.get('model').removeObject(post); + this.send("closeModal"); }, function () { bootbox.alert(I18n.t("admin.flags.error")); }); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 index 8f93884c604..8aaf637552e 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 @@ -1,11 +1,9 @@ import { escapeExpression } from 'discourse/lib/utilities'; export default Ember.Controller.extend({ - needs: ['modal'], - - sample: Em.computed.alias('model.sample'), - errors: Em.computed.alias('model.errors'), - count: Em.computed.alias('model.grant_count'), + sample: Ember.computed.alias('model.sample'), + errors: Ember.computed.alias('model.errors'), + count: Ember.computed.alias('model.grant_count'), count_warning: function() { if (this.get('count') <= 10) { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 index 284b8bfd09d..fc2e0627946 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 @@ -1,36 +1,31 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; export default Ember.Controller.extend(ModalFunctionality, { - needs: ["admin-flags-list"], + adminFlagsList: Ember.inject.controller(), actions: { + deletePostDeferFlag() { + const adminFlagController = this.get("adminFlagsList"); + const post = this.get("content"); - deletePostDeferFlag: function () { - var adminFlagController = this.get("controllers.admin-flags-list"); - var post = this.get("content"); - var self = this; - - return post.deferFlags(true).then(function () { - adminFlagController.removeObject(post); - self.send("closeModal"); + return post.deferFlags(true).then(() => { + adminFlagController.get('model').removeObject(post); + this.send("closeModal"); }, function () { bootbox.alert(I18n.t("admin.flags.error")); }); }, - deletePostAgreeFlag: function () { - var adminFlagController = this.get("controllers.admin-flags-list"); - var post = this.get("content"); - var self = this; + deletePostAgreeFlag() { + const adminFlagController = this.get("adminFlagsList"); + const post = this.get("content"); - return post.agreeFlags("delete").then(function () { - adminFlagController.removeObject(post); - self.send("closeModal"); + return post.agreeFlags("delete").then(() => { + adminFlagController.get('model').removeObject(post); + this.send("closeModal"); }, function () { bootbox.alert(I18n.t("admin.flags.error")); }); } - } - }); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 index 086080c1738..fe0416bc307 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 @@ -1,6 +1,5 @@ import { ajax } from 'discourse/lib/ajax'; export default Ember.Controller.extend({ - needs: ['modal'], modelChanged: function(){ const model = this.get('model'); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 index 15cd838245b..c041b24f744 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 @@ -2,31 +2,27 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import Backup from 'admin/models/backup'; export default Ember.Controller.extend(ModalFunctionality, { - needs: ["adminBackupsLogs"], + adminBackupsLogs: Ember.inject.controller(), - _startBackup: function (withUploads) { - var self = this; - Discourse.User.currentProp("hideReadOnlyAlert", true); - Backup.start(withUploads).then(function() { - self.get("controllers.adminBackupsLogs").clear(); - self.send("backupStarted"); + _startBackup(withUploads) { + this.currentUser.set('hideReadOnlyAlert', true); + Backup.start(withUploads).then(() => { + this.get("adminBackupsLogs.logs").clear(); + this.send("backupStarted"); }); }, actions: { - - startBackup: function () { + startBackup() { this._startBackup(); }, - startBackupWithoutUpload: function () { + startBackupWithoutUpload() { this._startBackup(false); }, - cancel: function () { + cancel() { this.send("closeModal"); } - } - }); diff --git a/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 index d38c396ceb7..95537e305a3 100644 --- a/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 @@ -1,7 +1,7 @@ import ChangeSiteCustomizationDetailsController from "admin/controllers/modals/change-site-customization-details"; export default ChangeSiteCustomizationDetailsController.extend({ - onShow: function() { + onShow() { this.send("selectPrevious"); } }); diff --git a/app/assets/javascripts/admin/helpers/human-size.js.es6 b/app/assets/javascripts/admin/helpers/human-size.js.es6 index a43897c627e..a50cfe58190 100644 --- a/app/assets/javascripts/admin/helpers/human-size.js.es6 +++ b/app/assets/javascripts/admin/helpers/human-size.js.es6 @@ -1,3 +1,3 @@ -import { htmlHelper } from 'discourse/lib/helpers'; +import { htmlHelper } from 'discourse-common/lib/helpers'; export default htmlHelper(size => I18n.toHumanSize(size)); diff --git a/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 b/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 index 73bac433799..b58e9a552ce 100644 --- a/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 +++ b/app/assets/javascripts/admin/helpers/preserve-newlines.js.es6 @@ -1,4 +1,4 @@ -import { htmlHelper } from 'discourse/lib/helpers'; +import { htmlHelper } from 'discourse-common/lib/helpers'; import { escapeExpression } from 'discourse/lib/utilities'; export default htmlHelper(str => escapeExpression(str).replace(/\n/g, "
")); diff --git a/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 b/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 index aeac49e83d6..48d2271caba 100644 --- a/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 +++ b/app/assets/javascripts/admin/helpers/value-at-tl.js.es6 @@ -1,4 +1,4 @@ -import { registerUnbound } from 'discourse/lib/helpers'; +import { registerUnbound } from 'discourse-common/lib/helpers'; registerUnbound('value-at-tl', function(data, params) { var tl = parseInt(params.level, 10); diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6 index d804894770a..48764b671d6 100644 --- a/app/assets/javascripts/admin/models/admin-user.js.es6 +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -96,7 +96,7 @@ const AdminUser = Discourse.User.extend({ deleteAllPosts() { const user = this, - message = I18n.t('admin.user.delete_all_posts_confirm', { posts: user.get('post_count'), topics: user.get('topic_count') }), + message = I18n.messageFormat('admin.user.delete_all_posts_confirm_MF', { "POSTS": user.get('post_count'), "TOPICS": user.get('topic_count') }), buttons = [{ "label": I18n.t("composer.cancel"), "class": "cancel-inline", @@ -257,7 +257,7 @@ const AdminUser = Discourse.User.extend({ }); }, - log_out() { + logOut() { return ajax("/admin/users/" + this.id + "/log_out", { type: 'POST', data: { username_or_email: this.get('username') } @@ -467,13 +467,13 @@ const AdminUser = Discourse.User.extend({ user.checkEmail().then(function() { const data = { - posts: user.get('post_count'), - topics: user.get('topic_count'), + "POSTS": user.get('post_count'), + "TOPICS": user.get('topic_count'), email: user.get('email') || I18n.t("flagging.hidden_email_address"), ip_address: user.get('ip_address') || I18n.t("flagging.ip_address_missing") }; - const message = I18n.t('flagging.delete_confirm', data), + const message = I18n.messageFormat('flagging.delete_confirm_MF', data), buttons = [{ "label": I18n.t("composer.cancel"), "class": "cancel-inline", diff --git a/app/assets/javascripts/admin/models/api-key.js.es6 b/app/assets/javascripts/admin/models/api-key.js.es6 index aa05ce8341c..2a7cf867783 100644 --- a/app/assets/javascripts/admin/models/api-key.js.es6 +++ b/app/assets/javascripts/admin/models/api-key.js.es6 @@ -52,7 +52,7 @@ ApiKey.reopenClass({ @returns {Promise} a promise that resolves to the array of `ApiKey` instances **/ find: function() { - return ajax("/admin/api").then(function(keys) { + return ajax("/admin/api/keys").then(function(keys) { return keys.map(function (key) { return ApiKey.create(key); }); diff --git a/app/assets/javascripts/admin/models/backup.js.es6 b/app/assets/javascripts/admin/models/backup.js.es6 index d7baceebacf..7fe81441c37 100644 --- a/app/assets/javascripts/admin/models/backup.js.es6 +++ b/app/assets/javascripts/admin/models/backup.js.es6 @@ -2,7 +2,6 @@ import { ajax } from 'discourse/lib/ajax'; import PreloadStore from 'preload-store'; const Backup = Discourse.Model.extend({ - destroy() { return ajax("/admin/backups/" + this.get("filename"), { type: "DELETE" }); }, @@ -13,11 +12,9 @@ const Backup = Discourse.Model.extend({ data: { client_id: window.MessageBus.clientId } }); } - }); Backup.reopenClass({ - find() { return PreloadStore.getAndRemove("backups", () => ajax("/admin/backups.json")) .then(backups => backups.map(backup => Backup.create(backup))); diff --git a/app/assets/javascripts/admin/models/email-preview.js.es6 b/app/assets/javascripts/admin/models/email-preview.js.es6 index f992bf250d8..acc7462b925 100644 --- a/app/assets/javascripts/admin/models/email-preview.js.es6 +++ b/app/assets/javascripts/admin/models/email-preview.js.es6 @@ -5,7 +5,7 @@ EmailPreview.reopenClass({ findDigest: function(lastSeenAt, username) { if (Em.isEmpty(lastSeenAt)) { - lastSeenAt = moment().subtract(7, 'days').format('YYYY-MM-DD'); + lastSeenAt = this.oneWeekAgo(); } if (Em.isEmpty(username)) { @@ -17,6 +17,25 @@ EmailPreview.reopenClass({ }).then(function (result) { return EmailPreview.create(result); }); + }, + + sendDigest: function(lastSeenAt, username, email) { + if (Em.isEmpty(lastSeenAt)) { + lastSeenAt = this.oneWeekAgo(); + } + + if (Em.isEmpty(username)) { + username = Discourse.User.current().username; + } + + return ajax("/admin/email/send-digest.json", { + data: { last_seen_at: lastSeenAt, username: username, email: email } + }); + }, + + oneWeekAgo() { + const en = moment().locale('en'); + return en.subtract(7, 'days').format('YYYY-MM-DD'); } }); diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index 3342323b467..03e3888f97b 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -81,7 +81,8 @@ const Report = Discourse.Model.extend({ switch (this.get("type")) { case "flags": return "flag"; case "likes": return "heart"; - default: return null; + case "bookmarks": return "bookmark"; + default: return null; } }.property("type"), diff --git a/app/assets/javascripts/admin/models/web-hook.js.es6 b/app/assets/javascripts/admin/models/web-hook.js.es6 new file mode 100644 index 00000000000..e688a4dd0a1 --- /dev/null +++ b/app/assets/javascripts/admin/models/web-hook.js.es6 @@ -0,0 +1,85 @@ +import RestModel from 'discourse/models/rest'; +import Category from 'discourse/models/category'; +import Group from 'discourse/models/group'; +import { default as computed, observes } from 'ember-addons/ember-computed-decorators'; + +export default RestModel.extend({ + content_type: 1, // json + last_delivery_status: 1, // inactive + wildcard_web_hook: false, + verify_certificate: true, + active: false, + web_hook_event_types: null, + categoriesFilter: null, + groupsFilterInName: null, + + @computed('wildcard_web_hook') + webHookType: { + get(wildcard) { + return wildcard ? 'wildcard' : 'individual'; + }, + set(value) { + this.set('wildcard_web_hook', value === 'wildcard'); + } + }, + + @observes('category_ids') + updateCategoriesFilter() { + this.set('categoriesFilter', Category.findByIds(this.get('category_ids'))); + }, + + @observes('group_ids') + updateGroupsFilter() { + const groupIds = this.get('group_ids'); + this.set('groupsFilterInName', Discourse.Site.currentProp('groups').reduce((groupNames, g) => { + if (groupIds.includes(g.id)) { groupNames.push(g.name); } + return groupNames; + }, [])); + }, + + groupFinder(term) { + return Group.findAll({search: term, ignore_automatic: false}); + }, + + @computed('wildcard_web_hook', 'web_hook_event_types.[]') + description(isWildcardWebHook, types) { + let desc = ''; + + types.forEach(type => { + const name = `${type.name.toLowerCase()}_event`; + desc += (desc !== '' ? `, ${name}` : name); + }); + + return (isWildcardWebHook ? '*' : desc); + }, + + createProperties() { + const types = this.get('web_hook_event_types'); + const categories = this.get('categoriesFilter'); + // Hack as {{group-selector}} accepts a comma-separated string as data source, but + // we use an array to populate the datasource above. + const groupsFilter = this.get('groupsFilterInName'); + const groupNames = typeof groupsFilter === 'string' ? groupsFilter.split(',') : groupsFilter; + + return { + payload_url: this.get('payload_url'), + content_type: this.get('content_type'), + secret: this.get('secret'), + wildcard_web_hook: this.get('wildcard_web_hook'), + verify_certificate: this.get('verify_certificate'), + active: this.get('active'), + web_hook_event_type_ids: Ember.isEmpty(types) ? [null] : types.map(type => type.id), + category_ids: Ember.isEmpty(categories) ? [null] : categories.map(c => c.id), + group_ids: Ember.isEmpty(groupNames) || Ember.isEmpty(groupNames[0]) ? [null] : Discourse.Site.currentProp('groups') + .reduce((groupIds, g) => { + if (groupNames.includes(g.name)) { groupIds.push(g.id); } + return groupIds; + }, []) + }; + }, + + updateProperties() { + return this.createProperties(); + } +}); + diff --git a/app/assets/javascripts/admin/routes/admin-api-index.js.es6 b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 new file mode 100644 index 00000000000..f41f6bb7948 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 @@ -0,0 +1,5 @@ +export default Ember.Route.extend({ + beforeModel() { + this.transitionTo('adminApiKeys'); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-api.js.es6 b/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 similarity index 100% rename from app/assets/javascripts/admin/routes/admin-api.js.es6 rename to app/assets/javascripts/admin/routes/admin-api-keys.js.es6 diff --git a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 index cd01295f5de..c036a107429 100644 --- a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 @@ -5,17 +5,17 @@ export default Ember.Route.extend({ // since the logs are pushed via the message bus // we only want to preload them (hence the beforeModel hook) beforeModel() { - const logsController = this.controllerFor("adminBackupsLogs"); + const logs = this.controllerFor("adminBackupsLogs").get('logs'); // preload the logs if any PreloadStore.getAndRemove("logs").then(function (preloadedLogs) { if (preloadedLogs && preloadedLogs.length) { // we need to filter out message like: "[SUCCESS]" // and convert POJOs to Ember Objects - const logs = _.chain(preloadedLogs) - .reject(function (log) { return log.message.length === 0 || log.message[0] === "["; }) - .map(function (log) { return Em.Object.create(log); }) - .value(); - logsController.pushObjects(logs); + const newLogs = _.chain(preloadedLogs) + .reject(function (log) { return log.message.length === 0 || log.message[0] === "["; }) + .map(function (log) { return Em.Object.create(log); }) + .value(); + logs.pushObjects(newLogs); } }); }, diff --git a/app/assets/javascripts/admin/routes/admin-backups.js.es6 b/app/assets/javascripts/admin/routes/admin-backups.js.es6 index d590019431e..95407e9ff30 100644 --- a/app/assets/javascripts/admin/routes/admin-backups.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups.js.es6 @@ -15,7 +15,7 @@ export default Discourse.Route.extend({ _processLogMessage(log) { if (log.message === "[STARTED]") { this.controllerFor("adminBackups").set("model.isOperationRunning", true); - this.controllerFor("adminBackupsLogs").clear(); + this.controllerFor("adminBackupsLogs").get('logs').clear(); } else if (log.message === "[FAILED]") { this.controllerFor("adminBackups").set("model.isOperationRunning", false); bootbox.alert(I18n.t("admin.backups.operations.failed", { operation: log.operation })); @@ -27,7 +27,7 @@ export default Discourse.Route.extend({ window.location.pathname = Discourse.getURL("/"); } } else { - this.controllerFor("adminBackupsLogs").pushObject(Em.Object.create(log)); + this.controllerFor("adminBackupsLogs").get('logs').pushObject(Em.Object.create(log)); } }, @@ -49,7 +49,7 @@ export default Discourse.Route.extend({ actions: { startBackup() { - showModal('modals/admin-start-backup'); + showModal('admin-start-backup', { admin: true }); this.controllerFor('modal').set('modalClass', 'start-backup-modal'); }, diff --git a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 index 03d091d228d..cc0155181f7 100644 --- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 @@ -13,7 +13,7 @@ export default Ember.Route.extend({ name: I18n.t('admin.badges.new_badge') }); } - return this.modelFor('adminBadges').findProperty('id', parseInt(params.badge_id)); + return this.modelFor('adminBadges').findBy('id', parseInt(params.badge_id)); }, actions: { @@ -27,7 +27,7 @@ export default Ember.Route.extend({ editGroupings() { const model = this.controllerFor('admin-badges').get('badgeGroupings'); - showModal('modals/admin-edit-badge-groupings', { model }); + showModal('admin-edit-badge-groupings', { model, admin: true }); }, preview(badge, explain) { @@ -42,7 +42,7 @@ export default Ember.Route.extend({ } }).then(function(model) { badge.set('preview_loading', false); - showModal('modals/admin-badge-preview', { model }); + showModal('admin-badge-preview', { model, admin: true }); }).catch(function(error) { badge.set('preview_loading', false); Em.Logger.error(error); diff --git a/app/assets/javascripts/admin/routes/admin-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-badges.js.es6 index 68da5edb6b1..96ecddab234 100644 --- a/app/assets/javascripts/admin/routes/admin-badges.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges.js.es6 @@ -5,21 +5,20 @@ import BadgeGrouping from 'discourse/models/badge-grouping'; export default Discourse.Route.extend({ _json: null, - model: function() { - var self = this; - return ajax('/admin/badges.json').then(function(json) { - self._json = json; + model() { + return ajax('/admin/badges.json').then(json => { + this._json = json; return Badge.createFromJson(json); }); }, - setupController: function(controller, model) { - var json = this._json, - triggers = [], - badgeGroupings = []; + setupController(controller, model) { + const json = this._json; + const badgeTriggers = []; + const badgeGroupings = []; _.each(json.admin_badges.triggers,function(v,k){ - triggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)}); + badgeTriggers.push({id: v, name: I18n.t('admin.badges.trigger_type.'+k)}); }); json.badge_groupings.forEach(function(badgeGroupingJson) { @@ -30,8 +29,8 @@ export default Discourse.Route.extend({ badgeGroupings: badgeGroupings, badgeTypes: json.badge_types, protectedSystemFields: json.admin_badges.protected_system_fields, - badgeTriggers: triggers, - model: model + badgeTriggers, + model }); } }); diff --git a/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6 index dc38f3c51fb..7df829706fd 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-css-html-show.js.es6 @@ -1,7 +1,7 @@ export default Ember.Route.extend({ model(params) { const all = this.modelFor('adminCustomizeCssHtml'); - const model = all.findProperty('id', parseInt(params.site_customization_id)); + const model = all.findBy('id', parseInt(params.site_customization_id)); return model ? { model, section: params.section } : this.replaceWith('adminCustomizeCssHtml.index'); }, diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 index b6e4e36bf9f..7c759995fb4 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 @@ -3,7 +3,7 @@ import { scrollTop } from 'discourse/mixins/scroll-top'; export default Ember.Route.extend({ model(params) { const all = this.modelFor('adminCustomizeEmailTemplates'); - return all.findProperty('id', params.id); + return all.findBy('id', params.id); }, setupController(controller, emailTemplate) { diff --git a/app/assets/javascripts/admin/routes/admin-email-index.js.es6 b/app/assets/javascripts/admin/routes/admin-email-index.js.es6 index 1b75e39f6f8..ae1272c0b9f 100644 --- a/app/assets/javascripts/admin/routes/admin-email-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-index.js.es6 @@ -3,9 +3,5 @@ import EmailSettings from 'admin/models/email-settings'; export default Discourse.Route.extend({ model() { return EmailSettings.find(); - }, - - renderTemplate() { - this.render('admin/templates/email_index', { into: 'adminEmail' }); } }); diff --git a/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6 b/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6 index a7819b31a60..22c4141275e 100644 --- a/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6 @@ -6,7 +6,7 @@ export default AdminEmailIncomings.extend({ actions: { showIncomingEmail(id) { - showModal('modals/admin-incoming-email'); + showModal('admin-incoming-email', { admin: true }); this.controllerFor("modals/admin-incoming-email").load(id); } } diff --git a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 index ebbc3e6d2bc..ba00186d90e 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 @@ -14,12 +14,12 @@ export default Discourse.Route.extend({ actions: { showAgreeFlagModal(model) { - showModal('modals/admin-agree-flag', { model }); + showModal('admin-agree-flag', { model, admin: true }); this.controllerFor('modal').set('modalClass', 'agree-flag-modal'); }, showDeleteFlagModal(model) { - showModal('modals/admin-delete-flag', { model }); + showModal('admin-delete-flag', { model, admin: true }); this.controllerFor('modal').set('modalClass', 'delete-flag-modal'); } diff --git a/app/assets/javascripts/admin/routes/admin-group.js.es6 b/app/assets/javascripts/admin/routes/admin-group.js.es6 index 298bffaa434..3575496edd4 100644 --- a/app/assets/javascripts/admin/routes/admin-group.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-group.js.es6 @@ -7,8 +7,7 @@ export default Discourse.Route.extend({ return Group.create({ automatic: false, visible: true }); } - const group = this.modelFor('adminGroupsType') - .findProperty('name', params.name); + const group = this.modelFor('adminGroupsType').findBy('name', params.name); if (!group) { return this.transitionTo('adminGroups.index'); } diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 index 1008dc1c1db..d31e5219242 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 @@ -1,6 +1,6 @@ export default Discourse.Route.extend({ renderTemplate: function() { - this.render('admin/templates/logs/screened_emails', {into: 'adminLogs'}); + this.render('admin/templates/logs/screened-emails', {into: 'adminLogs'}); }, setupController: function() { diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 index ca914fe1d26..c6518c244c8 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 @@ -1,6 +1,6 @@ export default Discourse.Route.extend({ renderTemplate() { - this.render('admin/templates/logs/screened_ip_addresses', {into: 'adminLogs'}); + this.render('admin/templates/logs/screened-ip-addresses', {into: 'adminLogs'}); }, setupController() { diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 index 093dd263319..ee65fda0900 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 @@ -1,6 +1,6 @@ export default Discourse.Route.extend({ renderTemplate: function() { - this.render('admin/templates/logs/screened_urls', {into: 'adminLogs'}); + this.render('admin/templates/logs/screened-urls', {into: 'adminLogs'}); }, setupController: function() { diff --git a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 index 6ef900e8436..48d04abc5f7 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 @@ -3,7 +3,7 @@ import showModal from 'discourse/lib/show-modal'; export default Discourse.Route.extend({ // TODO: make this automatic using an `{{outlet}}` renderTemplate: function() { - this.render('admin/templates/logs/staff_action_logs', {into: 'adminLogs'}); + this.render('admin/templates/logs/staff-action-logs', {into: 'adminLogs'}); }, setupController: function(controller) { @@ -13,13 +13,18 @@ export default Discourse.Route.extend({ actions: { showDetailsModal(model) { - showModal('modals/admin-staff-action-log-details', { model }); + showModal('admin-staff-action-log-details', { model, admin: true }); this.controllerFor('modal').set('modalClass', 'log-details-modal'); }, showCustomDetailsModal(model) { - const modalName = "modals/" + (model.action_name + '_details').replace("_", "-"); - showModal(modalName, { model }); + const modalName = (model.action_name + '_details').replace(/\_/g, "-"); + + showModal(modalName, { + model, + admin: true, + templateName: 'site-customization-change' + }); this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal'); } } diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 index 8c1f988af37..bd38784bb7f 100644 --- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 @@ -1,13 +1,11 @@ -export default { - resource: 'admin', - - map() { +export default function() { + this.route('admin', { resetNamespace: true }, function() { this.route('dashboard', { path: '/' }); - this.resource('adminSiteSettings', { path: '/site_settings' }, function() { - this.resource('adminSiteSettingsCategory', { path: 'category/:category_id'} ); + this.route('adminSiteSettings', { path: '/site_settings', resetNamespace: true }, function() { + this.route('adminSiteSettingsCategory', { path: 'category/:category_id', resetNamespace: true} ); }); - this.resource('adminEmail', { path: '/email'}, function() { + this.route('adminEmail', { path: '/email', resetNamespace: true}, function() { this.route('sent'); this.route('skipped'); this.route('bounced'); @@ -16,65 +14,77 @@ export default { this.route('previewDigest', { path: '/preview-digest' }); }); - this.resource('adminCustomize', { path: '/customize' } ,function() { + this.route('adminCustomize', { path: '/customize', resetNamespace: true } ,function() { this.route('colors'); - this.resource('adminCustomizeCssHtml', { path: 'css_html' }, function() { + this.route('adminCustomizeCssHtml', { path: 'css_html', resetNamespace: true }, function() { this.route('show', {path: '/:site_customization_id/:section'}); }); - this.resource('adminSiteText', { path: '/site_texts' }, function() { + this.route('adminSiteText', { path: '/site_texts', resetNamespace: true }, function() { this.route('edit', { path: '/:id' }); }); - this.resource('adminUserFields', { path: '/user_fields' }); - this.resource('adminEmojis', { path: '/emojis' }); - this.resource('adminPermalinks', { path: '/permalinks' }); - this.resource('adminEmbedding', { path: '/embedding' }); - this.resource('adminCustomizeEmailTemplates', { path: '/email_templates' }, function() { + this.route('adminUserFields', { path: '/user_fields', resetNamespace: true }); + this.route('adminEmojis', { path: '/emojis', resetNamespace: true }); + this.route('adminPermalinks', { path: '/permalinks', resetNamespace: true }); + this.route('adminEmbedding', { path: '/embedding', resetNamespace: true }); + this.route('adminCustomizeEmailTemplates', { path: '/email_templates', resetNamespace: true }, function() { this.route('edit', { path: '/:id' }); }); }); - this.route('api'); - this.resource('admin.backups', { path: '/backups' }, function() { + this.route('adminApi', { path: '/api', resetNamespace: true }, function() { + this.route('adminApiKeys', { path: '/keys', resetNamespace: true }); + + this.route('adminWebHooks', { path: '/web_hooks', resetNamespace: true }, function() { + this.route('show', { path: '/:web_hook_id' }); + this.route('showEvents', { path: '/:web_hook_id/events' }); + }); + }); + + this.route('admin.backups', { path: '/backups', resetNamespace: true }, function() { this.route('logs'); }); - this.resource('adminReports', { path: '/reports/:type' }); + this.route('adminReports', { path: '/reports/:type', resetNamespace: true }); - this.resource('adminFlags', { path: '/flags' }, function() { + this.route('adminFlags', { path: '/flags', resetNamespace: true }, function() { this.route('list', { path: '/:filter' }); }); - this.resource('adminLogs', { path: '/logs' }, function() { + this.route('adminLogs', { path: '/logs', resetNamespace: true }, 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.route('adminGroups', { path: '/groups', resetNamespace: true }, function() { this.route('bulk'); this.route('bulkComplete', { path: 'bulk-complete' }); - this.resource('adminGroupsType', { path: '/:type' }, function() { - this.resource('adminGroup', { path: '/:name' }); + this.route('adminGroupsType', { path: '/:type', resetNamespace: true }, function() { + this.route('adminGroup', { path: '/:name', resetNamespace: true }); }); }); - this.resource('adminUsers', { path: '/users' }, function() { - this.resource('adminUser', { path: '/:user_id/:username' }, function() { + this.route('adminUsers', { path: '/users', resetNamespace: true }, function() { + this.route('adminUser', { path: '/:user_id/:username', resetNamespace: true }, function() { this.route('badges'); this.route('tl3Requirements', { path: '/tl3_requirements' }); }); - this.resource('adminUsersList', { path: '/list' }, function() { + this.route('adminUsersList', { path: '/list', resetNamespace: true }, function() { this.route('show', { path: '/:filter' }); }); }); - this.resource('adminBadges', { path: '/badges' }, function() { + this.route('adminBadges', { path: '/badges', resetNamespace: true }, function() { this.route('show', { path: '/:badge_id' }); }); - } + + this.route('adminPlugins', { path: '/plugins', resetNamespace: true }, function() { + this.route('index', { path: '/' }); + }); + }); }; diff --git a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 index 5a3afa10caa..c10e5957d5a 100644 --- a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 @@ -26,7 +26,7 @@ export default Discourse.Route.extend({ actions: { showSuspendModal(model) { - showModal('modals/admin-suspend-user', { model }); + showModal('admin-suspend-user', { model, admin: true }); this.controllerFor('modal').set('modalClass', 'suspend-user-modal'); } } diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 new file mode 100644 index 00000000000..c9700db463c --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 @@ -0,0 +1,18 @@ +export default Discourse.Route.extend({ + model(params) { + return this.store.findAll('web-hook-event', Ember.get(params, 'web_hook_id')); + }, + + setupController(controller, model) { + controller.set('model', model); + controller.subscribe(); + }, + + deactivate() { + this.controllerFor('adminWebHooks.showEvents').unsubscribe(); + }, + + renderTemplate() { + this.render('admin/templates/web-hooks-show-events', { into: 'adminApi' }); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 new file mode 100644 index 00000000000..51b7d55d47c --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 @@ -0,0 +1,26 @@ +export default Discourse.Route.extend({ + serialize(model) { + return { web_hook_id: model.get('id') || 'new' }; + }, + + model(params) { + if (params.web_hook_id === 'new') { + return this.store.createRecord('web-hook'); + } + return this.store.find('web-hook', Ember.get(params, 'web_hook_id')); + }, + + setupController(controller, model) { + if (model.get('isNew') || Ember.isEmpty(model.get('web_hook_event_types'))) { + model.set('web_hook_event_types', controller.get('defaultEventTypes')); + } + + model.set('category_ids', model.get('category_ids')); + model.set('group_ids', model.get('group_ids')); + controller.setProperties({ model, saved: false }); + }, + + renderTemplate() { + this.render('admin/templates/web-hooks-show', { into: 'adminApi' }); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 new file mode 100644 index 00000000000..69d7b4bd202 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 @@ -0,0 +1,15 @@ +export default Ember.Route.extend({ + model() { + return this.store.findAll('web-hook'); + }, + + setupController(controller, model) { + controller.setProperties({ + model, + eventTypes: model.extras.event_types, + defaultEventTypes: model.extras.default_event_types, + contentTypes: model.extras.content_types, + deliveryStatuses: model.extras.delivery_statuses + }); + } +}); diff --git a/app/assets/javascripts/admin/templates/admin.hbs b/app/assets/javascripts/admin/templates/admin.hbs index 13afd577f77..7f34c00b772 100644 --- a/app/assets/javascripts/admin/templates/admin.hbs +++ b/app/assets/javascripts/admin/templates/admin.hbs @@ -1,4 +1,4 @@ -
+{{#disable-custom-stylesheets class="container"}}
@@ -19,11 +19,11 @@ {{nav-item route='adminLogs' label='admin.logs.title'}} {{#if currentUser.admin}} {{nav-item route='adminCustomize' label='admin.customize.title'}} - {{nav-item route='admin.api' label='admin.api.title'}} + {{nav-item route='adminApi' label='admin.api.title'}} {{nav-item route='admin.backups' label='admin.backups.title'}} {{/if}} {{nav-item route='adminPlugins' label='admin.plugins.title'}} - {{plugin-outlet "admin-menu" tagName="li"}} + {{plugin-outlet name="admin-menu" connectorTagName="li"}}
@@ -34,4 +34,4 @@
-
+{{/disable-custom-stylesheets}} diff --git a/app/assets/javascripts/admin/templates/api-keys.hbs b/app/assets/javascripts/admin/templates/api-keys.hbs new file mode 100644 index 00000000000..60449052bb9 --- /dev/null +++ b/app/assets/javascripts/admin/templates/api-keys.hbs @@ -0,0 +1,33 @@ +{{#if model}} + + + + + + + {{#each model as |k|}} + + + + + + {{/each}} +
{{i18n 'admin.api.key'}}{{i18n 'admin.api.user'}} 
{{k.key}} + {{#if k.user}} + {{#link-to 'adminUser' k.user}} + {{avatar k.user imageSize="small"}} + {{/link-to}} + {{else}} + {{i18n 'admin.api.all_users'}} + {{/if}} + + {{d-button action="regenerateKey" actionParam=k icon="undo" label='admin.api.regenerate'}} + {{d-button action="revokeKey" actionParam=k icon="times" label='admin.api.revoke'}} +
+{{else}} +

{{i18n 'admin.api.none'}}

+{{/if}} + +{{#unless hasMasterKey}} + +{{/unless}} diff --git a/app/assets/javascripts/admin/templates/api.hbs b/app/assets/javascripts/admin/templates/api.hbs index 0f2e65b89c3..f3407fe0ccf 100644 --- a/app/assets/javascripts/admin/templates/api.hbs +++ b/app/assets/javascripts/admin/templates/api.hbs @@ -1,33 +1,10 @@ -{{#if model}} - - - - - - - {{#each model as |k|}} - - - - - - {{/each}} -
{{i18n 'admin.api.key'}}{{i18n 'admin.api.user'}} 
{{k.key}} - {{#if k.user}} - {{#link-to 'adminUser' k.user}} - {{avatar k.user imageSize="small"}} - {{/link-to}} - {{else}} - {{i18n 'admin.api.all_users'}} - {{/if}} - - - -
-{{else}} -

{{i18n 'admin.api.none'}}

-{{/if}} +
+ {{#admin-nav}} + {{nav-item route='adminApiKeys' label='admin.api.title'}} + {{nav-item route='adminWebHooks' label='admin.web_hooks.title'}} + {{/admin-nav}} -{{#unless hasMasterKey}} - -{{/unless }} +
+ {{outlet}} +
+
diff --git a/app/assets/javascripts/admin/templates/backups_index.hbs b/app/assets/javascripts/admin/templates/backups-index.hbs similarity index 62% rename from app/assets/javascripts/admin/templates/backups_index.hbs rename to app/assets/javascripts/admin/templates/backups-index.hbs index c7323ebea02..a8220a4e1ac 100644 --- a/app/assets/javascripts/admin/templates/backups_index.hbs +++ b/app/assets/javascripts/admin/templates/backups-index.hbs @@ -6,9 +6,9 @@
{{resumable-upload target="/admin/backups/upload" success="uploadSuccess" error="uploadError" uploadText=uploadLabel title="admin.backups.upload.title"}} {{#if site.isReadOnly}} - {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}} + {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.isOperationRunning title="admin.backups.read_only.disable.title" label="admin.backups.read_only.disable.label"}} {{else}} - {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.model.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}} + {{d-button icon="eye" action="toggleReadOnlyMode" disabled=status.isOperationRunning title="admin.backups.read_only.enable.title" label="admin.backups.read_only.enable.label"}} {{/if}}
@@ -19,13 +19,18 @@ {{human-size backup.size}}
- {{fa-icon "download"}}{{i18n 'admin.backups.operations.download.label'}} - {{#if status.model.isOperationRunning}} + {{d-button class="download" + action="download" + actionParam=backup + icon="download" + title="admin.backups.operations.download.title" + label="admin.backups.operations.download.label"}} + {{#if status.isOperationRunning}} {{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" disabled="true" title="admin.backups.operations.is_running"}} - {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}} + {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}} {{else}} {{d-button icon="trash-o" action="destroyBackup" actionParam=backup class="btn-danger" title="admin.backups.operations.destroy.title"}} - {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.model.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}} + {{d-button icon="play" action="startRestore" actionParam=backup disabled=status.restoreDisabled title=restoreTitle label="admin.backups.operations.restore.label"}} {{/if}}
diff --git a/app/assets/javascripts/admin/templates/backups-logs.hbs b/app/assets/javascripts/admin/templates/backups-logs.hbs new file mode 100644 index 00000000000..34ec15f84a7 --- /dev/null +++ b/app/assets/javascripts/admin/templates/backups-logs.hbs @@ -0,0 +1 @@ +{{admin-backups-logs logs=logs status=status}} diff --git a/app/assets/javascripts/admin/templates/backups.hbs b/app/assets/javascripts/admin/templates/backups.hbs index 7562754c08c..ea8bc189873 100644 --- a/app/assets/javascripts/admin/templates/backups.hbs +++ b/app/assets/javascripts/admin/templates/backups.hbs @@ -1,35 +1,37 @@ -
-
- +
+
+
+ +
+
+ {{#if model.canRollback}} + {{d-button action="rollback" + class="btn-rollback" + label="admin.backups.operations.rollback.label" + title="admin.backups.operations.rollback.title" + icon="ambulance" + disabled=rollbackDisabled}} + {{/if}} + {{#if model.isOperationRunning}} + {{d-button action="cancelOperation" + class="btn-danger" + title="admin.backups.operations.cancel.title" + label="admin.backups.operations.cancel.label" + icon="times"}} + {{else}} + {{d-button action="startBackup" + class="btn-primary" + title="admin.backups.operations.backup.title" + label="admin.backups.operations.backup.label" + icon="rocket"}} + {{/if}} +
-
- {{#if model.canRollback}} - {{d-button action="rollback" - class="btn-rollback" - label="admin.backups.operations.rollback.label" - title="admin.backups.operations.rollback.title" - icon="ambulance" - disabled=rollbackDisabled}} - {{/if}} - {{#if model.isOperationRunning}} - {{d-button action="cancelOperation" - class="btn-danger" - title="admin.backups.operations.cancel.title" - label="admin.backups.operations.cancel.label" - icon="times"}} - {{else}} - {{d-button action="startBackup" - class="btn-primary" - title="admin.backups.operations.backup.title" - label="admin.backups.operations.backup.label" - icon="rocket"}} - {{/if}} -
-
-
- {{outlet}} +
+ {{outlet}} +
diff --git a/app/assets/javascripts/admin/templates/badges-index.hbs b/app/assets/javascripts/admin/templates/badges-index.hbs index 6ee80748f81..c94f59fe105 100644 --- a/app/assets/javascripts/admin/templates/badges-index.hbs +++ b/app/assets/javascripts/admin/templates/badges-index.hbs @@ -1,4 +1,4 @@ -
+{{#d-section class="current-badge span13"}}

{{i18n 'admin.badges.none_selected'}}

@@ -6,4 +6,4 @@ {{fa-icon "plus"}} {{i18n 'admin.badges.new'}} {{/link-to}}
-
+{{/d-section}} diff --git a/app/assets/javascripts/admin/templates/badges-show.hbs b/app/assets/javascripts/admin/templates/badges-show.hbs index f29829eba55..e0ae7001df0 100644 --- a/app/assets/javascripts/admin/templates/badges-show.hbs +++ b/app/assets/javascripts/admin/templates/badges-show.hbs @@ -1,4 +1,4 @@ -
+{{#d-section class="current-badge span13"}}
@@ -143,7 +143,7 @@ {{/unless}}
-
+{{/d-section}} {{#if grant_count}}
diff --git a/app/assets/javascripts/admin/templates/components/ace-editor.hbs b/app/assets/javascripts/admin/templates/components/ace-editor.hbs new file mode 100644 index 00000000000..c837b2b34ee --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/ace-editor.hbs @@ -0,0 +1 @@ +
{{content}}
diff --git a/app/assets/javascripts/admin/templates/components/admin-web-hook-event-chooser.hbs b/app/assets/javascripts/admin/templates/components/admin-web-hook-event-chooser.hbs new file mode 100644 index 00000000000..0ecb553d38e --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/admin-web-hook-event-chooser.hbs @@ -0,0 +1,3 @@ +{{input id=typeName type="checkbox" name="event-choice" checked=enabled}} + +

{{details}}

diff --git a/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs new file mode 100644 index 00000000000..026b6daae27 --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs @@ -0,0 +1,19 @@ +
+ {{model.status}} +
+
{{model.id}}
+
{{createdAt}}
+
{{completion}}
+
+ {{d-button icon='ellipsis-v' action='toggleRequest' label='admin.web_hooks.events.request'}} + {{d-button icon='ellipsis-v' action='toggleResponse' label='admin.web_hooks.events.response'}} + {{d-button icon='refresh' action='redeliver' label='admin.web_hooks.events.redeliver'}} +
+{{#if expandDetails}} +
+

{{i18n 'admin.web_hooks.events.headers'}}

+
{{headers}}
+

{{bodyLabel}}

+
{{body}}
+
+{{/if}} diff --git a/app/assets/javascripts/admin/templates/components/embeddable-host.hbs b/app/assets/javascripts/admin/templates/components/embeddable-host.hbs index c35d40e1d6e..5f2581138f5 100644 --- a/app/assets/javascripts/admin/templates/components/embeddable-host.hbs +++ b/app/assets/javascripts/admin/templates/components/embeddable-host.hbs @@ -2,6 +2,9 @@ {{input value=buffered.host placeholder="example.com" enter="save" class="host-name"}} + + {{input value=buffered.path_whitelist placeholder="/blog/.*" enter="save" class="path-whitelist"}} + {{category-chooser value=categoryId}} @@ -11,6 +14,7 @@ {{else}} {{host.host}} + {{host.path_whitelist}} {{category-badge host.category}} {{d-button icon="pencil" action="edit"}} diff --git a/app/assets/javascripts/admin/templates/components/permalink-form.hbs b/app/assets/javascripts/admin/templates/components/permalink-form.hbs index 987a1bc9185..c7942543316 100644 --- a/app/assets/javascripts/admin/templates/components/permalink-form.hbs +++ b/app/assets/javascripts/admin/templates/components/permalink-form.hbs @@ -2,4 +2,4 @@ {{text-field value=url disabled=formSubmitted class="permalink-url" placeholderKey="admin.permalink.url" autocorrect="off" autocapitalize="off"}} {{combo-box content=permalinkTypes value=permalinkType}} {{text-field value=permalink_type_value disabled=formSubmitted class="external-url" placeholderKey=permalinkTypePlaceholder autocorrect="off" autocapitalize="off"}} - +{{d-button action="submit" disabled=formSubmitted label="admin.permalink.form.add"}} diff --git a/app/assets/javascripts/admin/templates/components/permalinks-list.hbs b/app/assets/javascripts/admin/templates/components/permalinks-list.hbs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/assets/javascripts/admin/templates/components/site-customization-change-details.hbs b/app/assets/javascripts/admin/templates/components/site-customization-change-details.hbs new file mode 100644 index 00000000000..a9ea9cea094 --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/site-customization-change-details.hbs @@ -0,0 +1,18 @@ +
+ {{i18n 'admin.customize.enabled'}}: {{change.enabled}} +
+ +{{site-customization-change-field field=change.stylesheet name="admin.customize.css"}} +{{site-customization-change-field icon="mobile" field=change.mobile_stylesheet name="admin.customize.css"}} + +{{site-customization-change-field field=change.header name="admin.customize.header"}} +{{site-customization-change-field icon="mobile" field=change.mobile_header name="admin.customize.header"}} + +{{site-customization-change-field field=change.top name="admin.customize.top"}} +{{site-customization-change-field icon="mobile" field=change.mobile_top name="admin.customize.top"}} + +{{site-customization-change-field field=change.footer name="admin.customize.footer"}} +{{site-customization-change-field icon="mobile" field=change.mobile_footer name="admin.customize.footer"}} + +{{site-customization-change-field icon="file-text-o" field=change.head_tag name="admin.customize.head_tag.text"}} +{{site-customization-change-field icon="file-text-o" field=change.body_tag name="admin.customize.body_tag.text"}} diff --git a/app/assets/javascripts/admin/templates/components/site-customization-change-field.hbs b/app/assets/javascripts/admin/templates/components/site-customization-change-field.hbs new file mode 100644 index 00000000000..43aea18163f --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/site-customization-change-field.hbs @@ -0,0 +1,7 @@ +{{#if field}} +
+ {{i18n name}}: ({{i18n 'character_count' count=field.length}}) +
+ {{textarea value=field class="plain"}} +
+{{/if}} diff --git a/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs b/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs index 621f3fa70e7..8c0b4eda1e9 100644 --- a/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs +++ b/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs @@ -1,3 +1,3 @@ -{{category-group categories=selectedCategories blacklist=selectedCategories}} +{{category-selector categories=selectedCategories blacklist=selectedCategories}}
{{{unbound setting.description}}}
{{setting-validation-message message=validationMessage}} diff --git a/app/assets/javascripts/admin/templates/customize_colors.hbs b/app/assets/javascripts/admin/templates/customize-colors.hbs similarity index 100% rename from app/assets/javascripts/admin/templates/customize_colors.hbs rename to app/assets/javascripts/admin/templates/customize-colors.hbs diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index e02a5a925ca..ec7753ac6c9 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -1,4 +1,4 @@ -{{plugin-outlet "admin-dashboard-top"}} +{{plugin-outlet name="admin-dashboard-top"}} {{#conditional-loading-spinner condition=loading}}
diff --git a/app/assets/javascripts/admin/templates/email_index.hbs b/app/assets/javascripts/admin/templates/email-index.hbs similarity index 100% rename from app/assets/javascripts/admin/templates/email_index.hbs rename to app/assets/javascripts/admin/templates/email-index.hbs diff --git a/app/assets/javascripts/admin/templates/email_preview_digest.hbs b/app/assets/javascripts/admin/templates/email-preview-digest.hbs similarity index 50% rename from app/assets/javascripts/admin/templates/email_preview_digest.hbs rename to app/assets/javascripts/admin/templates/email-preview-digest.hbs index 7bd2a4455f1..80f48717b02 100644 --- a/app/assets/javascripts/admin/templates/email_preview_digest.hbs +++ b/app/assets/javascripts/admin/templates/email-preview-digest.hbs @@ -19,9 +19,36 @@
{{#conditional-loading-spinner condition=loading}} - {{#if showHtml}} - {{{model.html_content}}} - {{else}} -
{{{model.text_content}}}
+ +