Merge master
@ -6,9 +6,6 @@ app/assets/javascripts/ember-addons/
|
||||
app/assets/javascripts/discourse/lib/autosize.js.es6
|
||||
lib/javascripts/locale/
|
||||
lib/javascripts/messageformat.js
|
||||
lib/javascripts/moment.js
|
||||
lib/javascripts/moment-timezone-with-data.js
|
||||
lib/javascripts/moment_locale/
|
||||
lib/highlight_js/
|
||||
plugins/**/lib/javascripts/locale
|
||||
public/javascripts/
|
||||
|
17
.eslintrc
@ -5,7 +5,7 @@
|
||||
"es6": true,
|
||||
"jasmine": true,
|
||||
"mocha": true,
|
||||
"node": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 7,
|
||||
@ -16,12 +16,11 @@
|
||||
"_": true,
|
||||
"andThen": true,
|
||||
"asyncRender": true,
|
||||
"asyncTestDiscourse": true,
|
||||
"Blob": true,
|
||||
"bootbox": true,
|
||||
"click": true,
|
||||
"collapseSelectKit": true,
|
||||
"controllerFor": true,
|
||||
"waitUntil": true,
|
||||
"getSettledState": true,
|
||||
"count": true,
|
||||
"currentPath": true,
|
||||
"currentRouteName": true,
|
||||
@ -30,11 +29,9 @@
|
||||
"Discourse": true,
|
||||
"Ember": true,
|
||||
"exists": true,
|
||||
"expandSelectKit": true,
|
||||
"File": true,
|
||||
"fillIn": true,
|
||||
"find": true,
|
||||
"fixture": true,
|
||||
"Handlebars": true,
|
||||
"hasModule": true,
|
||||
"I18n": true,
|
||||
@ -51,12 +48,6 @@
|
||||
"requirejs": true,
|
||||
"RSVP": true,
|
||||
"sandbox": true,
|
||||
"selectKit": true,
|
||||
"selectKitFillInFilter": true,
|
||||
"selectKitSelectNoneRow": true,
|
||||
"selectKitSelectRowByIndex": true,
|
||||
"selectKitSelectRowByName": true,
|
||||
"selectKitSelectRowByValue": true,
|
||||
"sinon": true,
|
||||
"test": true,
|
||||
"triggerEvent": true,
|
||||
@ -99,7 +90,7 @@
|
||||
"semi": 2,
|
||||
"strict": 0,
|
||||
"valid-typeof": 2,
|
||||
"wrap-iife": [2, "inside"],
|
||||
"wrap-iife": [2, "inside"]
|
||||
},
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
3
.gitignore
vendored
@ -124,3 +124,6 @@ vendor/bundle/*
|
||||
/package-lock.json
|
||||
|
||||
/vendor/data/GeoLite2-City.mmdb
|
||||
|
||||
# Vagrant
|
||||
.vagrant
|
||||
|
@ -2,4 +2,5 @@ app/assets/stylesheets/vendor/
|
||||
plugins/**/assets/stylesheets/vendor/
|
||||
package.json
|
||||
config/locales/**/*.yml
|
||||
!config/locales/**/*.en.yml
|
||||
!config/locales/**/*.en*.yml
|
||||
script/import_scripts/**/*.yml
|
||||
|
4
.rspec_parallel
Normal file
@ -0,0 +1,4 @@
|
||||
--format progress
|
||||
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
|
||||
--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log
|
||||
--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
|
@ -7,11 +7,15 @@ AllCops:
|
||||
- 'vendor/**/*'
|
||||
- 'node_modules/**/*'
|
||||
- 'public/**/*'
|
||||
- 'plugins/**/*'
|
||||
|
||||
# Prefer &&/|| over and/or.
|
||||
Style/AndOr:
|
||||
Enabled: true
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: true
|
||||
|
||||
# Do not use braces for hash literals when they are the last argument of a
|
||||
# method call.
|
||||
Style/BracesAroundHashParameters:
|
||||
|
@ -1 +1 @@
|
||||
2.5.3
|
||||
2.6.1
|
||||
|
10
.travis.yml
@ -34,7 +34,7 @@ matrix:
|
||||
fast_finish: true
|
||||
|
||||
rvm:
|
||||
- 2.5.3
|
||||
- 2.6.3
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
@ -68,14 +68,14 @@ install:
|
||||
- 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"
|
||||
- bash -c "if [ '$QUNIT_RUN' == '1' ] || [ '$RUN_LINT' == '1' ]; then yarn install --dev; fi"
|
||||
- bash -c "if [ '$RUN_LINT' != '1' ]; then LOAD_PLUGINS=1 bundle exec rake db:create db:migrate; fi"
|
||||
- bash -c "if [ '$RUN_LINT' != '1' ]; then bundle exec rake db:create && LOAD_PLUGINS=1 bundle exec rake db:migrate; fi"
|
||||
|
||||
script:
|
||||
- |
|
||||
bash -c "
|
||||
if [ '$RUN_LINT' == '1' ]; then
|
||||
bundle exec rubocop --parallel && \
|
||||
bundle exec danger && \
|
||||
yarn prettier --list-different "app/assets/stylesheets/**/*.scss" "app/assets/javascripts/**/*.es6" "test/javascripts/**/*.es6"
|
||||
yarn eslint --ext .es6 app/assets/javascripts && \
|
||||
yarn eslint --ext .es6 test/javascripts && \
|
||||
yarn eslint --ext .es6 plugins/**/assets/javascripts && \
|
||||
@ -83,8 +83,8 @@ script:
|
||||
yarn eslint app/assets/javascripts test/javascripts
|
||||
else
|
||||
if [ '$QUNIT_RUN' == '1' ]; then
|
||||
bundle exec rake qunit:test['500000'] && \
|
||||
bundle exec rake qunit:test['500000','/wizard/qunit'] && \
|
||||
bundle exec rake qunit:test['1200000'] && \
|
||||
bundle exec rake qunit:test['1200000','/wizard/qunit'] && \
|
||||
bundle exec rake plugin:qunit
|
||||
else
|
||||
bundle exec rspec && bundle exec rake plugin:spec
|
||||
|
2
Brewfile
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Install development dependencies on Mac OS X using Homebrew (http://mxcl.github.com/homebrew)
|
||||
|
||||
# you probably already have git installed; ensure that it is the latest version
|
||||
|
39
Dangerfile
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
if github.pr_json && (github.pr_json["additions"] || 0) > 250 || (github.pr_json["deletions"] || 0) > 250
|
||||
warn("This pull request is big! We prefer smaller PRs whenever possible, as they are easier to review. Can this be split into a few smaller PRs?")
|
||||
end
|
||||
@ -11,8 +13,8 @@ This PR doesn't match our required code formatting standards, as enforced by pre
|
||||
})
|
||||
end
|
||||
|
||||
locales_changes = git.modified_files.grep(/config\/locales/)
|
||||
has_non_en_locales_changes = locales_changes.grep_v(/config\/locales\/(client|server)\.en\.yml/).any?
|
||||
locales_changes = git.modified_files.grep(%r{config/locales})
|
||||
has_non_en_locales_changes = locales_changes.grep_v(%r{config/locales/(?:client|server)\.(?:en|en_US)\.yml}).any?
|
||||
|
||||
if locales_changes.any? && has_non_en_locales_changes
|
||||
fail("Please submit your non-English translation updates via [Transifex](https://www.transifex.com/discourse/discourse-org/). You can read more on how to contribute translations [here](https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882).")
|
||||
@ -22,21 +24,50 @@ files = (git.added_files + git.modified_files)
|
||||
.select { |path| !path.start_with?("plugins/") }
|
||||
.select { |path| path.end_with?("es6") || path.end_with?("rb") }
|
||||
|
||||
super_offenses = []
|
||||
js_files = files.select { |path| path.end_with?(".js.es6") }
|
||||
js_test_files = js_files.select { |path| path.end_with?("-test.js.es6") }
|
||||
|
||||
files.each do |path|
|
||||
super_offenses = []
|
||||
self_offenses = []
|
||||
js_files.each do |path|
|
||||
diff = git.diff_for_file(path)
|
||||
|
||||
next if !diff
|
||||
|
||||
diff.patch.lines.grep(/^\+\s\s/).each do |added_line|
|
||||
super_offenses << path if added_line['this._super()']
|
||||
self_offenses << path if added_line[/(?:(^|\W)self\.?)/]
|
||||
end
|
||||
end
|
||||
|
||||
jquery_find_offenses = []
|
||||
js_test_files.each do |path|
|
||||
diff = git.diff_for_file(path)
|
||||
|
||||
next if !diff
|
||||
|
||||
diff.patch.lines.grep(/^\+\s\s/).each do |added_line|
|
||||
jquery_find_offenses << path if added_line['this.$(']
|
||||
end
|
||||
end
|
||||
|
||||
if !self_offenses.empty?
|
||||
warn(%{
|
||||
Use fat arrow instead of self pattern.\n
|
||||
#{self_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
||||
if !super_offenses.empty?
|
||||
warn(%{
|
||||
When possible use `this._super(...arguments)` instead of `this._super()`\n
|
||||
#{super_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
||||
if !jquery_find_offenses.empty?
|
||||
warn(%{
|
||||
Use `find()` instead of `this.$` in js tests`\n
|
||||
#{jquery_find_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
65
Gemfile
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
# if there is a super emergency and rubygems is playing up, try
|
||||
#source 'http://production.cf.rubygems.org'
|
||||
@ -11,46 +13,49 @@ end
|
||||
if rails_master?
|
||||
gem 'arel', git: 'https://github.com/rails/arel.git'
|
||||
gem 'rails', git: 'https://github.com/rails/rails.git'
|
||||
gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse'
|
||||
else
|
||||
# until rubygems gives us optional dependencies we are stuck with this
|
||||
# bundle update actionmailer actionpack actionview activemodel activerecord activesupport railties
|
||||
gem 'actionmailer', '5.2.2.1'
|
||||
gem 'actionpack', '5.2.2.1'
|
||||
gem 'actionview', '5.2.2.1'
|
||||
gem 'activemodel', '5.2.2.1'
|
||||
gem 'activerecord', '5.2.2.1'
|
||||
gem 'activesupport', '5.2.2.1'
|
||||
gem 'railties', '5.2.2.1'
|
||||
gem 'actionmailer', '5.2.3'
|
||||
gem 'actionpack', '5.2.3'
|
||||
gem 'actionview', '5.2.3'
|
||||
gem 'activemodel', '5.2.3'
|
||||
gem 'activerecord', '5.2.3'
|
||||
gem 'activesupport', '5.2.3'
|
||||
gem 'railties', '5.2.3'
|
||||
gem 'sprockets-rails'
|
||||
gem 'seed-fu'
|
||||
end
|
||||
|
||||
gem 'mail', '2.7.1.rc1', require: false
|
||||
gem 'seed-fu'
|
||||
|
||||
gem 'mail', require: false
|
||||
gem 'mini_mime'
|
||||
gem 'mini_suffix'
|
||||
|
||||
gem 'hiredis'
|
||||
gem 'redis', require: ["redis", "redis/connection/hiredis"]
|
||||
|
||||
# holding off redis upgrade temporarily as it is having issues with our current
|
||||
# freedom patch, we will follow this up.
|
||||
#
|
||||
# FrozenError: can't modify frozen Hash
|
||||
# /var/www/discourse/vendor/bundle/ruby/2.5.0/gems/redis-4.1.0/lib/redis/client.rb:93:in `delete'
|
||||
# /var/www/discourse/vendor/bundle/ruby/2.5.0/gems/redis-4.1.0/lib/redis/client.rb:93:in `initialize'
|
||||
# /var/www/discourse/lib/freedom_patches/redis.rb:7:in `initialize'
|
||||
gem 'redis', '4.0.1', require: ["redis", "redis/connection/hiredis"]
|
||||
gem 'redis-namespace'
|
||||
|
||||
gem 'active_model_serializers', '~> 0.8.3'
|
||||
|
||||
gem 'onebox', '1.8.77'
|
||||
gem 'onebox', '1.8.92'
|
||||
|
||||
gem 'http_accept_language', '~>2.0.5', require: false
|
||||
|
||||
gem 'ember-rails', '0.18.5'
|
||||
gem 'discourse-ember-source', '~> 3.5.1'
|
||||
gem 'discourse-ember-source', '~> 3.8.0'
|
||||
gem 'ember-handlebars-template', '0.8.0'
|
||||
gem 'barber'
|
||||
|
||||
# message bus 2.2.0 should be very stable
|
||||
# we trimmed some of the internal API surface down so we went with
|
||||
# a pre release here to make we don't do a full release prior to
|
||||
# baking here. Remove 2.2.0.pre no later than Jan 2019 and move back
|
||||
# to the standard releases
|
||||
gem 'message_bus', '2.2.0.pre.1'
|
||||
gem 'message_bus'
|
||||
|
||||
gem 'rails_multisite'
|
||||
|
||||
@ -62,6 +67,7 @@ gem 'fast_xor', platform: :mri
|
||||
gem 'fastimage'
|
||||
|
||||
gem 'aws-sdk-s3', require: false
|
||||
gem 'aws-sdk-sns', require: false
|
||||
gem 'excon', require: false
|
||||
gem 'unf', require: false
|
||||
|
||||
@ -84,6 +90,7 @@ gem 'omniauth-github'
|
||||
gem 'omniauth-oauth2', require: false
|
||||
|
||||
gem 'omniauth-google-oauth2'
|
||||
|
||||
gem 'oj'
|
||||
gem 'pg'
|
||||
gem 'mini_sql'
|
||||
@ -92,6 +99,7 @@ gem 'r2', '~> 0.2.5', require: false
|
||||
gem 'rake'
|
||||
|
||||
gem 'thor', require: false
|
||||
gem 'diffy', require: false
|
||||
gem 'rinku'
|
||||
gem 'sanitize'
|
||||
gem 'sidekiq'
|
||||
@ -116,7 +124,8 @@ group :test do
|
||||
gem 'webmock', require: false
|
||||
gem 'fakeweb', '~> 1.3.0', require: false
|
||||
gem 'minitest', require: false
|
||||
gem 'danger'
|
||||
gem 'simplecov', require: false
|
||||
gem "test-prof"
|
||||
end
|
||||
|
||||
group :test, :development do
|
||||
@ -130,11 +139,12 @@ group :test, :development do
|
||||
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
|
||||
gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
|
||||
gem 'rspec-rails', require: false
|
||||
gem 'shoulda', require: false
|
||||
gem 'shoulda-matchers', '~> 3.1', '>= 3.1.3', require: false
|
||||
gem 'rspec-html-matchers'
|
||||
gem 'pry-nav'
|
||||
gem 'byebug', require: ENV['RM_INFO'].nil?
|
||||
gem 'rubocop', require: false
|
||||
gem 'parallel_tests'
|
||||
end
|
||||
|
||||
group :development do
|
||||
@ -142,8 +152,13 @@ group :development do
|
||||
gem 'bullet', require: !!ENV['BULLET']
|
||||
gem 'better_errors'
|
||||
gem 'binding_of_caller'
|
||||
gem 'annotate'
|
||||
gem 'foreman', require: false
|
||||
|
||||
# waiting on 2.7.5 per: https://github.com/ctran/annotate_models/pull/595
|
||||
if rails_master?
|
||||
gem 'annotate', git: 'https://github.com/ctran/annotate_models.git'
|
||||
else
|
||||
gem 'annotate'
|
||||
end
|
||||
end
|
||||
|
||||
# this is an optional gem, it provides a high performance replacement
|
||||
@ -182,6 +197,7 @@ gem 'logstash-logger', require: false
|
||||
gem 'logster'
|
||||
|
||||
gem 'sassc', require: false
|
||||
gem "sassc-rails"
|
||||
|
||||
gem 'rotp'
|
||||
gem 'rqrcode'
|
||||
@ -193,10 +209,11 @@ gem 'rchardet', require: false
|
||||
if ENV["IMPORT"] == "1"
|
||||
gem 'mysql2'
|
||||
gem 'redcarpet'
|
||||
gem 'sqlite3', '~> 1.3.13'
|
||||
gem 'sqlite3', '~> 1.3', '>= 1.3.13'
|
||||
gem 'ruby-bbcode-to-md', git: 'https://github.com/nlalonde/ruby-bbcode-to-md'
|
||||
gem 'reverse_markdown'
|
||||
gem 'tiny_tds'
|
||||
gem 'csv', '~> 3.0'
|
||||
end
|
||||
|
||||
gem 'webpush', require: false
|
||||
|
386
Gemfile.lock
@ -1,117 +1,104 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (5.2.2.1)
|
||||
actionpack (= 5.2.2.1)
|
||||
actionview (= 5.2.2.1)
|
||||
activejob (= 5.2.2.1)
|
||||
actionmailer (5.2.3)
|
||||
actionpack (= 5.2.3)
|
||||
actionview (= 5.2.3)
|
||||
activejob (= 5.2.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (5.2.2.1)
|
||||
actionview (= 5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
actionpack (5.2.3)
|
||||
actionview (= 5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
rack (~> 2.0)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
actionview (5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
activejob (5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
activerecord (5.2.2.1)
|
||||
activemodel (= 5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
activemodel (5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
activerecord (5.2.3)
|
||||
activemodel (= 5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
arel (>= 9.0)
|
||||
activesupport (5.2.2.1)
|
||||
activesupport (5.2.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
annotate (2.7.4)
|
||||
activerecord (>= 3.2, < 6.0)
|
||||
annotate (2.7.5)
|
||||
activerecord (>= 3.2, < 7.0)
|
||||
rake (>= 10.4, < 13.0)
|
||||
arel (9.0.0)
|
||||
ast (2.4.0)
|
||||
aws-eventstream (1.0.1)
|
||||
aws-partitions (1.104.0)
|
||||
aws-sdk-core (3.27.0)
|
||||
aws-eventstream (~> 1.0)
|
||||
aws-eventstream (1.0.3)
|
||||
aws-partitions (1.154.0)
|
||||
aws-sdk-core (3.48.6)
|
||||
aws-eventstream (~> 1.0, >= 1.0.2)
|
||||
aws-partitions (~> 1.0)
|
||||
aws-sigv4 (~> 1.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.9.0)
|
||||
aws-sdk-core (~> 3, >= 3.26.0)
|
||||
aws-sigv4 (~> 1.0)
|
||||
aws-sdk-s3 (1.19.0)
|
||||
aws-sdk-core (~> 3, >= 3.26.0)
|
||||
aws-sdk-kms (1.17.0)
|
||||
aws-sdk-core (~> 3, >= 3.48.2)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.36.1)
|
||||
aws-sdk-core (~> 3, >= 3.48.2)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.0)
|
||||
aws-sigv4 (1.0.3)
|
||||
barber (0.12.0)
|
||||
aws-sdk-sns (1.13.0)
|
||||
aws-sdk-core (~> 3, >= 3.48.2)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.1.0)
|
||||
aws-eventstream (~> 1.0, >= 1.0.2)
|
||||
barber (0.12.2)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
execjs (>= 1.2, < 3)
|
||||
better_errors (2.4.0)
|
||||
better_errors (2.5.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.8.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.3.0)
|
||||
bootsnap (1.4.4)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.3)
|
||||
bullet (5.7.5)
|
||||
bullet (6.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11.0)
|
||||
byebug (10.0.2)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (11.0.1)
|
||||
certified (1.0.0)
|
||||
chunky_png (1.3.10)
|
||||
claide (1.0.2)
|
||||
claide-plugins (0.9.2)
|
||||
cork
|
||||
nap
|
||||
open4 (~> 1.3)
|
||||
chunky_png (1.3.11)
|
||||
coderay (1.1.2)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.4)
|
||||
concurrent-ruby (1.1.5)
|
||||
connection_pool (2.2.2)
|
||||
cork (0.3.0)
|
||||
colored2 (~> 3.1)
|
||||
cppjieba_rb (0.3.0)
|
||||
cppjieba_rb (0.3.3)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
crass (1.0.4)
|
||||
danger (5.11.1)
|
||||
claide (~> 1.0)
|
||||
claide-plugins (>= 0.9.2)
|
||||
colored2 (~> 3.1)
|
||||
cork (~> 0.1)
|
||||
faraday (~> 0.9)
|
||||
faraday-http-cache (~> 1.0)
|
||||
git (~> 1.5)
|
||||
kramdown (~> 1.5)
|
||||
no_proxy_fix
|
||||
octokit (~> 4.7)
|
||||
terminal-table (~> 1)
|
||||
debug_inspector (0.0.3)
|
||||
diff-lcs (1.3)
|
||||
discourse-ember-source (3.5.1.3)
|
||||
diffy (3.3.0)
|
||||
discourse-ember-source (3.8.0.1)
|
||||
discourse_image_optim (0.26.2)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
fspath (~> 3.0)
|
||||
image_size (~> 1.5)
|
||||
in_threads (~> 1.3)
|
||||
progress (~> 3.0, >= 3.0.1)
|
||||
docile (1.3.1)
|
||||
email_reply_trimmer (0.1.12)
|
||||
ember-data-source (3.0.2)
|
||||
ember-source (>= 2, < 3.0)
|
||||
@ -126,58 +113,53 @@ GEM
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
ember-source (2.18.2)
|
||||
erubi (1.7.1)
|
||||
excon (0.62.0)
|
||||
erubi (1.8.0)
|
||||
excon (0.64.0)
|
||||
execjs (2.7.0)
|
||||
exifr (1.3.4)
|
||||
exifr (1.3.6)
|
||||
fabrication (2.20.1)
|
||||
fakeweb (1.3.0)
|
||||
faraday (0.15.4)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-http-cache (1.3.1)
|
||||
faraday (~> 0.8)
|
||||
fast_blank (1.0.0)
|
||||
fast_xor (1.1.3)
|
||||
rake
|
||||
rake-compiler
|
||||
fast_xs (0.8.0)
|
||||
fastimage (2.1.3)
|
||||
ffi (1.9.25)
|
||||
fastimage (2.1.5)
|
||||
ffi (1.10.0)
|
||||
flamegraph (0.9.5)
|
||||
foreman (0.85.0)
|
||||
thor (~> 0.19.1)
|
||||
fspath (3.1.0)
|
||||
gc_tracer (1.5.1)
|
||||
git (1.5.0)
|
||||
globalid (0.4.1)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
guess_html_encoding (0.0.11)
|
||||
hashdiff (0.3.7)
|
||||
hashdiff (0.3.9)
|
||||
hashie (3.6.0)
|
||||
highline (1.7.10)
|
||||
hiredis (0.6.1)
|
||||
hiredis (0.6.3)
|
||||
hkdf (0.3.0)
|
||||
htmlentities (4.3.4)
|
||||
http_accept_language (2.0.5)
|
||||
i18n (1.1.1)
|
||||
i18n (1.6.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_size (1.5.0)
|
||||
in_threads (1.5.0)
|
||||
jaro_winkler (1.5.1)
|
||||
in_threads (1.5.1)
|
||||
jaro_winkler (1.5.2)
|
||||
jmespath (1.4.0)
|
||||
jquery-rails (4.3.3)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jwt (2.1.0)
|
||||
json (2.2.0)
|
||||
jwt (2.2.1)
|
||||
kgio (2.11.2)
|
||||
kramdown (1.17.0)
|
||||
libv8 (7.3.492.27.1)
|
||||
listen (3.1.5)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
ruby_dep (~> 1.2)
|
||||
lograge (0.10.0)
|
||||
lograge (0.11.0)
|
||||
actionpack (>= 4)
|
||||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
@ -185,44 +167,42 @@ GEM
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.0.1)
|
||||
logster (2.3.0)
|
||||
loofah (2.2.3)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
mail (2.7.1.rc1)
|
||||
mail (2.7.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
maxminddb (0.1.21)
|
||||
memory_profiler (0.9.12)
|
||||
message_bus (2.2.0.pre.1)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (0.9.13)
|
||||
message_bus (2.2.0)
|
||||
rack (>= 1.1.3)
|
||||
metaclass (0.0.4)
|
||||
method_source (0.8.2)
|
||||
method_source (0.9.2)
|
||||
mini_mime (1.0.1)
|
||||
mini_portile2 (2.4.0)
|
||||
mini_racer (0.2.5)
|
||||
mini_racer (0.2.6)
|
||||
libv8 (>= 6.9.411)
|
||||
mini_scheduler (0.9.1)
|
||||
mini_scheduler (0.9.2)
|
||||
sidekiq
|
||||
mini_sql (0.1.10)
|
||||
mini_sql (0.2.2)
|
||||
mini_suffix (0.3.0)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.11.3)
|
||||
mocha (1.5.0)
|
||||
mocha (1.8.0)
|
||||
metaclass (~> 0.0.1)
|
||||
mock_redis (0.18.0)
|
||||
moneta (1.0.0)
|
||||
msgpack (1.2.4)
|
||||
mock_redis (0.19.0)
|
||||
moneta (1.1.1)
|
||||
msgpack (1.2.10)
|
||||
multi_json (1.13.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
mustache (1.0.5)
|
||||
nap (1.1.0)
|
||||
no_proxy_fix (0.1.2)
|
||||
multipart-post (2.1.1)
|
||||
mustache (1.1.0)
|
||||
nokogiri (1.10.3)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nokogumbo (1.5.0)
|
||||
nokogiri
|
||||
nokogumbo (2.0.1)
|
||||
nokogiri (~> 1.8, >= 1.8.4)
|
||||
oauth (0.5.4)
|
||||
oauth2 (1.4.1)
|
||||
faraday (>= 0.8, < 0.16.0)
|
||||
@ -230,9 +210,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
octokit (4.13.0)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
oj (3.6.2)
|
||||
oj (3.7.12)
|
||||
omniauth (1.9.0)
|
||||
hashie (>= 3.4.6, < 3.7.0)
|
||||
rack (>= 1.6.2, < 3)
|
||||
@ -241,7 +219,7 @@ GEM
|
||||
omniauth-github (1.3.0)
|
||||
omniauth (~> 1.5)
|
||||
omniauth-oauth2 (>= 1.4.0, < 2.0)
|
||||
omniauth-google-oauth2 (0.6.0)
|
||||
omniauth-google-oauth2 (0.7.0)
|
||||
jwt (>= 2.0)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (>= 1.5)
|
||||
@ -260,41 +238,41 @@ GEM
|
||||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
onebox (1.8.77)
|
||||
onebox (1.8.92)
|
||||
htmlentities (~> 4.3)
|
||||
moneta (~> 1.0)
|
||||
multi_json (~> 1.11)
|
||||
mustache
|
||||
nokogiri (~> 1.7)
|
||||
sanitize
|
||||
open4 (1.3.4)
|
||||
openid-redis-store (0.0.2)
|
||||
redis
|
||||
ruby-openid
|
||||
parallel (1.12.1)
|
||||
parser (2.5.3.0)
|
||||
optimist (3.0.0)
|
||||
parallel (1.17.0)
|
||||
parallel_tests (2.28.0)
|
||||
parallel
|
||||
parser (2.6.3.0)
|
||||
ast (~> 2.4.0)
|
||||
pg (1.1.3)
|
||||
powerpack (0.1.2)
|
||||
progress (3.4.0)
|
||||
pry (0.10.4)
|
||||
pg (1.1.4)
|
||||
progress (3.5.0)
|
||||
pry (0.12.2)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pry-nav (0.2.4)
|
||||
pry (>= 0.9.10, < 0.11.0)
|
||||
pry-rails (0.3.6)
|
||||
method_source (~> 0.9.0)
|
||||
pry-nav (0.3.0)
|
||||
pry (>= 0.9.10, < 0.13.0)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (3.0.3)
|
||||
puma (3.11.4)
|
||||
puma (3.12.1)
|
||||
r2 (0.2.7)
|
||||
rack (2.0.6)
|
||||
rack-mini-profiler (1.0.1)
|
||||
rack (2.0.7)
|
||||
rack-mini-profiler (1.0.2)
|
||||
rack (>= 1.2.0)
|
||||
rack-openid (1.3.1)
|
||||
rack (>= 1.1.0)
|
||||
ruby-openid (>= 2.1.8)
|
||||
rack-protection (2.0.3)
|
||||
rack-protection (2.0.5)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
@ -303,70 +281,69 @@ GEM
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.0.4)
|
||||
loofah (~> 2.2, >= 2.2.2)
|
||||
rails_multisite (2.0.6)
|
||||
activerecord (> 4.2, < 6)
|
||||
railties (> 4.2, < 6)
|
||||
railties (5.2.2.1)
|
||||
actionpack (= 5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
rails_multisite (2.0.7)
|
||||
activerecord (> 4.2, < 7)
|
||||
railties (> 4.2, < 7)
|
||||
railties (5.2.3)
|
||||
actionpack (= 5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.19.0, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.0)
|
||||
rake (12.3.2)
|
||||
rake-compiler (1.0.4)
|
||||
rake-compiler (1.0.7)
|
||||
rake
|
||||
rb-fsevent (0.10.3)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
rbtrace (0.4.10)
|
||||
rb-inotify (0.10.0)
|
||||
ffi (~> 1.0)
|
||||
rbtrace (0.4.11)
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
trollop (>= 1.16.2)
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
redis (4.0.1)
|
||||
redis-namespace (1.6.0)
|
||||
redis (>= 3.0.4)
|
||||
request_store (1.4.1)
|
||||
rack (>= 1.4)
|
||||
rinku (2.0.4)
|
||||
rinku (2.0.6)
|
||||
rotp (3.3.1)
|
||||
rqrcode (0.10.1)
|
||||
chunky_png (~> 1.0)
|
||||
rspec (3.7.0)
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-core (3.7.1)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-expectations (3.7.0)
|
||||
rspec (3.8.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-core (3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-expectations (3.8.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-html-matchers (0.9.1)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a, < 4)
|
||||
rspec-mocks (3.7.0)
|
||||
rspec-mocks (3.8.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-rails (3.7.2)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-rails (3.8.2)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-support (3.7.1)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-support (3.8.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (0.61.1)
|
||||
rubocop (0.69.0)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.5, != 2.5.1.1)
|
||||
powerpack (~> 0.1)
|
||||
parser (>= 2.6)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.4.0)
|
||||
unicode-display_width (>= 1.4.0, < 1.7)
|
||||
ruby-openid (2.7.0)
|
||||
ruby-prof (0.17.0)
|
||||
ruby-progressbar (1.10.0)
|
||||
@ -374,38 +351,35 @@ GEM
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
ruby_dep (1.5.0)
|
||||
safe_yaml (1.0.4)
|
||||
sanitize (4.6.5)
|
||||
safe_yaml (1.0.5)
|
||||
sanitize (5.0.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.4.4)
|
||||
nokogumbo (~> 1.4)
|
||||
sass (3.5.6)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
sassc (1.11.4)
|
||||
bundler
|
||||
ffi (~> 1.9.6)
|
||||
sass (>= 3.3.0)
|
||||
sawyer (0.8.1)
|
||||
addressable (>= 2.3.5, < 2.6)
|
||||
faraday (~> 0.8, < 1.0)
|
||||
nokogiri (>= 1.8.0)
|
||||
nokogumbo (~> 2.0)
|
||||
sassc (2.0.1)
|
||||
ffi (~> 1.9)
|
||||
rake
|
||||
sassc-rails (2.1.1)
|
||||
railties (>= 4.0.0)
|
||||
sassc (>= 2.0)
|
||||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
seed-fu (2.3.9)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
shoulda (3.5.0)
|
||||
shoulda-context (~> 1.0, >= 1.0.1)
|
||||
shoulda-matchers (>= 1.4.1, < 3.0)
|
||||
shoulda-context (1.2.2)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (5.1.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
shoulda-matchers (3.1.3)
|
||||
activesupport (>= 4.0.0)
|
||||
sidekiq (5.2.7)
|
||||
connection_pool (~> 2.2, >= 2.2.2)
|
||||
rack (>= 1.5.0)
|
||||
rack-protection (>= 1.5.0)
|
||||
redis (>= 3.3.5, < 5)
|
||||
slop (3.6.0)
|
||||
simplecov (0.16.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
@ -413,31 +387,29 @@ GEM
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (1.9.0)
|
||||
stackprof (0.2.11)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
thor (0.19.4)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.12)
|
||||
test-prof (0.9.0)
|
||||
thor (0.20.3)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.8)
|
||||
trollop (2.1.2)
|
||||
tilt (2.0.9)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (4.1.11)
|
||||
uglifier (4.1.20)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.5)
|
||||
unicode-display_width (1.4.1)
|
||||
unicorn (5.4.0)
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.6.0)
|
||||
unicorn (5.5.1)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.11.0)
|
||||
webmock (3.4.2)
|
||||
uniform_notifier (1.12.1)
|
||||
webmock (3.5.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff
|
||||
webpush (0.3.6)
|
||||
webpush (0.3.8)
|
||||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
|
||||
@ -445,15 +417,16 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 5.2.2.1)
|
||||
actionpack (= 5.2.2.1)
|
||||
actionview (= 5.2.2.1)
|
||||
actionmailer (= 5.2.3)
|
||||
actionpack (= 5.2.3)
|
||||
actionview (= 5.2.3)
|
||||
active_model_serializers (~> 0.8.3)
|
||||
activemodel (= 5.2.2.1)
|
||||
activerecord (= 5.2.2.1)
|
||||
activesupport (= 5.2.2.1)
|
||||
activemodel (= 5.2.3)
|
||||
activerecord (= 5.2.3)
|
||||
activesupport (= 5.2.3)
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
aws-sdk-sns
|
||||
barber
|
||||
better_errors
|
||||
binding_of_caller
|
||||
@ -463,8 +436,8 @@ DEPENDENCIES
|
||||
certified
|
||||
colored2
|
||||
cppjieba_rb
|
||||
danger
|
||||
discourse-ember-source (~> 3.5.1)
|
||||
diffy
|
||||
discourse-ember-source (~> 3.8.0)
|
||||
discourse_image_optim
|
||||
email_reply_trimmer (~> 0.1)
|
||||
ember-handlebars-template (= 0.8.0)
|
||||
@ -478,7 +451,6 @@ DEPENDENCIES
|
||||
fast_xs
|
||||
fastimage
|
||||
flamegraph
|
||||
foreman
|
||||
gc_tracer
|
||||
highline (~> 1.7.0)
|
||||
hiredis
|
||||
@ -490,10 +462,10 @@ DEPENDENCIES
|
||||
logstash-logger
|
||||
logster
|
||||
lru_redux
|
||||
mail (= 2.7.1.rc1)
|
||||
mail
|
||||
maxminddb
|
||||
memory_profiler
|
||||
message_bus (= 2.2.0.pre.1)
|
||||
message_bus
|
||||
mini_mime
|
||||
mini_racer
|
||||
mini_scheduler
|
||||
@ -514,8 +486,9 @@ DEPENDENCIES
|
||||
omniauth-oauth2
|
||||
omniauth-openid
|
||||
omniauth-twitter
|
||||
onebox (= 1.8.77)
|
||||
onebox (= 1.8.92)
|
||||
openid-redis-store
|
||||
parallel_tests
|
||||
pg
|
||||
pry-nav
|
||||
pry-rails
|
||||
@ -524,13 +497,13 @@ DEPENDENCIES
|
||||
rack-mini-profiler
|
||||
rack-protection
|
||||
rails_multisite
|
||||
railties (= 5.2.2.1)
|
||||
railties (= 5.2.3)
|
||||
rake
|
||||
rb-fsevent
|
||||
rb-inotify (~> 0.9)
|
||||
rbtrace
|
||||
rchardet
|
||||
redis
|
||||
redis (= 4.0.1)
|
||||
redis-namespace
|
||||
rinku
|
||||
rotp
|
||||
@ -544,12 +517,15 @@ DEPENDENCIES
|
||||
ruby-readability
|
||||
sanitize
|
||||
sassc
|
||||
sassc-rails
|
||||
seed-fu
|
||||
shoulda
|
||||
shoulda-matchers (~> 3.1, >= 3.1.3)
|
||||
sidekiq
|
||||
simplecov
|
||||
sprockets-rails
|
||||
sshkey
|
||||
stackprof
|
||||
test-prof
|
||||
thor
|
||||
tilt
|
||||
uglifier
|
||||
|
2
Procfile
@ -1,2 +0,0 @@
|
||||
web: bundle exec rails server -p $PORT
|
||||
worker: bundle exec sidekiq -e $RAILS_ENV
|
42
README.md
@ -1,4 +1,8 @@
|
||||
<a href="http://www.discourse.org/"></a>
|
||||
<a href="https://www.discourse.org/"><img src=
|
||||
"https://user-images.githubusercontent.com/1681963/52239617-e2683480-289c-11e9-922b-5da55472e5b4.png"
|
||||
width="300px"></a>
|
||||
|
||||
|
||||
|
||||
Discourse is the 100% open source discussion platform built for the next decade of the Internet. Use it as a:
|
||||
|
||||
@ -6,17 +10,17 @@ Discourse is the 100% open source discussion platform built for the next decade
|
||||
- discussion forum
|
||||
- long-form chat room
|
||||
|
||||
To learn more about the philosophy and goals of the project, [visit **discourse.org**](http://www.discourse.org).
|
||||
To learn more about the philosophy and goals of the project, [visit **discourse.org**](https://www.discourse.org).
|
||||
|
||||
## Screenshots
|
||||
|
||||
|
||||
<a href="https://bbs.boingboing.net"><img alt="Boing Boing" src="https://cloud.githubusercontent.com/assets/1385470/25397876/3fe6cdac-29c0-11e7-8a41-9d0c0279f5a3.png" width="720px"></a>
|
||||
<a href="https://twittercommunity.com/"><img src="https://cloud.githubusercontent.com/assets/1385470/25397920/71b24e4c-29c0-11e7-8bcf-7a47b888412e.png" width="720px"></a>
|
||||
<a href="http://discuss.howtogeek.com"><img src="https://cloud.githubusercontent.com/assets/1385470/25398049/f0995962-29c0-11e7-99d7-a3b9c4f0b357.png" width="720px"></a>
|
||||
<a href="https://talk.turtlerockstudios.com/"><img src="https://cloud.githubusercontent.com/assets/1385470/25398115/2d560d96-29c1-11e7-9a96-b0134a4fedff.png" width="720px"></a>
|
||||
<a href="https://bbs.boingboing.net"><img alt="Boing Boing" src="https://user-images.githubusercontent.com/1681963/52239245-04ad8280-289c-11e9-9c88-8c173d4a0422.png" width="720px"></a>
|
||||
<a href="https://twittercommunity.com/"><img src="https://user-images.githubusercontent.com/1681963/52239250-04ad8280-289c-11e9-9e42-574f6eaab9d7.png" width="720px"></a>
|
||||
<a href="https://discuss.howtogeek.com"><img src="https://user-images.githubusercontent.com/1681963/52239247-04ad8280-289c-11e9-9706-fd66bc0749dc.png" width="720px"></a>
|
||||
<a href="https://talk.turtlerockstudios.com/"><img src="https://user-images.githubusercontent.com/1681963/52239249-04ad8280-289c-11e9-9155-f0ccc5decc50.png" width="720px"></a>
|
||||
|
||||
<img src="https://www.discourse.org/a/img/about/mobile-devices-2x.jpg" alt="Mobile" width="414">
|
||||
<img src="https://user-images.githubusercontent.com/1681963/52239118-b304f800-289b-11e9-9904-16450680d9ec.jpg" alt="Mobile" width="414">
|
||||
|
||||
Browse [lots more notable Discourse instances](https://www.discourse.org/customers).
|
||||
|
||||
@ -30,7 +34,7 @@ To get your environment setup, follow the community setup guide for your operati
|
||||
|
||||
If you're familiar with how Rails works and are comfortable setting up your own environment, you can also try out the [**Discourse Advanced Developer Guide**](docs/DEVELOPER-ADVANCED.md), which is aimed primarily at Ubuntu and macOS environments.
|
||||
|
||||
Before you get started, ensure you have the following minimum versions: [Ruby 2.5+](http://www.ruby-lang.org/en/downloads/), [PostgreSQL 10+](http://www.postgresql.org/download/), [Redis 2.6+](http://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
||||
Before you get started, ensure you have the following minimum versions: [Ruby 2.5+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 10+](https://www.postgresql.org/download/), [Redis 2.6+](https://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
||||
|
||||
## Setting up Discourse
|
||||
|
||||
@ -44,17 +48,17 @@ Discourse is built for the *next* 10 years of the Internet, so our requirements
|
||||
|
||||
| Browsers | Tablets | Phones |
|
||||
| --------------------- | ------------ | ------------ |
|
||||
| Safari 6.1+ | iPad 3+ | iOS 8+ |
|
||||
| Google Chrome 32+ | Android 4.3+ | Android 4.3+ |
|
||||
| Safari 10+ | iPad 4+ | iOS 10+ |
|
||||
| Google Chrome 57+ | Android 4.4+ | Android 4.4+ |
|
||||
| Internet Explorer 11+ | | |
|
||||
| Firefox 27+ | | |
|
||||
| Firefox 52+ | | |
|
||||
|
||||
## Built With
|
||||
|
||||
- [Ruby on Rails](https://github.com/rails/rails) — Our back end API is a Rails app. It responds to requests RESTfully in JSON.
|
||||
- [Ember.js](https://github.com/emberjs/ember.js) — Our front end is an Ember.js app that communicates with the Rails API.
|
||||
- [PostgreSQL](http://www.postgresql.org/) — Our main data store is in Postgres.
|
||||
- [Redis](http://redis.io/) — We use Redis as a cache and for transient data.
|
||||
- [PostgreSQL](https://www.postgresql.org/) — Our main data store is in Postgres.
|
||||
- [Redis](https://redis.io/) — We use Redis as a cache and for transient data.
|
||||
|
||||
Plus *lots* of Ruby Gems, a complete list of which is at [/master/Gemfile](https://github.com/discourse/discourse/blob/master/Gemfile).
|
||||
|
||||
@ -67,11 +71,11 @@ accepts contributions from the public – including you!
|
||||
|
||||
Before contributing to Discourse:
|
||||
|
||||
1. Please read the complete mission statements on [**discourse.org**](http://www.discourse.org). Yes we actually believe this stuff; you should too.
|
||||
2. Read and sign the [**Electronic Discourse Forums Contribution License Agreement**](http://discourse.org/cla).
|
||||
1. Please read the complete mission statements on [**discourse.org**](https://www.discourse.org). Yes we actually believe this stuff; you should too.
|
||||
2. Read and sign the [**Electronic Discourse Forums Contribution License Agreement**](https://www.discourse.org/cla).
|
||||
3. Dig into [**CONTRIBUTING.MD**](CONTRIBUTING.md), which covers submitting bugs, requesting new features, preparing your code for a pull request, etc.
|
||||
4. Always strive to collaborate [with mutual respect](https://github.com/discourse/discourse/blob/master/docs/code-of-conduct.md).
|
||||
5. Not sure what to work on? [**We've got some ideas.**](http://meta.discourse.org/t/so-you-want-to-help-out-with-discourse/3823)
|
||||
5. Not sure what to work on? [**We've got some ideas.**](https://meta.discourse.org/t/so-you-want-to-help-out-with-discourse/3823)
|
||||
|
||||
|
||||
We look forward to seeing your pull requests!
|
||||
@ -82,7 +86,7 @@ We take security very seriously at Discourse; all our code is 100% open source a
|
||||
|
||||
## The Discourse Team
|
||||
|
||||
The original Discourse code contributors can be found in [**AUTHORS.MD**](docs/AUTHORS.md). For a complete list of the many individuals that contributed to the design and implementation of Discourse, please refer to [the official Discourse blog](http://blog.discourse.org/2013/02/the-discourse-team/) and [GitHub's list of contributors](https://github.com/discourse/discourse/contributors).
|
||||
The original Discourse code contributors can be found in [**AUTHORS.MD**](docs/AUTHORS.md). For a complete list of the many individuals that contributed to the design and implementation of Discourse, please refer to [the official Discourse blog](https://blog.discourse.org/2013/02/the-discourse-team/) and [GitHub's list of contributors](https://github.com/discourse/discourse/contributors).
|
||||
|
||||
|
||||
## Copyright / License
|
||||
@ -93,7 +97,7 @@ Licensed under the GNU General Public License Version 2.0 (or later);
|
||||
you may not use this work except in compliance with the License.
|
||||
You may obtain a copy of the License in the LICENSE file, or at:
|
||||
|
||||
http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||
https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@ -105,4 +109,4 @@ Discourse logo and “Discourse Forum” ®, Civilized Discourse Construction Ki
|
||||
|
||||
## Dedication
|
||||
|
||||
Discourse is built with [love, Internet style.](http://www.youtube.com/watch?v=Xe1TZaElTAs)
|
||||
Discourse is built with [love, Internet style.](https://www.youtube.com/watch?v=Xe1TZaElTAs)
|
||||
|
2
Rakefile
@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
|
Before ![]() (image error) Size: 4.2 KiB After ![]() (image error) Size: 3.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.6 KiB After ![]() (image error) Size: 1.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 919 B After ![]() (image error) Size: 882 B ![]() ![]() |
Before ![]() (image error) Size: 1.9 KiB After ![]() (image error) Size: 1.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.0 KiB After ![]() (image error) Size: 1.0 KiB ![]() ![]() |
Before ![]() (image error) Size: 1021 B After ![]() (image error) Size: 984 B ![]() ![]() |
Before ![]() (image error) Size: 932 B After ![]() (image error) Size: 895 B ![]() ![]() |
Before ![]() (image error) Size: 4.1 KiB After ![]() (image error) Size: 3.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 5.8 KiB After ![]() (image error) Size: 4.9 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.6 KiB After ![]() (image error) Size: 1.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 7.8 KiB After ![]() (image error) Size: 4.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.6 KiB After ![]() (image error) Size: 3.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.1 KiB After ![]() (image error) Size: 2.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.6 KiB After ![]() (image error) Size: 3.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.9 KiB After ![]() (image error) Size: 1.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.9 KiB After ![]() (image error) Size: 1.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.6 KiB After ![]() (image error) Size: 1.6 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.9 KiB After ![]() (image error) Size: 1.8 KiB ![]() ![]() |
@ -1,38 +0,0 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default RestAdapter.extend({
|
||||
pathFor(store, type, findArgs) {
|
||||
let args = _.merge({ rest_api: true }, findArgs);
|
||||
delete args.filter;
|
||||
return `/admin/flags/${findArgs.filter}.json?${$.param(args)}`;
|
||||
},
|
||||
|
||||
afterFindAll(results, helper) {
|
||||
results.forEach(flag => {
|
||||
let conversations = [];
|
||||
flag.post_actions.forEach(pa => {
|
||||
if (pa.conversation) {
|
||||
let conversation = {
|
||||
permalink: pa.permalink,
|
||||
hasMore: pa.conversation.has_more,
|
||||
response: {
|
||||
excerpt: pa.conversation.response.excerpt,
|
||||
user: helper.lookup("user", pa.conversation.response.user_id)
|
||||
}
|
||||
};
|
||||
|
||||
if (pa.conversation.reply) {
|
||||
conversation.reply = {
|
||||
excerpt: pa.conversation.reply.excerpt,
|
||||
user: helper.lookup("user", pa.conversation.reply.user_id)
|
||||
};
|
||||
}
|
||||
conversations.push(conversation);
|
||||
}
|
||||
});
|
||||
flag.set("conversations", conversations);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
});
|
@ -10,7 +10,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@observes("editorId")
|
||||
editorIdChanged() {
|
||||
if (this.get("autofocus")) {
|
||||
if (this.autofocus) {
|
||||
this.send("focus");
|
||||
}
|
||||
},
|
||||
@ -18,14 +18,14 @@ export default Ember.Component.extend({
|
||||
@observes("content")
|
||||
contentChanged() {
|
||||
if (this._editor && !this._skipContentChangeEvent) {
|
||||
this._editor.getSession().setValue(this.get("content"));
|
||||
this._editor.getSession().setValue(this.content);
|
||||
}
|
||||
},
|
||||
|
||||
@observes("mode")
|
||||
modeChanged() {
|
||||
if (this._editor && !this._skipContentChangeEvent) {
|
||||
this._editor.getSession().setMode("ace/mode/" + this.get("mode"));
|
||||
this._editor.getSession().setMode("ace/mode/" + this.mode);
|
||||
}
|
||||
},
|
||||
|
||||
@ -37,7 +37,7 @@ export default Ember.Component.extend({
|
||||
changeDisabledState() {
|
||||
const editor = this._editor;
|
||||
if (editor) {
|
||||
const disabled = this.get("disabled");
|
||||
const disabled = this.disabled;
|
||||
editor.setOptions({
|
||||
readOnly: disabled,
|
||||
highlightActiveLine: !disabled,
|
||||
@ -79,7 +79,7 @@ export default Ember.Component.extend({
|
||||
editor.setTheme("ace/theme/chrome");
|
||||
editor.setShowPrintMargin(false);
|
||||
editor.setOptions({ fontSize: "14px" });
|
||||
editor.getSession().setMode("ace/mode/" + this.get("mode"));
|
||||
editor.getSession().setMode("ace/mode/" + this.mode);
|
||||
editor.on("change", () => {
|
||||
this._skipContentChangeEvent = true;
|
||||
this.set("content", editor.getSession().getValue());
|
||||
@ -100,10 +100,10 @@ export default Ember.Component.extend({
|
||||
|
||||
if (this.appEvents) {
|
||||
// xxx: don't run during qunit tests
|
||||
this.appEvents.on("ace:resize", () => this.resize());
|
||||
this.appEvents.on("ace:resize", this, "resize");
|
||||
}
|
||||
|
||||
if (this.get("autofocus")) {
|
||||
if (this.autofocus) {
|
||||
this.send("focus");
|
||||
}
|
||||
});
|
||||
|
@ -25,7 +25,7 @@ export default Ember.Component.extend(
|
||||
@on("init")
|
||||
@observes("logs.[]")
|
||||
_resetFormattedLogs() {
|
||||
if (this.get("logs").length === 0) {
|
||||
if (this.logs.length === 0) {
|
||||
this._reset(); // reset the cached logs whenever the model is reset
|
||||
this.rerenderBuffer();
|
||||
}
|
||||
@ -34,12 +34,12 @@ export default Ember.Component.extend(
|
||||
@on("init")
|
||||
@observes("logs.[]")
|
||||
_updateFormattedLogs: debounce(function() {
|
||||
const logs = this.get("logs");
|
||||
const logs = this.logs;
|
||||
if (logs.length === 0) return;
|
||||
|
||||
// do the log formatting only once for HELLish performance
|
||||
let formattedLogs = this.get("formattedLogs");
|
||||
for (let i = this.get("index"), length = logs.length; i < length; i++) {
|
||||
let formattedLogs = this.formattedLogs;
|
||||
for (let i = this.index, length = logs.length; i < length; i++) {
|
||||
const date = logs[i].get("timestamp"),
|
||||
message = escapeExpression(logs[i].get("message"));
|
||||
formattedLogs += "[" + date + "] " + message + "\n";
|
||||
@ -56,7 +56,7 @@ export default Ember.Component.extend(
|
||||
}, 150),
|
||||
|
||||
buildBuffer(buffer) {
|
||||
const formattedLogs = this.get("formattedLogs");
|
||||
const formattedLogs = this.formattedLogs;
|
||||
if (formattedLogs && formattedLogs.length > 0) {
|
||||
buffer.push("<pre>");
|
||||
buffer.push(formattedLogs);
|
||||
|
@ -8,27 +8,25 @@ export default Ember.Component.extend(
|
||||
rerenderTriggers: ["order", "ascending"],
|
||||
|
||||
buildBuffer(buffer) {
|
||||
const icon = this.get("icon");
|
||||
const icon = this.icon;
|
||||
|
||||
if (icon) {
|
||||
buffer.push(iconHTML(icon));
|
||||
}
|
||||
|
||||
buffer.push(I18n.t(this.get("i18nKey")));
|
||||
buffer.push(I18n.t(this.i18nKey));
|
||||
|
||||
if (this.get("field") === this.get("order")) {
|
||||
buffer.push(
|
||||
iconHTML(this.get("ascending") ? "chevron-up" : "chevron-down")
|
||||
);
|
||||
if (this.field === this.order) {
|
||||
buffer.push(iconHTML(this.ascending ? "chevron-up" : "chevron-down"));
|
||||
}
|
||||
},
|
||||
|
||||
click() {
|
||||
const currentOrder = this.get("order");
|
||||
const field = this.get("field");
|
||||
const currentOrder = this.order;
|
||||
const field = this.field;
|
||||
|
||||
if (currentOrder === field) {
|
||||
this.set("ascending", this.get("ascending") ? null : true);
|
||||
this.set("ascending", this.ascending ? null : true);
|
||||
} else {
|
||||
this.setProperties({ order: field, ascending: null });
|
||||
}
|
||||
|
@ -11,13 +11,13 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
edit() {
|
||||
this.set("buffer", this.get("value"));
|
||||
this.set("buffer", this.value);
|
||||
this.toggleProperty("editing");
|
||||
},
|
||||
|
||||
save() {
|
||||
// Action has to toggle 'editing' property.
|
||||
this.action(this.get("buffer"));
|
||||
this.action(this.buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { number } from "discourse/lib/formatter";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: "canvas",
|
||||
type: "line",
|
||||
|
||||
refreshChart() {
|
||||
const ctx = this.$()[0].getContext("2d");
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
const rawData = this.get("model.data");
|
||||
|
||||
var data = {
|
||||
@ -14,14 +15,14 @@ export default Ember.Component.extend({
|
||||
{
|
||||
data: rawData.map(r => r.y),
|
||||
label: model.get("title"),
|
||||
backgroundColor: "rgba(200,220,240,0.3)",
|
||||
backgroundColor: `rgba(200,220,240,${this.type === "bar" ? 1 : 0.3})`,
|
||||
borderColor: "#08C"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const config = {
|
||||
type: "line",
|
||||
type: this.type,
|
||||
data: data,
|
||||
options: {
|
||||
responsive: true,
|
||||
@ -36,8 +37,7 @@ export default Ember.Component.extend({
|
||||
{
|
||||
display: true,
|
||||
ticks: {
|
||||
callback: label => number(label),
|
||||
suggestedMin: 0
|
||||
stepSize: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -35,7 +35,7 @@ export default Ember.Component.extend({
|
||||
|
||||
_scheduleChartRendering() {
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this._renderChart(this.get("model"), this.$(".chart-canvas"));
|
||||
this._renderChart(this.model, this.$(".chart-canvas"));
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["admin-report-counters"]
|
||||
classNames: ["admin-report-counters"],
|
||||
|
||||
attributeBindings: ["model.description:title"]
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ export default Ember.Component.extend({
|
||||
|
||||
_scheduleChartRendering() {
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this._renderChart(this.get("model"), this.$(".chart-canvas"));
|
||||
this._renderChart(this.model, this.$(".chart-canvas"));
|
||||
});
|
||||
},
|
||||
|
||||
@ -114,6 +114,7 @@ export default Ember.Component.extend({
|
||||
display: true,
|
||||
gridLines: { display: false },
|
||||
type: "time",
|
||||
offset: true,
|
||||
time: {
|
||||
parser: "YYYY-MM-DD",
|
||||
minUnit: "day"
|
||||
|
@ -31,6 +31,21 @@ export default Ember.Component.extend({
|
||||
return reportTotal && total && twoColumns;
|
||||
},
|
||||
|
||||
@computed("model.{average,data}", "totalsForSample.1.value", "twoColumns")
|
||||
showAverage(model, sampleTotalValue, hasTwoColumns) {
|
||||
return (
|
||||
model.average &&
|
||||
model.data.length > 0 &&
|
||||
sampleTotalValue &&
|
||||
hasTwoColumns
|
||||
);
|
||||
},
|
||||
|
||||
@computed("totalsForSample.1.value", "model.data.length")
|
||||
averageForSample(totals, count) {
|
||||
return (totals / count).toFixed(0);
|
||||
},
|
||||
|
||||
@computed("model.data.length")
|
||||
showSortingUI(dataLength) {
|
||||
return dataLength >= 5;
|
||||
@ -79,8 +94,8 @@ export default Ember.Component.extend({
|
||||
if (sortLabel) {
|
||||
const compare = (label, direction) => {
|
||||
return (a, b) => {
|
||||
let aValue = label.compute(a).value;
|
||||
let bValue = label.compute(b).value;
|
||||
const aValue = label.compute(a, { useSortProperty: true }).value;
|
||||
const bValue = label.compute(b, { useSortProperty: true }).value;
|
||||
const result = aValue < bValue ? -1 : aValue > bValue ? 1 : 0;
|
||||
return result * direction;
|
||||
};
|
||||
@ -134,8 +149,8 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
sortByLabel(label) {
|
||||
if (this.get("sortLabel") === label) {
|
||||
this.set("sortDirection", this.get("sortDirection") === 1 ? -1 : 1);
|
||||
if (this.sortLabel === label) {
|
||||
this.set("sortDirection", this.sortDirection === 1 ? -1 : 1);
|
||||
} else {
|
||||
this.set("sortLabel", label);
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
import ReportLoader from "discourse/lib/reports-loader";
|
||||
import Category from "discourse/models/category";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { isNumeric } from "discourse/lib/utilities";
|
||||
import { SCHEMA_VERSION, default as Report } from "admin/models/report";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import {
|
||||
registerHoverTooltip,
|
||||
unregisterHoverTooltip
|
||||
} from "discourse/lib/tooltip";
|
||||
|
||||
const TABLE_OPTIONS = {
|
||||
perPage: 8,
|
||||
@ -54,20 +50,15 @@ export default Ember.Component.extend({
|
||||
filters: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
category: null,
|
||||
groupId: null,
|
||||
showTrend: false,
|
||||
showHeader: true,
|
||||
showTitle: true,
|
||||
showFilteringUI: false,
|
||||
showCategoryOptions: Ember.computed.alias("model.category_filtering"),
|
||||
showDatesOptions: Ember.computed.alias("model.dates_filtering"),
|
||||
showGroupOptions: Ember.computed.alias("model.group_filtering"),
|
||||
showExport: Ember.computed.not("model.onlyTable"),
|
||||
showRefresh: Ember.computed.or(
|
||||
"showCategoryOptions",
|
||||
"showDatesOptions",
|
||||
"showGroupOptions"
|
||||
"model.available_filters.length"
|
||||
),
|
||||
shouldDisplayTrend: Ember.computed.and("showTrend", "model.prev_period"),
|
||||
|
||||
@ -77,41 +68,19 @@ export default Ember.Component.extend({
|
||||
this._reports = [];
|
||||
},
|
||||
|
||||
startDate: Ember.computed.reads("filters.startDate"),
|
||||
endDate: Ember.computed.reads("filters.endDate"),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
const state = this.get("filters") || {};
|
||||
|
||||
this.setProperties({
|
||||
category: Category.findById(state.categoryId),
|
||||
groupId: state.groupId,
|
||||
startDate: state.startDate,
|
||||
endDate: state.endDate
|
||||
});
|
||||
|
||||
if (this.get("report")) {
|
||||
this._renderReport(
|
||||
this.get("report"),
|
||||
this.get("forcedModes"),
|
||||
this.get("currentMode")
|
||||
);
|
||||
} else if (this.get("dataSourceName")) {
|
||||
if (this.report) {
|
||||
this._renderReport(this.report, this.forcedModes, this.currentMode);
|
||||
} else if (this.dataSourceName) {
|
||||
this._fetchReport();
|
||||
}
|
||||
},
|
||||
|
||||
didRender() {
|
||||
this._super(...arguments);
|
||||
|
||||
registerHoverTooltip($(".info[data-tooltip]"));
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
unregisterHoverTooltip($(".info[data-tooltip]"));
|
||||
},
|
||||
|
||||
showError: Ember.computed.or(
|
||||
"showTimeoutError",
|
||||
"showExceptionError",
|
||||
@ -139,8 +108,6 @@ export default Ember.Component.extend({
|
||||
return displayedModesLength > 1;
|
||||
},
|
||||
|
||||
categoryId: Ember.computed.alias("category.id"),
|
||||
|
||||
@computed("currentMode", "model.modes", "forcedModes")
|
||||
displayedModes(currentMode, reportModes, forcedModes) {
|
||||
const modes = forcedModes ? forcedModes.split(",") : reportModes;
|
||||
@ -157,18 +124,6 @@ export default Ember.Component.extend({
|
||||
});
|
||||
},
|
||||
|
||||
@computed()
|
||||
groupOptions() {
|
||||
const arr = [
|
||||
{ name: I18n.t("admin.dashboard.reports.groups"), value: "all" }
|
||||
];
|
||||
return arr.concat(
|
||||
(this.site.groups || []).map(i => {
|
||||
return { name: i["name"], value: i["id"] };
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
@computed("currentMode")
|
||||
modeComponent(currentMode) {
|
||||
return `admin-report-${currentMode}`;
|
||||
@ -200,23 +155,25 @@ export default Ember.Component.extend({
|
||||
|
||||
@computed(
|
||||
"dataSourceName",
|
||||
"categoryId",
|
||||
"groupId",
|
||||
"normalizedStartDate",
|
||||
"normalizedEndDate"
|
||||
"normalizedEndDate",
|
||||
"filters.customFilters"
|
||||
)
|
||||
reportKey(dataSourceName, categoryId, groupId, startDate, endDate) {
|
||||
reportKey(dataSourceName, startDate, endDate, customFilters) {
|
||||
if (!dataSourceName || !startDate || !endDate) return null;
|
||||
|
||||
let reportKey = "reports:";
|
||||
reportKey += [
|
||||
dataSourceName,
|
||||
categoryId,
|
||||
startDate.replace(/-/g, ""),
|
||||
endDate.replace(/-/g, ""),
|
||||
groupId,
|
||||
"[:prev_period]",
|
||||
this.get("reportOptions.table.limit"),
|
||||
customFilters
|
||||
? JSON.stringify(customFilters, (key, value) =>
|
||||
isNumeric(value) ? value.toString() : value
|
||||
)
|
||||
: null,
|
||||
SCHEMA_VERSION
|
||||
]
|
||||
.filter(x => x)
|
||||
@ -227,24 +184,41 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
applyFilter(id, value) {
|
||||
let customFilters = this.get("filters.customFilters") || {};
|
||||
|
||||
if (typeof value === "undefined") {
|
||||
delete customFilters[id];
|
||||
} else {
|
||||
customFilters[id] = value;
|
||||
}
|
||||
|
||||
this.attrs.onRefresh({
|
||||
type: this.get("model.type"),
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
filters: customFilters
|
||||
});
|
||||
},
|
||||
|
||||
refreshReport() {
|
||||
this.attrs.onRefresh({
|
||||
categoryId: this.get("categoryId"),
|
||||
groupId: this.get("groupId"),
|
||||
startDate: this.get("startDate"),
|
||||
endDate: this.get("endDate")
|
||||
type: this.get("model.type"),
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
filters: this.get("filters.customFilters")
|
||||
});
|
||||
},
|
||||
|
||||
exportCsv() {
|
||||
const customFilters = this.get("filters.customFilters") || {};
|
||||
|
||||
exportEntity("report", {
|
||||
name: this.get("model.type"),
|
||||
start_date: this.get("startDate"),
|
||||
end_date: this.get("endDate"),
|
||||
category_id:
|
||||
this.get("categoryId") === "all" ? undefined : this.get("categoryId"),
|
||||
group_id:
|
||||
this.get("groupId") === "all" ? undefined : this.get("groupId")
|
||||
start_date: this.startDate,
|
||||
end_date: this.endDate,
|
||||
category_id: customFilters.category,
|
||||
group_id: customFilters.group
|
||||
}).then(outputExportResult);
|
||||
},
|
||||
|
||||
@ -271,16 +245,16 @@ export default Ember.Component.extend({
|
||||
|
||||
const sort = r => {
|
||||
if (r.length > 1) {
|
||||
return r.findBy("type", this.get("dataSourceName"));
|
||||
return r.findBy("type", this.dataSourceName);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.get("startDate") || !this.get("endDate")) {
|
||||
if (!this.startDate || !this.endDate) {
|
||||
report = sort(filteredReports)[0];
|
||||
} else {
|
||||
const reportKey = this.get("reportKey");
|
||||
const reportKey = this.reportKey;
|
||||
|
||||
report = sort(
|
||||
filteredReports.filter(r => r.report_key.includes(reportKey))
|
||||
@ -293,11 +267,7 @@ export default Ember.Component.extend({
|
||||
this.set("showFilteringUI", false);
|
||||
}
|
||||
|
||||
this._renderReport(
|
||||
report,
|
||||
this.get("forcedModes"),
|
||||
this.get("currentMode")
|
||||
);
|
||||
this._renderReport(report, this.forcedModes, this.currentMode);
|
||||
},
|
||||
|
||||
_renderReport(report, forcedModes, currentMode) {
|
||||
@ -339,37 +309,33 @@ export default Ember.Component.extend({
|
||||
}
|
||||
};
|
||||
|
||||
ReportLoader.enqueue(this.get("dataSourceName"), payload.data, callback);
|
||||
ReportLoader.enqueue(this.dataSourceName, payload.data, callback);
|
||||
});
|
||||
},
|
||||
|
||||
_buildPayload(facets) {
|
||||
let payload = { data: { cache: true, facets } };
|
||||
|
||||
if (this.get("startDate")) {
|
||||
if (this.startDate) {
|
||||
payload.data.start_date = moment
|
||||
.utc(this.get("startDate"), "YYYY-MM-DD")
|
||||
.utc(this.startDate, "YYYY-MM-DD")
|
||||
.toISOString();
|
||||
}
|
||||
|
||||
if (this.get("endDate")) {
|
||||
if (this.endDate) {
|
||||
payload.data.end_date = moment
|
||||
.utc(this.get("endDate"), "YYYY-MM-DD")
|
||||
.utc(this.endDate, "YYYY-MM-DD")
|
||||
.toISOString();
|
||||
}
|
||||
|
||||
if (this.get("groupId") && this.get("groupId") !== "all") {
|
||||
payload.data.group_id = this.get("groupId");
|
||||
}
|
||||
|
||||
if (this.get("categoryId") && this.get("categoryId") !== "all") {
|
||||
payload.data.category_id = this.get("categoryId");
|
||||
}
|
||||
|
||||
if (this.get("reportOptions.table.limit")) {
|
||||
payload.data.limit = this.get("reportOptions.table.limit");
|
||||
}
|
||||
|
||||
if (this.get("filters.customFilters")) {
|
||||
payload.data.filters = this.get("filters.customFilters");
|
||||
}
|
||||
|
||||
return payload;
|
||||
},
|
||||
|
||||
@ -414,8 +380,8 @@ export default Ember.Component.extend({
|
||||
Report.fillMissingDates(jsonReport, {
|
||||
filledField: "prevChartData",
|
||||
dataField: "prev_data",
|
||||
starDate: jsonReport.prev_start_date,
|
||||
endDate: jsonReport.prev_end_date
|
||||
starDate: jsonReport.prev_startDate,
|
||||
endDate: jsonReport.prev_endDate
|
||||
});
|
||||
|
||||
if (jsonReport.prevChartData && jsonReport.prevChartData.length > 40) {
|
||||
|
@ -0,0 +1,92 @@
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
@computed("theme.targets", "onlyOverridden", "showAdvanced")
|
||||
visibleTargets(targets, onlyOverridden, showAdvanced) {
|
||||
return targets.filter(target => {
|
||||
if (target.advanced && !showAdvanced) {
|
||||
return false;
|
||||
}
|
||||
if (!onlyOverridden) {
|
||||
return true;
|
||||
}
|
||||
return target.edited;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "onlyOverridden", "theme.fields")
|
||||
visibleFields(targetName, onlyOverridden, fields) {
|
||||
fields = fields[targetName];
|
||||
if (onlyOverridden) {
|
||||
fields = fields.filter(field => field.edited);
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "fieldName")
|
||||
activeSectionMode(targetName, fieldName) {
|
||||
if (["settings", "translations"].includes(targetName)) return "yaml";
|
||||
if (["extra_scss"].includes(targetName)) return "scss";
|
||||
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
|
||||
},
|
||||
|
||||
@computed("fieldName", "currentTargetName", "theme")
|
||||
activeSection: {
|
||||
get(fieldName, target, model) {
|
||||
return model.getField(target, fieldName);
|
||||
},
|
||||
set(value, fieldName, target, model) {
|
||||
model.setField(target, fieldName, value);
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
editorId: fmt("fieldName", "currentTargetName", "%@|%@"),
|
||||
|
||||
@computed("maximized")
|
||||
maximizeIcon(maximized) {
|
||||
return maximized ? "discourse-compress" : "discourse-expand";
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "theme.targets")
|
||||
showAddField(currentTargetName, targets) {
|
||||
return targets.find(t => t.name === currentTargetName).customNames;
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "fieldName", "theme.theme_fields.@each.error")
|
||||
error(target, fieldName) {
|
||||
return this.theme.getError(target, fieldName);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleShowAdvanced() {
|
||||
this.toggleProperty("showAdvanced");
|
||||
},
|
||||
|
||||
toggleAddField() {
|
||||
this.toggleProperty("addingField");
|
||||
},
|
||||
|
||||
cancelAddField() {
|
||||
this.set("addingField", false);
|
||||
},
|
||||
|
||||
addField(name) {
|
||||
if (!name) return;
|
||||
name = name.replace(/[^a-zA-Z0-9-_/]/g, "");
|
||||
this.theme.setField(this.currentTargetName, name, "");
|
||||
this.setProperties({ newFieldName: "", addingField: false });
|
||||
this.fieldAdded(this.currentTargetName, name);
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
this.toggleProperty("maximized");
|
||||
Ember.run.next(() => this.appEvents.trigger("ace:resize"));
|
||||
},
|
||||
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
}
|
||||
}
|
||||
});
|
@ -2,6 +2,12 @@ import UserField from "admin/models/user-field";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
import { i18n } from "discourse/lib/computed";
|
||||
import {
|
||||
default as computed,
|
||||
observes,
|
||||
on
|
||||
} from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend(bufferedProperty("userField"), {
|
||||
editing: Ember.computed.empty("userField.id"),
|
||||
@ -10,59 +16,57 @@ export default Ember.Component.extend(bufferedProperty("userField"), {
|
||||
cantMoveUp: propertyEqual("userField", "firstField"),
|
||||
cantMoveDown: propertyEqual("userField", "lastField"),
|
||||
|
||||
userFieldsDescription: function() {
|
||||
return I18n.t("admin.user_fields.description");
|
||||
}.property(),
|
||||
userFieldsDescription: i18n("admin.user_fields.description"),
|
||||
|
||||
bufferedFieldType: function() {
|
||||
return UserField.fieldTypeById(this.get("buffered.field_type"));
|
||||
}.property("buffered.field_type"),
|
||||
@computed("buffered.field_type")
|
||||
bufferedFieldType(fieldType) {
|
||||
return UserField.fieldTypeById(fieldType);
|
||||
},
|
||||
|
||||
_focusOnEdit: function() {
|
||||
if (this.get("editing")) {
|
||||
@on("didInsertElement")
|
||||
@observes("editing")
|
||||
_focusOnEdit() {
|
||||
if (this.editing) {
|
||||
Ember.run.scheduleOnce("afterRender", this, "_focusName");
|
||||
}
|
||||
}
|
||||
.observes("editing")
|
||||
.on("didInsertElement"),
|
||||
},
|
||||
|
||||
_focusName: function() {
|
||||
_focusName() {
|
||||
$(".user-field-name").select();
|
||||
},
|
||||
|
||||
fieldName: function() {
|
||||
return UserField.fieldTypeById(this.get("userField.field_type")).get(
|
||||
"name"
|
||||
);
|
||||
}.property("userField.field_type"),
|
||||
@computed("userField.field_type")
|
||||
fieldName(fieldType) {
|
||||
return UserField.fieldTypeById(fieldType).get("name");
|
||||
},
|
||||
|
||||
flags: function() {
|
||||
const ret = [];
|
||||
if (this.get("userField.editable")) {
|
||||
ret.push(I18n.t("admin.user_fields.editable.enabled"));
|
||||
}
|
||||
if (this.get("userField.required")) {
|
||||
ret.push(I18n.t("admin.user_fields.required.enabled"));
|
||||
}
|
||||
if (this.get("userField.show_on_profile")) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_profile.enabled"));
|
||||
}
|
||||
if (this.get("userField.show_on_user_card")) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_user_card.enabled"));
|
||||
}
|
||||
|
||||
return ret.join(", ");
|
||||
}.property(
|
||||
@computed(
|
||||
"userField.editable",
|
||||
"userField.required",
|
||||
"userField.show_on_profile",
|
||||
"userField.show_on_user_card"
|
||||
),
|
||||
)
|
||||
flags(editable, required, showOnProfile, showOnUserCard) {
|
||||
const ret = [];
|
||||
if (editable) {
|
||||
ret.push(I18n.t("admin.user_fields.editable.enabled"));
|
||||
}
|
||||
if (required) {
|
||||
ret.push(I18n.t("admin.user_fields.required.enabled"));
|
||||
}
|
||||
if (showOnProfile) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_profile.enabled"));
|
||||
}
|
||||
if (showOnUserCard) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_user_card.enabled"));
|
||||
}
|
||||
|
||||
return ret.join(", ");
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
const self = this;
|
||||
const buffered = this.get("buffered");
|
||||
const buffered = this.buffered;
|
||||
const attrs = buffered.getProperties(
|
||||
"name",
|
||||
"description",
|
||||
@ -74,11 +78,11 @@ export default Ember.Component.extend(bufferedProperty("userField"), {
|
||||
"options"
|
||||
);
|
||||
|
||||
this.get("userField")
|
||||
this.userField
|
||||
.save(attrs)
|
||||
.then(function() {
|
||||
self.set("editing", false);
|
||||
self.commitBuffer();
|
||||
.then(() => {
|
||||
this.set("editing", false);
|
||||
this.commitBuffer();
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
@ -90,7 +94,7 @@ export default Ember.Component.extend(bufferedProperty("userField"), {
|
||||
cancel() {
|
||||
const id = this.get("userField.id");
|
||||
if (Ember.isEmpty(id)) {
|
||||
this.destroyAction(this.get("userField"));
|
||||
this.destroyAction(this.userField);
|
||||
} else {
|
||||
this.rollbackBuffer();
|
||||
this.set("editing", false);
|
||||
|
@ -11,10 +11,10 @@ export default Ember.Component.extend(
|
||||
},
|
||||
|
||||
click() {
|
||||
this.get("word")
|
||||
this.word
|
||||
.destroy()
|
||||
.then(() => {
|
||||
this.action(this.get("word"));
|
||||
this.action(this.word);
|
||||
})
|
||||
.catch(e => {
|
||||
bootbox.alert(
|
||||
|
@ -25,8 +25,8 @@ export default Ember.Component.extend({
|
||||
return eventTypeExists;
|
||||
},
|
||||
set(value, eventTypeExists) {
|
||||
const type = this.get("type");
|
||||
const model = this.get("model");
|
||||
const type = this.type;
|
||||
const model = this.model;
|
||||
// add an association when not exists
|
||||
if (value !== eventTypeExists) {
|
||||
if (value) {
|
||||
|
@ -6,6 +6,8 @@ import { ensureJSON, plainJSON, prettyJSON } from "discourse/lib/formatter";
|
||||
export default Ember.Component.extend({
|
||||
tagName: "li",
|
||||
expandDetails: null,
|
||||
expandDetailsRequestKey: "request",
|
||||
expandDetailsResponseKey: "response",
|
||||
|
||||
@computed("model.status")
|
||||
statusColorClasses(status) {
|
||||
@ -29,6 +31,20 @@ export default Ember.Component.extend({
|
||||
return I18n.t("admin.web_hooks.events.completed_in", { count: seconds });
|
||||
},
|
||||
|
||||
@computed("expandDetails")
|
||||
expandRequestIcon(expandDetails) {
|
||||
return expandDetails === this.expandDetailsRequestKey
|
||||
? "ellipsis-h"
|
||||
: "ellipsis-v";
|
||||
},
|
||||
|
||||
@computed("expandDetails")
|
||||
expandResponseIcon(expandDetails) {
|
||||
return expandDetails === this.expandDetailsResponseKey
|
||||
? "ellipsis-h"
|
||||
: "ellipsis-v";
|
||||
},
|
||||
|
||||
actions: {
|
||||
redeliver() {
|
||||
return bootbox.confirm(
|
||||
@ -53,9 +69,9 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
toggleRequest() {
|
||||
const expandDetailsKey = "request";
|
||||
const expandDetailsKey = this.expandDetailsRequestKey;
|
||||
|
||||
if (this.get("expandDetails") !== expandDetailsKey) {
|
||||
if (this.expandDetails !== expandDetailsKey) {
|
||||
let headers = _.extend(
|
||||
{
|
||||
"Request URL": this.get("model.request_url"),
|
||||
@ -75,9 +91,9 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
toggleResponse() {
|
||||
const expandDetailsKey = "response";
|
||||
const expandDetailsKey = this.expandDetailsResponseKey;
|
||||
|
||||
if (this.get("expandDetails") !== expandDetailsKey) {
|
||||
if (this.expandDetails !== expandDetailsKey) {
|
||||
this.setProperties({
|
||||
headers: plainJSON(this.get("model.response_headers")),
|
||||
body: this.get("model.response_body"),
|
||||
|
@ -4,8 +4,8 @@ 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"],
|
||||
classes: ["text-muted", "text-danger", "text-successful", "text-muted"],
|
||||
icons: ["circle-o", "times-circle", "circle", "circle"],
|
||||
|
||||
@computed("deliveryStatuses", "model.last_delivery_status")
|
||||
status(deliveryStatuses, lastDeliveryStatus) {
|
||||
@ -23,7 +23,7 @@ export default Ember.Component.extend(
|
||||
},
|
||||
|
||||
buildBuffer(buffer) {
|
||||
buffer.push(iconHTML(this.get("icon"), { class: this.get("class") }));
|
||||
buffer.push(iconHTML(this.icon, { class: this.class }));
|
||||
buffer.push(
|
||||
I18n.t(`admin.web_hooks.delivery_status.${this.get("status.name")}`)
|
||||
);
|
||||
|
@ -10,21 +10,21 @@ import { default as loadScript, loadCSS } from "discourse/lib/load-script";
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["color-picker"],
|
||||
hexValueChanged: function() {
|
||||
var hex = this.get("hexValue");
|
||||
var hex = this.hexValue;
|
||||
let $text = this.$("input.hex-input");
|
||||
|
||||
if (this.get("valid")) {
|
||||
if (this.valid) {
|
||||
$text.attr(
|
||||
"style",
|
||||
"color: " +
|
||||
(this.get("brightnessValue") > 125 ? "black" : "white") +
|
||||
(this.brightnessValue > 125 ? "black" : "white") +
|
||||
"; background-color: #" +
|
||||
hex +
|
||||
";"
|
||||
);
|
||||
|
||||
if (this.get("pickerLoaded")) {
|
||||
this.$(".picker").spectrum({ color: "#" + this.get("hexValue") });
|
||||
if (this.pickerLoaded) {
|
||||
this.$(".picker").spectrum({ color: "#" + this.hexValue });
|
||||
}
|
||||
} else {
|
||||
$text.attr("style", "");
|
||||
@ -36,7 +36,7 @@ export default Ember.Component.extend({
|
||||
loadCSS("/javascripts/spectrum.css").then(() => {
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.$(".picker")
|
||||
.spectrum({ color: "#" + this.get("hexValue") })
|
||||
.spectrum({ color: "#" + this.hexValue })
|
||||
.on("change.spectrum", (me, color) => {
|
||||
this.set("hexValue", color.toHexString().replace("#", ""));
|
||||
});
|
||||
|
@ -30,26 +30,23 @@ export default Ember.Component.extend(bufferedProperty("host"), {
|
||||
},
|
||||
|
||||
save() {
|
||||
if (this.get("cantSave")) {
|
||||
if (this.cantSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
const props = this.get("buffered").getProperties(
|
||||
const props = this.buffered.getProperties(
|
||||
"host",
|
||||
"path_whitelist",
|
||||
"class_name"
|
||||
);
|
||||
props.category_id = this.get("categoryId");
|
||||
props.category_id = this.categoryId;
|
||||
|
||||
const host = this.get("host");
|
||||
const host = this.host;
|
||||
|
||||
host
|
||||
.save(props)
|
||||
.then(() => {
|
||||
host.set(
|
||||
"category",
|
||||
Discourse.Category.findById(this.get("categoryId"))
|
||||
);
|
||||
host.set("category", Discourse.Category.findById(this.categoryId));
|
||||
this.set("editToggled", false);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
@ -58,17 +55,15 @@ export default Ember.Component.extend(bufferedProperty("host"), {
|
||||
delete() {
|
||||
bootbox.confirm(I18n.t("admin.embedding.confirm_delete"), result => {
|
||||
if (result) {
|
||||
this.get("host")
|
||||
.destroyRecord()
|
||||
.then(() => {
|
||||
this.deleteHost(this.get("host"));
|
||||
});
|
||||
this.host.destroyRecord().then(() => {
|
||||
this.deleteHost(this.host);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancel() {
|
||||
const host = this.get("host");
|
||||
const host = this.host;
|
||||
if (host.get("isNew")) {
|
||||
this.deleteHost(host);
|
||||
} else {
|
||||
|
@ -1,3 +0,0 @@
|
||||
export default Ember.Component.extend({
|
||||
classNames: ["flagged-post-response"]
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
adminTools: Ember.inject.service(),
|
||||
expanded: false,
|
||||
tagName: "div",
|
||||
classNameBindings: [
|
||||
":flagged-post",
|
||||
"flaggedPost.hidden:hidden-post",
|
||||
"flaggedPost.deleted"
|
||||
],
|
||||
|
||||
canAct: Ember.computed.alias("actableFilter"),
|
||||
|
||||
@computed("filter")
|
||||
actableFilter(filter) {
|
||||
return filter === "active";
|
||||
},
|
||||
|
||||
removeAfter(promise) {
|
||||
return promise.then(() => this.attrs.removePost());
|
||||
},
|
||||
|
||||
_spawnModal(name, model, modalClass) {
|
||||
let controller = showModal(name, { model, admin: true, modalClass });
|
||||
controller.removeAfter = p => this.removeAfter(p);
|
||||
},
|
||||
|
||||
actions: {
|
||||
removeAfter(promise) {
|
||||
return this.removeAfter(promise);
|
||||
},
|
||||
|
||||
disagree() {
|
||||
this.removeAfter(this.get("flaggedPost").disagreeFlags());
|
||||
},
|
||||
|
||||
defer() {
|
||||
this.removeAfter(this.get("flaggedPost").deferFlags());
|
||||
},
|
||||
|
||||
expand() {
|
||||
this.get("flaggedPost")
|
||||
.expandHidden()
|
||||
.then(() => {
|
||||
this.set("expanded", true);
|
||||
});
|
||||
},
|
||||
|
||||
showModerationHistory() {
|
||||
this.get("adminTools").showModerationHistory({
|
||||
filter: "post",
|
||||
post_id: this.get("flaggedPost.id")
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -12,12 +12,12 @@ export default Ember.Component.extend({
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("checkedInternal", this.get("checked"));
|
||||
this.set("checkedInternal", this.checked);
|
||||
},
|
||||
|
||||
@observes("checked")
|
||||
checkedChanged() {
|
||||
this.set("checkedInternal", this.get("checked"));
|
||||
this.set("checkedInternal", this.checked);
|
||||
},
|
||||
|
||||
@computed("labelKey")
|
||||
@ -32,11 +32,11 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
cancelled() {
|
||||
this.set("checkedInternal", this.get("checked"));
|
||||
this.set("checkedInternal", this.checked);
|
||||
},
|
||||
|
||||
finished() {
|
||||
this.set("checked", this.get("checkedInternal"));
|
||||
this.set("checked", this.checkedInternal);
|
||||
this.action();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
export default Ember.Component.extend({
|
||||
tagName: "h3"
|
||||
classNames: ["install-theme-item"]
|
||||
});
|
@ -18,18 +18,18 @@ export default Ember.Component.extend({
|
||||
lookup() {
|
||||
this.set("show", true);
|
||||
|
||||
if (!this.get("location")) {
|
||||
ajax("/admin/users/ip-info", { data: { ip: this.get("ip") } }).then(
|
||||
location => this.set("location", Ember.Object.create(location))
|
||||
if (!this.location) {
|
||||
ajax("/admin/users/ip-info", { data: { ip: this.ip } }).then(location =>
|
||||
this.set("location", Ember.Object.create(location))
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.get("other_accounts")) {
|
||||
if (!this.other_accounts) {
|
||||
this.set("otherAccountsLoading", true);
|
||||
|
||||
const data = {
|
||||
ip: this.get("ip"),
|
||||
exclude: this.get("userId"),
|
||||
ip: this.ip,
|
||||
exclude: this.userId,
|
||||
order: "trust_level DESC"
|
||||
};
|
||||
|
||||
@ -51,8 +51,8 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
copy() {
|
||||
let text = `IP: ${this.get("ip")}\n`;
|
||||
const location = this.get("location");
|
||||
let text = `IP: ${this.ip}\n`;
|
||||
const location = this.location;
|
||||
if (location) {
|
||||
if (location.hostname) {
|
||||
text += `${I18n.t("ip_lookup.hostname")}: ${location.hostname}\n`;
|
||||
@ -97,8 +97,8 @@ export default Ember.Component.extend({
|
||||
ajax("/admin/users/delete-others-with-same-ip.json", {
|
||||
type: "DELETE",
|
||||
data: {
|
||||
ip: this.get("ip"),
|
||||
exclude: this.get("userId"),
|
||||
ip: this.ip,
|
||||
exclude: this.userId,
|
||||
order: "trust_level DESC"
|
||||
}
|
||||
}).then(() => this.send("lookup"));
|
||||
|
@ -1,7 +1,9 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
const ACTIONS = ["delete", "edit", "none"];
|
||||
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
||||
|
||||
export default Ember.Component.extend({
|
||||
postId: null,
|
||||
postAction: null,
|
||||
postEdit: null,
|
||||
|
||||
@ -16,7 +18,7 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
penaltyChanged() {
|
||||
let postAction = this.get("postAction");
|
||||
let postAction = this.postAction;
|
||||
|
||||
// If we switch to edit mode, jump to the edit textarea
|
||||
if (postAction === "edit") {
|
||||
|
@ -24,13 +24,13 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
submit() {
|
||||
if (!this.get("formSubmitted")) {
|
||||
if (!this.formSubmitted) {
|
||||
this.set("formSubmitted", true);
|
||||
|
||||
Permalink.create({
|
||||
url: this.get("url"),
|
||||
permalink_type: this.get("permalinkType"),
|
||||
permalink_type_value: this.get("permalink_type_value")
|
||||
url: this.url,
|
||||
permalink_type: this.permalinkType,
|
||||
permalink_type_value: this.permalink_type_value
|
||||
})
|
||||
.save()
|
||||
.then(
|
||||
|
@ -0,0 +1,20 @@
|
||||
import Category from "discourse/models/category";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["category-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/category",
|
||||
|
||||
@computed("filter.default")
|
||||
category(categoryId) {
|
||||
return Category.findById(categoryId);
|
||||
},
|
||||
|
||||
actions: {
|
||||
onDeselect() {
|
||||
this.applyFilter(this.get("filter.id"), undefined);
|
||||
}
|
||||
}
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["file-extension-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/file-extension"
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
export default Ember.Component.extend({
|
||||
actions: {
|
||||
onChange(value) {
|
||||
this.applyFilter(this.get("filter.id"), value);
|
||||
}
|
||||
}
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["group-filter"],
|
||||
|
||||
layoutName: "admin/templates/components/report-filters/group",
|
||||
|
||||
@computed()
|
||||
groupOptions() {
|
||||
return (this.site.groups || []).map(group => {
|
||||
return { name: group["name"], value: group["id"] };
|
||||
});
|
||||
},
|
||||
|
||||
@computed("filter.default")
|
||||
groupId(filterDefault) {
|
||||
return filterDefault ? parseInt(filterDefault, 10) : null;
|
||||
}
|
||||
});
|
@ -1,5 +1,9 @@
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import { bufferedRender } from "discourse-common/lib/buffered-render";
|
||||
import {
|
||||
default as computed,
|
||||
on
|
||||
} from "ember-addons/ember-computed-decorators";
|
||||
|
||||
/*global Resumable:true */
|
||||
|
||||
@ -19,113 +23,108 @@ export default Ember.Component.extend(
|
||||
classNames: ["btn", "ru"],
|
||||
classNameBindings: ["isUploading"],
|
||||
attributeBindings: ["translatedTitle:title"],
|
||||
|
||||
resumable: null,
|
||||
|
||||
isUploading: false,
|
||||
progress: 0,
|
||||
|
||||
rerenderTriggers: ["isUploading", "progress"],
|
||||
|
||||
translatedTitle: function() {
|
||||
const title = this.get("title");
|
||||
return title ? I18n.t(title) : this.get("text");
|
||||
}.property("title", "text"),
|
||||
@on("init")
|
||||
_initialize() {
|
||||
this.resumable = new Resumable({
|
||||
target: Discourse.getURL(this.target),
|
||||
maxFiles: 1, // only 1 file at a time
|
||||
headers: {
|
||||
"X-CSRF-Token": document.querySelector("meta[name='csrf-token']")
|
||||
.content
|
||||
}
|
||||
});
|
||||
|
||||
text: function() {
|
||||
if (this.get("isUploading")) {
|
||||
return this.get("progress") + " %";
|
||||
} else {
|
||||
return this.get("uploadText");
|
||||
}
|
||||
}.property("isUploading", "progress"),
|
||||
this.resumable.on("fileAdded", () => {
|
||||
// automatically upload the selected file
|
||||
this.resumable.upload();
|
||||
|
||||
buildBuffer(buffer) {
|
||||
const icon = this.get("isUploading") ? "times" : "upload";
|
||||
buffer.push(iconHTML(icon));
|
||||
buffer.push("<span class='ru-label'>" + this.get("text") + "</span>");
|
||||
buffer.push(
|
||||
"<span class='ru-progress' style='width:" +
|
||||
this.get("progress") +
|
||||
"%'></span>"
|
||||
// mark as uploading
|
||||
Ember.run.later(() => this.set("isUploading", true));
|
||||
});
|
||||
|
||||
this.resumable.on("fileProgress", file => {
|
||||
// update progress
|
||||
Ember.run.later(() =>
|
||||
this.set("progress", parseInt(file.progress() * 100, 10))
|
||||
);
|
||||
});
|
||||
|
||||
this.resumable.on("fileSuccess", file => {
|
||||
Ember.run.later(() => {
|
||||
// mark as not uploading anymore
|
||||
this._reset();
|
||||
|
||||
// fire an event to allow the parent route to reload its model
|
||||
this.success(file.fileName);
|
||||
});
|
||||
});
|
||||
|
||||
this.resumable.on("fileError", (file, message) => {
|
||||
Ember.run.later(() => {
|
||||
// mark as not uploading anymore
|
||||
this._reset();
|
||||
|
||||
// fire an event to allow the parent route to display the error message
|
||||
this.error(file.fileName, message);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@on("didInsertElement")
|
||||
_assignBrowse() {
|
||||
Ember.run.schedule("afterRender", () =>
|
||||
this.resumable.assignBrowse($(this.element))
|
||||
);
|
||||
},
|
||||
|
||||
click: function() {
|
||||
if (this.get("isUploading")) {
|
||||
@on("willDestroyElement")
|
||||
_teardown() {
|
||||
if (this.resumable) {
|
||||
this.resumable.cancel();
|
||||
var self = this;
|
||||
Ember.run.later(function() {
|
||||
self._reset();
|
||||
});
|
||||
this.resumable = null;
|
||||
}
|
||||
},
|
||||
|
||||
@computed("title", "text")
|
||||
translatedTitle(title, text) {
|
||||
return title ? I18n.t(title) : text;
|
||||
},
|
||||
|
||||
@computed("isUploading", "progress")
|
||||
text(isUploading, progress) {
|
||||
if (isUploading) {
|
||||
return progress + " %";
|
||||
} else {
|
||||
return this.uploadText;
|
||||
}
|
||||
},
|
||||
|
||||
buildBuffer(buffer) {
|
||||
const icon = this.isUploading ? "times" : "upload";
|
||||
buffer.push(iconHTML(icon));
|
||||
buffer.push("<span class='ru-label'>" + this.text + "</span>");
|
||||
buffer.push(
|
||||
"<span class='ru-progress' style='width:" + this.progress + "%'></span>"
|
||||
);
|
||||
},
|
||||
|
||||
click() {
|
||||
if (this.isUploading) {
|
||||
this.resumable.cancel();
|
||||
Ember.run.later(() => this._reset());
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
_reset: function() {
|
||||
_reset() {
|
||||
this.setProperties({ isUploading: false, progress: 0 });
|
||||
},
|
||||
|
||||
_initialize: function() {
|
||||
this.resumable = new Resumable({
|
||||
target: Discourse.getURL(this.get("target")),
|
||||
maxFiles: 1, // only 1 file at a time
|
||||
headers: {
|
||||
"X-CSRF-Token": $("meta[name='csrf-token']").attr("content")
|
||||
}
|
||||
});
|
||||
|
||||
var self = this;
|
||||
|
||||
this.resumable.on("fileAdded", function() {
|
||||
// automatically upload the selected file
|
||||
self.resumable.upload();
|
||||
// mark as uploading
|
||||
Ember.run.later(function() {
|
||||
self.set("isUploading", true);
|
||||
});
|
||||
});
|
||||
|
||||
this.resumable.on("fileProgress", function(file) {
|
||||
// update progress
|
||||
Ember.run.later(function() {
|
||||
self.set("progress", parseInt(file.progress() * 100, 10));
|
||||
});
|
||||
});
|
||||
|
||||
this.resumable.on("fileSuccess", function(file) {
|
||||
Ember.run.later(function() {
|
||||
// mark as not uploading anymore
|
||||
self._reset();
|
||||
// fire an event to allow the parent route to reload its model
|
||||
self.success(file.fileName);
|
||||
});
|
||||
});
|
||||
|
||||
this.resumable.on("fileError", function(file, message) {
|
||||
Ember.run.later(function() {
|
||||
// mark as not uploading anymore
|
||||
self._reset();
|
||||
// fire an event to allow the parent route to display the error message
|
||||
self.error(file.fileName, message);
|
||||
});
|
||||
});
|
||||
}.on("init"),
|
||||
|
||||
_assignBrowse: function() {
|
||||
var self = this;
|
||||
Ember.run.schedule("afterRender", function() {
|
||||
self.resumable.assignBrowse(self.$());
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
_teardown: function() {
|
||||
if (this.resumable) {
|
||||
this.resumable.cancel();
|
||||
this.resumable = null;
|
||||
}
|
||||
}.on("willDestroyElement")
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -50,11 +50,11 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
submit() {
|
||||
if (!this.get("formSubmitted")) {
|
||||
if (!this.formSubmitted) {
|
||||
this.set("formSubmitted", true);
|
||||
const screenedIpAddress = ScreenedIpAddress.create({
|
||||
ip_address: this.get("ip_address"),
|
||||
action_name: this.get("actionName")
|
||||
ip_address: this.ip_address,
|
||||
action_name: this.actionName
|
||||
});
|
||||
screenedIpAddress
|
||||
.save()
|
||||
|
@ -9,11 +9,11 @@ export default Ember.Component.extend({
|
||||
|
||||
@on("didReceiveAttrs")
|
||||
_setupCollection() {
|
||||
const values = this.get("values");
|
||||
const values = this.values;
|
||||
|
||||
this.set(
|
||||
"collection",
|
||||
this._splitValues(values, this.get("inputDelimiter") || "\n")
|
||||
this._splitValues(values, this.inputDelimiter || "\n")
|
||||
);
|
||||
},
|
||||
|
||||
@ -29,9 +29,8 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
addValue() {
|
||||
if (this._checkInvalidInput([this.get("newKey"), this.get("newSecret")]))
|
||||
return;
|
||||
this._addValue(this.get("newKey"), this.get("newSecret"));
|
||||
if (this._checkInvalidInput([this.newKey, this.newSecret])) return;
|
||||
this._addValue(this.newKey, this.newSecret);
|
||||
this.setProperties({ newKey: "", newSecret: "" });
|
||||
},
|
||||
|
||||
@ -54,18 +53,18 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
_addValue(value, secret) {
|
||||
this.get("collection").addObject({ key: value, secret: secret });
|
||||
this.collection.addObject({ key: value, secret: secret });
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_removeValue(value) {
|
||||
const collection = this.get("collection");
|
||||
const collection = this.collection;
|
||||
collection.removeObject(value);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_replaceValue(index, newValue, keyName) {
|
||||
let item = this.get("collection")[index];
|
||||
let item = this.collection[index];
|
||||
Ember.set(item, keyName, newValue);
|
||||
|
||||
this._saveValues();
|
||||
@ -74,7 +73,7 @@ export default Ember.Component.extend({
|
||||
_saveValues() {
|
||||
this.set(
|
||||
"values",
|
||||
this.get("collection")
|
||||
this.collection
|
||||
.map(function(elem) {
|
||||
return `${elem.key}|${elem.secret}`;
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ import SettingComponent from "admin/mixins/setting-component";
|
||||
|
||||
export default Ember.Component.extend(BufferedContent, SettingComponent, {
|
||||
_save() {
|
||||
const setting = this.get("buffered");
|
||||
const setting = this.buffered;
|
||||
return SiteSetting.update(setting.get("setting"), setting.get("value"));
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,8 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
@computed()
|
||||
groupChoices() {
|
||||
return this.site.get("groups").map(g => g.name);
|
||||
}
|
||||
});
|
@ -17,18 +17,18 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
click() {
|
||||
this.send("edit");
|
||||
this.editAction(this.siteText);
|
||||
},
|
||||
|
||||
_searchTerm() {
|
||||
const regex = this.get("searchRegex");
|
||||
const siteText = this.get("siteText");
|
||||
const regex = this.searchRegex;
|
||||
const siteText = this.siteText;
|
||||
|
||||
if (regex && siteText) {
|
||||
const matches = siteText.value.match(new RegExp(regex, "i"));
|
||||
if (matches) return matches[0];
|
||||
}
|
||||
|
||||
return this.get("term");
|
||||
return this.term;
|
||||
}
|
||||
});
|
||||
|
@ -4,7 +4,7 @@ import SettingComponent from "admin/mixins/setting-component";
|
||||
export default Ember.Component.extend(BufferedContent, SettingComponent, {
|
||||
layoutName: "admin/templates/components/site-setting",
|
||||
_save() {
|
||||
return this.get("model").saveSettings(
|
||||
return this.model.saveSettings(
|
||||
this.get("setting.setting"),
|
||||
this.get("buffered.value")
|
||||
);
|
||||
|
@ -8,7 +8,7 @@ export default Ember.Component.extend(BufferedContent, SettingComponent, {
|
||||
settingName: Ember.computed.alias("translation.key"),
|
||||
|
||||
_save() {
|
||||
return this.get("model").saveTranslation(
|
||||
return this.model.saveTranslation(
|
||||
this.get("translation.key"),
|
||||
this.get("buffered.value")
|
||||
);
|
||||
|
@ -56,12 +56,12 @@ export default Ember.Component.extend({
|
||||
"childrenExpanded"
|
||||
)
|
||||
children() {
|
||||
const theme = this.get("theme");
|
||||
const theme = this.theme;
|
||||
let children = theme.get("childThemes");
|
||||
if (theme.get("component") || !children) {
|
||||
return [];
|
||||
}
|
||||
children = this.get("childrenExpanded")
|
||||
children = this.childrenExpanded
|
||||
? children
|
||||
: children.slice(0, MAX_COMPONENTS);
|
||||
return children.map(t => t.get("name"));
|
||||
|
@ -16,7 +16,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@computed("themes", "components", "currentTab")
|
||||
themesList(themes, components) {
|
||||
if (this.get("themesTabActive")) {
|
||||
if (this.themesTabActive) {
|
||||
return themes;
|
||||
} else {
|
||||
return components;
|
||||
@ -30,7 +30,7 @@ export default Ember.Component.extend({
|
||||
"themesList.@each.default"
|
||||
)
|
||||
inactiveThemes(themes) {
|
||||
if (this.get("componentsTabActive")) {
|
||||
if (this.componentsTabActive) {
|
||||
return themes.filter(theme => theme.get("parent_themes.length") <= 0);
|
||||
}
|
||||
return themes.filter(
|
||||
@ -45,7 +45,7 @@ export default Ember.Component.extend({
|
||||
"themesList.@each.default"
|
||||
)
|
||||
activeThemes(themes) {
|
||||
if (this.get("componentsTabActive")) {
|
||||
if (this.componentsTabActive) {
|
||||
return themes.filter(theme => theme.get("parent_themes.length") > 0);
|
||||
} else {
|
||||
themes = themes.filter(
|
||||
@ -61,21 +61,9 @@ export default Ember.Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
didRender() {
|
||||
this._super(...arguments);
|
||||
|
||||
// hide scrollbar
|
||||
const $container = this.$(".themes-list-container");
|
||||
const containerNode = $container[0];
|
||||
if (containerNode) {
|
||||
const width = containerNode.offsetWidth - containerNode.clientWidth;
|
||||
$container.css("width", `calc(100% + ${width}px)`);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
changeView(newTab) {
|
||||
if (newTab !== this.get("currentTab")) {
|
||||
if (newTab !== this.currentTab) {
|
||||
this.set("currentTab", newTab);
|
||||
}
|
||||
},
|
||||
|
@ -15,15 +15,15 @@ export default Ember.Component.extend({
|
||||
|
||||
@on("didReceiveAttrs")
|
||||
_setupCollection() {
|
||||
const values = this.get("values");
|
||||
if (this.get("inputType") === "array") {
|
||||
const values = this.values;
|
||||
if (this.inputType === "array") {
|
||||
this.set("collection", values || []);
|
||||
return;
|
||||
}
|
||||
|
||||
this.set(
|
||||
"collection",
|
||||
this._splitValues(values, this.get("inputDelimiter") || "\n")
|
||||
this._splitValues(values, this.inputDelimiter || "\n")
|
||||
);
|
||||
},
|
||||
|
||||
@ -33,7 +33,7 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
keyDown(event) {
|
||||
if (event.keyCode === 13) this.send("addValue", this.get("newValue"));
|
||||
if (event.keyCode === 13) this.send("addValue", this.newValue);
|
||||
},
|
||||
|
||||
actions: {
|
||||
@ -42,7 +42,7 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
addValue(newValue) {
|
||||
if (this.get("inputInvalid")) return;
|
||||
if (this.inputInvalid) return;
|
||||
|
||||
this.set("newValue", "");
|
||||
this._addValue(newValue);
|
||||
@ -58,31 +58,28 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
_addValue(value) {
|
||||
this.get("collection").addObject(value);
|
||||
this.collection.addObject(value);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_removeValue(value) {
|
||||
const collection = this.get("collection");
|
||||
const collection = this.collection;
|
||||
collection.removeObject(value);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_replaceValue(index, newValue) {
|
||||
this.get("collection").replace(index, 1, [newValue]);
|
||||
this.collection.replace(index, 1, [newValue]);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_saveValues() {
|
||||
if (this.get("inputType") === "array") {
|
||||
this.set("values", this.get("collection"));
|
||||
if (this.inputType === "array") {
|
||||
this.set("values", this.collection);
|
||||
return;
|
||||
}
|
||||
|
||||
this.set(
|
||||
"values",
|
||||
this.get("collection").join(this.get("inputDelimiter") || "\n")
|
||||
);
|
||||
this.set("values", this.collection.join(this.inputDelimiter || "\n"));
|
||||
},
|
||||
|
||||
_splitValues(values, delimiter) {
|
||||
|
@ -21,17 +21,15 @@ export default Ember.Component.extend({
|
||||
|
||||
@observes("word")
|
||||
removeMessage() {
|
||||
if (this.get("showMessage") && !Ember.isEmpty(this.get("word"))) {
|
||||
if (this.showMessage && !Ember.isEmpty(this.word)) {
|
||||
this.set("showMessage", false);
|
||||
}
|
||||
},
|
||||
|
||||
@computed("word")
|
||||
isUniqueWord(word) {
|
||||
const words = this.get("filteredContent") || [];
|
||||
const filtered = words.filter(
|
||||
content => content.action === this.get("actionKey")
|
||||
);
|
||||
const words = this.filteredContent || [];
|
||||
const filtered = words.filter(content => content.action === this.actionKey);
|
||||
return filtered.every(
|
||||
content => content.word.toLowerCase() !== word.toLowerCase()
|
||||
);
|
||||
@ -39,7 +37,7 @@ export default Ember.Component.extend({
|
||||
|
||||
actions: {
|
||||
submit() {
|
||||
if (!this.get("isUniqueWord")) {
|
||||
if (!this.isUniqueWord) {
|
||||
this.setProperties({
|
||||
showMessage: true,
|
||||
message: I18n.t("admin.watched_words.form.exists")
|
||||
@ -47,12 +45,12 @@ export default Ember.Component.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.get("formSubmitted")) {
|
||||
if (!this.formSubmitted) {
|
||||
this.set("formSubmitted", true);
|
||||
|
||||
const watchedWord = WatchedWord.create({
|
||||
word: this.get("word"),
|
||||
action: this.get("actionKey")
|
||||
word: this.word,
|
||||
action: this.actionKey
|
||||
});
|
||||
|
||||
watchedWord
|
||||
|
@ -9,7 +9,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
actions: {
|
||||
generateMasterKey() {
|
||||
ApiKey.generateMasterKey().then(key => this.get("model").pushObject(key));
|
||||
ApiKey.generateMasterKey().then(key => this.model.pushObject(key));
|
||||
},
|
||||
|
||||
regenerateKey(key) {
|
||||
@ -32,7 +32,7 @@ export default Ember.Controller.extend({
|
||||
I18n.t("yes_value"),
|
||||
result => {
|
||||
if (result) {
|
||||
key.revoke().then(() => this.get("model").removeObject(key));
|
||||
key.revoke().then(() => this.model.removeObject(key));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -1,5 +1,10 @@
|
||||
export default Ember.Controller.extend({
|
||||
logs: [],
|
||||
adminBackups: Ember.inject.controller(),
|
||||
status: Ember.computed.alias("adminBackups.model")
|
||||
status: Ember.computed.alias("adminBackups.model"),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.logs = [];
|
||||
}
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { propertyNotEqual } from "discourse/lib/computed";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
adminBadges: Ember.inject.controller(),
|
||||
@ -17,14 +18,13 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
readOnly: Ember.computed.alias("buffered.system"),
|
||||
showDisplayName: propertyNotEqual("name", "displayName"),
|
||||
|
||||
hasQuery: function() {
|
||||
const bQuery = this.get("buffered.query");
|
||||
if (bQuery) {
|
||||
return bQuery.trim().length > 0;
|
||||
@computed("model.query", "buffered.query")
|
||||
hasQuery(modelQuery, bufferedQuery) {
|
||||
if (bufferedQuery) {
|
||||
return bufferedQuery.trim().length > 0;
|
||||
}
|
||||
const mQuery = this.get("model.query");
|
||||
return mQuery && mQuery.trim().length > 0;
|
||||
}.property("model.query", "buffered.query"),
|
||||
return modelQuery && modelQuery.trim().length > 0;
|
||||
},
|
||||
|
||||
_resetSaving: function() {
|
||||
this.set("saving", false);
|
||||
@ -33,7 +33,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
if (!this.get("saving")) {
|
||||
if (!this.saving) {
|
||||
let fields = [
|
||||
"allow_title",
|
||||
"multiple_grant",
|
||||
@ -54,7 +54,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
];
|
||||
|
||||
if (this.get("buffered.system")) {
|
||||
var protectedFields = this.get("protectedSystemFields") || [];
|
||||
var protectedFields = this.protectedSystemFields || [];
|
||||
fields = _.filter(fields, f => !protectedFields.includes(f));
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
];
|
||||
|
||||
const data = {};
|
||||
const buffered = this.get("buffered");
|
||||
const buffered = this.buffered;
|
||||
fields.forEach(function(field) {
|
||||
var d = buffered.get(field);
|
||||
if (boolFields.includes(field)) {
|
||||
@ -81,9 +81,9 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
data[field] = d;
|
||||
});
|
||||
|
||||
const newBadge = !this.get("id");
|
||||
const model = this.get("model");
|
||||
this.get("model")
|
||||
const newBadge = !this.id;
|
||||
const model = this.model;
|
||||
this.model
|
||||
.save(data)
|
||||
.then(() => {
|
||||
if (newBadge) {
|
||||
@ -107,7 +107,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), {
|
||||
|
||||
destroy() {
|
||||
const adminBadges = this.get("adminBadges.model");
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
|
||||
if (!model.get("id")) {
|
||||
this.transitionToRoute("adminBadges.index");
|
||||
|
@ -23,7 +23,7 @@ export default Ember.Controller.extend({
|
||||
$(".table.colors").hide();
|
||||
let area = $("<textarea id='copy-range'></textarea>");
|
||||
$(".table.colors").after(area);
|
||||
area.text(this.get("model").schemeJson());
|
||||
area.text(this.model.schemeJson());
|
||||
let range = document.createRange();
|
||||
range.selectNode(area[0]);
|
||||
window.getSelection().addRange(range);
|
||||
@ -51,7 +51,7 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
copy() {
|
||||
var newColorScheme = Ember.copy(this.get("model"), true);
|
||||
var newColorScheme = Ember.copy(this.model, true);
|
||||
newColorScheme.set(
|
||||
"name",
|
||||
I18n.t("admin.customize.colors.copy_name_prefix") +
|
||||
@ -59,17 +59,17 @@ export default Ember.Controller.extend({
|
||||
this.get("model.name")
|
||||
);
|
||||
newColorScheme.save().then(() => {
|
||||
this.get("allColors").pushObject(newColorScheme);
|
||||
this.allColors.pushObject(newColorScheme);
|
||||
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
||||
});
|
||||
},
|
||||
|
||||
save: function() {
|
||||
this.get("model").save();
|
||||
this.model.save();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
return bootbox.confirm(
|
||||
I18n.t("admin.customize.colors.delete_confirm"),
|
||||
I18n.t("no_value"),
|
||||
@ -77,7 +77,7 @@ export default Ember.Controller.extend({
|
||||
result => {
|
||||
if (result) {
|
||||
model.destroy().then(() => {
|
||||
this.get("allColors").removeObject(model);
|
||||
this.allColors.removeObject(model);
|
||||
this.replaceRoute("adminCustomize.colors");
|
||||
});
|
||||
}
|
||||
|
@ -1,33 +1,36 @@
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
baseColorScheme: function() {
|
||||
return this.get("model").findBy("is_base", true);
|
||||
}.property("model.@each.id"),
|
||||
@computed("model.@each.id")
|
||||
baseColorScheme() {
|
||||
return this.model.findBy("is_base", true);
|
||||
},
|
||||
|
||||
baseColorSchemes: function() {
|
||||
return this.get("model").filterBy("is_base", true);
|
||||
}.property("model.@each.id"),
|
||||
@computed("model.@each.id")
|
||||
baseColorSchemes() {
|
||||
return this.model.filterBy("is_base", true);
|
||||
},
|
||||
|
||||
baseColors: function() {
|
||||
var baseColorsHash = Ember.Object.create({});
|
||||
this.get("baseColorScheme.colors").forEach(color => {
|
||||
@computed("baseColorScheme")
|
||||
baseColors(baseColorScheme) {
|
||||
const baseColorsHash = Ember.Object.create({});
|
||||
baseColorScheme.get("colors").forEach(color => {
|
||||
baseColorsHash.set(color.get("name"), color);
|
||||
});
|
||||
return baseColorsHash;
|
||||
}.property("baseColorScheme"),
|
||||
},
|
||||
|
||||
actions: {
|
||||
newColorSchemeWithBase(baseKey) {
|
||||
const base = this.get("baseColorSchemes").findBy(
|
||||
"base_scheme_id",
|
||||
baseKey
|
||||
);
|
||||
const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey);
|
||||
const newColorScheme = Ember.copy(base, true);
|
||||
newColorScheme.set("name", I18n.t("admin.customize.colors.new_name"));
|
||||
newColorScheme.set("base_scheme_id", base.get("base_scheme_id"));
|
||||
newColorScheme.setProperties({
|
||||
name: I18n.t("admin.customize.colors.new_name"),
|
||||
base_scheme_id: base.get("base_scheme_id")
|
||||
});
|
||||
newColorScheme.save().then(() => {
|
||||
this.get("model").pushObject(newColorScheme);
|
||||
this.model.pushObject(newColorScheme);
|
||||
newColorScheme.set("savingStatus", null);
|
||||
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
||||
});
|
||||
@ -35,7 +38,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
newColorScheme() {
|
||||
showModal("admin-color-scheme-select-base", {
|
||||
model: this.get("baseColorSchemes"),
|
||||
model: this.baseColorSchemes,
|
||||
admin: true
|
||||
});
|
||||
}
|
||||
|
@ -1,23 +1,24 @@
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend(bufferedProperty("emailTemplate"), {
|
||||
saved: false,
|
||||
|
||||
hasMultipleSubjects: function() {
|
||||
const buffered = this.get("buffered");
|
||||
@computed("buffered")
|
||||
hasMultipleSubjects(buffered) {
|
||||
if (buffered.getProperties("subject")["subject"]) {
|
||||
return false;
|
||||
} else {
|
||||
return buffered.getProperties("id")["id"];
|
||||
}
|
||||
}.property("buffered"),
|
||||
},
|
||||
|
||||
actions: {
|
||||
saveChanges() {
|
||||
this.set("saved", false);
|
||||
const buffered = this.get("buffered");
|
||||
this.get("emailTemplate")
|
||||
const buffered = this.buffered;
|
||||
this.emailTemplate
|
||||
.save(buffered.getProperties("subject", "body"))
|
||||
.then(() => {
|
||||
this.set("saved", true);
|
||||
@ -31,10 +32,10 @@ export default Ember.Controller.extend(bufferedProperty("emailTemplate"), {
|
||||
I18n.t("admin.customize.email_templates.revert_confirm"),
|
||||
result => {
|
||||
if (result) {
|
||||
this.get("emailTemplate")
|
||||
this.emailTemplate
|
||||
.revert()
|
||||
.then(props => {
|
||||
const buffered = this.get("buffered");
|
||||
const buffered = this.buffered;
|
||||
buffered.setProperties(props);
|
||||
this.commitBuffer();
|
||||
})
|
||||
|
@ -1,6 +1,10 @@
|
||||
export default Ember.Controller.extend({
|
||||
titleSorting: ["title"],
|
||||
emailTemplates: null,
|
||||
sortedTemplates: Ember.computed.sort("emailTemplates", "titleSorting"),
|
||||
|
||||
sortedTemplates: Ember.computed.sort("emailTemplates", "titleSorting")
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.titleSorting = ["title"];
|
||||
}
|
||||
});
|
||||
|
@ -1,163 +1,28 @@
|
||||
import { url } from "discourse/lib/computed";
|
||||
import {
|
||||
default as computed,
|
||||
observes
|
||||
} from "ember-addons/ember-computed-decorators";
|
||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
section: null,
|
||||
currentTarget: 0,
|
||||
maximized: false,
|
||||
previewUrl: url("model.id", "/admin/themes/%@/preview"),
|
||||
|
||||
showAdvanced: false,
|
||||
editRouteName: "adminCustomizeThemes.edit",
|
||||
|
||||
targets: [
|
||||
{ id: 0, name: "common" },
|
||||
{ id: 1, name: "desktop" },
|
||||
{ id: 2, name: "mobile" },
|
||||
{ id: 3, name: "settings" },
|
||||
{ id: 4, name: "translations" }
|
||||
],
|
||||
|
||||
fieldsForTarget: function(target) {
|
||||
const common = [
|
||||
"scss",
|
||||
"head_tag",
|
||||
"header",
|
||||
"after_header",
|
||||
"body_tag",
|
||||
"footer"
|
||||
];
|
||||
switch (target) {
|
||||
case "common":
|
||||
return [...common, "embedded_scss"];
|
||||
case "desktop":
|
||||
return common;
|
||||
case "mobile":
|
||||
return common;
|
||||
case "settings":
|
||||
return ["yaml"];
|
||||
}
|
||||
},
|
||||
|
||||
@computed("onlyOverridden")
|
||||
showCommon() {
|
||||
return this.shouldShow("common");
|
||||
},
|
||||
|
||||
@computed("onlyOverridden")
|
||||
showDesktop() {
|
||||
return this.shouldShow("desktop");
|
||||
},
|
||||
|
||||
@computed("onlyOverridden")
|
||||
showMobile() {
|
||||
return this.shouldShow("mobile");
|
||||
},
|
||||
|
||||
@observes("onlyOverridden")
|
||||
onlyOverriddenChanged() {
|
||||
if (this.get("onlyOverridden")) {
|
||||
if (
|
||||
!this.get("model").hasEdited(
|
||||
this.get("currentTargetName"),
|
||||
this.get("fieldName")
|
||||
)
|
||||
) {
|
||||
let target =
|
||||
(this.get("showCommon") && "common") ||
|
||||
(this.get("showDesktop") && "desktop") ||
|
||||
(this.get("showMobile") && "mobile");
|
||||
|
||||
let fields = this.get("model.theme_fields");
|
||||
let field = fields && fields.find(f => f.target === target);
|
||||
this.replaceRoute(
|
||||
this.get("editRouteName"),
|
||||
this.get("model.id"),
|
||||
target,
|
||||
field && field.name
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
shouldShow(target) {
|
||||
if (!this.get("onlyOverridden")) {
|
||||
return true;
|
||||
}
|
||||
return this.get("model").hasEdited(target);
|
||||
},
|
||||
showRouteName: "adminCustomizeThemes.show",
|
||||
|
||||
setTargetName: function(name) {
|
||||
const target = this.get("targets").find(t => t.name === name);
|
||||
const target = this.get("model.targets").find(t => t.name === name);
|
||||
this.set("currentTarget", target && target.id);
|
||||
},
|
||||
|
||||
@computed("currentTarget")
|
||||
currentTargetName(id) {
|
||||
const target = this.get("targets").find(t => t.id === parseInt(id, 10));
|
||||
const target = this.get("model.targets").find(
|
||||
t => t.id === parseInt(id, 10)
|
||||
);
|
||||
return target && target.name;
|
||||
},
|
||||
|
||||
@computed("fieldName")
|
||||
activeSectionMode(fieldName) {
|
||||
if (fieldName === "yaml") return "yaml";
|
||||
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "fieldName", "saving")
|
||||
error(target, fieldName) {
|
||||
return this.get("model").getError(target, fieldName);
|
||||
},
|
||||
|
||||
@computed("fieldName", "currentTargetName")
|
||||
editorId(fieldName, currentTarget) {
|
||||
return fieldName + "|" + currentTarget;
|
||||
},
|
||||
|
||||
@computed("fieldName", "currentTargetName", "model")
|
||||
activeSection: {
|
||||
get(fieldName, target, model) {
|
||||
return model.getField(target, fieldName);
|
||||
},
|
||||
set(value, fieldName, target, model) {
|
||||
model.setField(target, fieldName, value);
|
||||
return value;
|
||||
}
|
||||
},
|
||||
|
||||
@computed("currentTargetName", "onlyOverridden")
|
||||
fields(target, onlyOverridden) {
|
||||
let fields = this.fieldsForTarget(target);
|
||||
|
||||
if (onlyOverridden) {
|
||||
const model = this.get("model");
|
||||
const targetName = this.get("currentTargetName");
|
||||
fields = fields.filter(name => model.hasEdited(targetName, name));
|
||||
}
|
||||
|
||||
return fields.map(name => {
|
||||
let hash = {
|
||||
key: `admin.customize.theme.${name}.text`,
|
||||
name: name
|
||||
};
|
||||
|
||||
if (name.indexOf("_tag") > 0) {
|
||||
hash.icon = "file-text-o";
|
||||
}
|
||||
|
||||
hash.title = I18n.t(`admin.customize.theme.${name}.title`);
|
||||
|
||||
return hash;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("maximized")
|
||||
maximizeIcon(maximized) {
|
||||
return maximized ? "discourse-compress" : "discourse-expand";
|
||||
},
|
||||
|
||||
@computed("model.isSaving")
|
||||
saveButtonText(isSaving) {
|
||||
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
||||
@ -171,18 +36,31 @@ export default Ember.Controller.extend({
|
||||
actions: {
|
||||
save() {
|
||||
this.set("saving", true);
|
||||
this.get("model")
|
||||
.saveChanges("theme_fields")
|
||||
.finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
this.model.saveChanges("theme_fields").finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
},
|
||||
|
||||
toggleMaximize: function() {
|
||||
this.toggleProperty("maximized");
|
||||
Ember.run.next(() => {
|
||||
this.appEvents.trigger("ace:resize");
|
||||
});
|
||||
fieldAdded(target, name) {
|
||||
this.replaceRoute(this.editRouteName, this.get("model.id"), target, name);
|
||||
},
|
||||
|
||||
onlyOverriddenChanged(onlyShowOverridden) {
|
||||
if (onlyShowOverridden) {
|
||||
if (!this.model.hasEdited(this.currentTargetName, this.fieldName)) {
|
||||
let firstTarget = this.get("model.targets").find(t => t.edited);
|
||||
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
|
||||
f => f.edited
|
||||
);
|
||||
|
||||
this.replaceRoute(
|
||||
this.editRouteName,
|
||||
this.get("model.id"),
|
||||
firstTarget.name,
|
||||
firstField.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -100,7 +100,7 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
commitSwitchType() {
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
const newValue = !model.get("component");
|
||||
model.set("component", newValue);
|
||||
|
||||
@ -141,16 +141,20 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
transitionToEditRoute() {
|
||||
this.transitionToRoute(
|
||||
this.get("editRouteName"),
|
||||
this.editRouteName,
|
||||
this.get("model.id"),
|
||||
"common",
|
||||
"scss"
|
||||
);
|
||||
},
|
||||
sourceIsHttp: Ember.computed.match(
|
||||
"model.remote_theme.remote_url",
|
||||
/^http(s)?:\/\//
|
||||
),
|
||||
actions: {
|
||||
updateToLatest() {
|
||||
this.set("updatingRemote", true);
|
||||
this.get("model")
|
||||
this.model
|
||||
.updateToLatest()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
@ -160,7 +164,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
checkForThemeUpdates() {
|
||||
this.set("updatingRemote", true);
|
||||
this.get("model")
|
||||
this.model
|
||||
.checkForUpdates()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
@ -173,7 +177,7 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
addUpload(info) {
|
||||
let model = this.get("model");
|
||||
let model = this.model;
|
||||
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
||||
model.saveChanges("theme_fields").catch(e => popupAjaxError(e));
|
||||
},
|
||||
@ -182,23 +186,23 @@ export default Ember.Controller.extend({
|
||||
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
||||
},
|
||||
changeScheme() {
|
||||
let schemeId = this.get("colorSchemeId");
|
||||
let schemeId = this.colorSchemeId;
|
||||
this.set(
|
||||
"model.color_scheme_id",
|
||||
schemeId === null ? null : parseInt(schemeId)
|
||||
);
|
||||
this.get("model").saveChanges("color_scheme_id");
|
||||
this.model.saveChanges("color_scheme_id");
|
||||
},
|
||||
startEditingName() {
|
||||
this.set("oldName", this.get("model.name"));
|
||||
this.set("editingName", true);
|
||||
},
|
||||
cancelEditingName() {
|
||||
this.set("model.name", this.get("oldName"));
|
||||
this.set("model.name", this.oldName);
|
||||
this.set("editingName", false);
|
||||
},
|
||||
finishedEditingName() {
|
||||
this.get("model").saveChanges("name");
|
||||
this.model.saveChanges("name");
|
||||
this.set("editingName", false);
|
||||
},
|
||||
|
||||
@ -218,10 +222,10 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
applyDefault() {
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
model.saveChanges("default").then(() => {
|
||||
if (model.get("default")) {
|
||||
this.get("allThemes").forEach(theme => {
|
||||
this.allThemes.forEach(theme => {
|
||||
if (theme !== model && theme.get("default")) {
|
||||
theme.set("default", false);
|
||||
}
|
||||
@ -231,13 +235,13 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
applyUserSelectable() {
|
||||
this.get("model").saveChanges("user_selectable");
|
||||
this.model.saveChanges("user_selectable");
|
||||
},
|
||||
|
||||
addChildTheme() {
|
||||
let themeId = parseInt(this.get("selectedChildThemeId"));
|
||||
let theme = this.get("allThemes").findBy("id", themeId);
|
||||
this.get("model").addChildTheme(theme);
|
||||
let themeId = parseInt(this.selectedChildThemeId);
|
||||
let theme = this.allThemes.findBy("id", themeId);
|
||||
this.model.addChildTheme(theme);
|
||||
},
|
||||
|
||||
removeUpload(upload) {
|
||||
@ -247,26 +251,28 @@ export default Ember.Controller.extend({
|
||||
I18n.t("yes_value"),
|
||||
result => {
|
||||
if (result) {
|
||||
this.get("model").removeField(upload);
|
||||
this.model.removeField(upload);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
removeChildTheme(theme) {
|
||||
this.get("model").removeChildTheme(theme);
|
||||
this.model.removeChildTheme(theme);
|
||||
},
|
||||
|
||||
destroy() {
|
||||
return bootbox.confirm(
|
||||
I18n.t("admin.customize.delete_confirm"),
|
||||
I18n.t("admin.customize.delete_confirm", {
|
||||
theme_name: this.get("model.name")
|
||||
}),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
result => {
|
||||
if (result) {
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
model.destroyRecord().then(() => {
|
||||
this.get("allThemes").removeObject(model);
|
||||
this.allThemes.removeObject(model);
|
||||
this.transitionToRoute("adminCustomizeThemes");
|
||||
});
|
||||
}
|
||||
@ -276,12 +282,12 @@ export default Ember.Controller.extend({
|
||||
|
||||
switchType() {
|
||||
const relatives = this.get("model.component")
|
||||
? this.get("parentThemes")
|
||||
? this.parentThemes
|
||||
: this.get("model.childThemes");
|
||||
if (relatives && relatives.length > 0) {
|
||||
const names = relatives.map(relative => relative.get("name"));
|
||||
bootbox.confirm(
|
||||
I18n.t(`${this.get("convertKey")}_alert`, {
|
||||
I18n.t(`${this.convertKey}_alert`, {
|
||||
relatives: names.join(", ")
|
||||
}),
|
||||
I18n.t("no_value"),
|
||||
|
@ -12,5 +12,10 @@ export default Ember.Controller.extend({
|
||||
@computed("model", "model.@each.component")
|
||||
childThemes(themes) {
|
||||
return themes.filter(t => t.get("component"));
|
||||
},
|
||||
|
||||
@computed("model", "model.@each.component")
|
||||
installedThemes(themes) {
|
||||
return themes.map(t => t.name);
|
||||
}
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import AdminDashboardNext from "admin/models/admin-dashboard-next";
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import Report from "admin/models/report";
|
||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||
|
||||
function staticReport(reportType) {
|
||||
return function() {
|
||||
return Ember.makeArray(this.get("reports")).find(
|
||||
return Ember.makeArray(this.reports).find(
|
||||
report => report.type === reportType
|
||||
);
|
||||
}.property("reports.[]");
|
||||
@ -27,8 +27,8 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
|
||||
@computed
|
||||
activityMetricsFilters() {
|
||||
return {
|
||||
startDate: this.get("lastMonth"),
|
||||
endDate: this.get("today")
|
||||
startDate: this.lastMonth,
|
||||
endDate: this.today
|
||||
};
|
||||
},
|
||||
|
||||
@ -45,7 +45,7 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
|
||||
startDate: moment()
|
||||
.subtract(6, "days")
|
||||
.startOf("day"),
|
||||
endDate: this.get("today")
|
||||
endDate: this.today
|
||||
};
|
||||
},
|
||||
|
||||
@ -55,7 +55,7 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
|
||||
startDate: moment()
|
||||
.subtract(1, "month")
|
||||
.startOf("day"),
|
||||
endDate: this.get("today")
|
||||
endDate: this.today
|
||||
};
|
||||
},
|
||||
|
||||
@ -78,28 +78,28 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
|
||||
storageReport: staticReport("storage_report"),
|
||||
|
||||
fetchDashboard() {
|
||||
if (this.get("isLoading")) return;
|
||||
if (this.isLoading) return;
|
||||
|
||||
if (
|
||||
!this.get("dashboardFetchedAt") ||
|
||||
!this.dashboardFetchedAt ||
|
||||
moment()
|
||||
.subtract(30, "minutes")
|
||||
.toDate() > this.get("dashboardFetchedAt")
|
||||
.toDate() > this.dashboardFetchedAt
|
||||
) {
|
||||
this.set("isLoading", true);
|
||||
|
||||
AdminDashboardNext.fetchGeneral()
|
||||
.then(adminDashboardNextModel => {
|
||||
AdminDashboard.fetchGeneral()
|
||||
.then(adminDashboardModel => {
|
||||
this.setProperties({
|
||||
dashboardFetchedAt: new Date(),
|
||||
model: adminDashboardNextModel,
|
||||
reports: Ember.makeArray(adminDashboardNextModel.reports).map(x =>
|
||||
model: adminDashboardModel,
|
||||
reports: Ember.makeArray(adminDashboardModel.reports).map(x =>
|
||||
Report.create(x)
|
||||
)
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
this.get("exceptionController").set("thrown", e.jqXHR);
|
||||
this.exceptionController.set("thrown", e.jqXHR);
|
||||
this.replaceRoute("exception");
|
||||
})
|
||||
.finally(() => this.set("isLoading", false));
|
||||
@ -111,13 +111,6 @@ export default Ember.Controller.extend(PeriodComputationMixin, {
|
||||
return { startDate, endDate };
|
||||
},
|
||||
|
||||
@computed("model.attributes.updated_at")
|
||||
updatedTimestamp(updatedAt) {
|
||||
return moment(updatedAt)
|
||||
.tz(moment.tz.guess())
|
||||
.format("LLL");
|
||||
},
|
||||
|
||||
_reportsForPeriodURL(period) {
|
||||
return Discourse.getURL(`/admin?period=${period}`);
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import AdminDashboardNext from "admin/models/admin-dashboard-next";
|
||||
import VersionCheck from "admin/models/version-check";
|
||||
|
||||
const PROBLEMS_CHECK_MINUTES = 1;
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
isLoading: false,
|
||||
dashboardFetchedAt: null,
|
||||
exceptionController: Ember.inject.controller("exception"),
|
||||
showVersionChecks: setting("version_checks"),
|
||||
|
||||
@computed("problems.length")
|
||||
foundProblems(problemsLength) {
|
||||
return this.currentUser.get("admin") && (problemsLength || 0) > 0;
|
||||
},
|
||||
|
||||
fetchProblems() {
|
||||
if (this.get("isLoadingProblems")) return;
|
||||
|
||||
if (
|
||||
!this.get("problemsFetchedAt") ||
|
||||
moment()
|
||||
.subtract(PROBLEMS_CHECK_MINUTES, "minutes")
|
||||
.toDate() > this.get("problemsFetchedAt")
|
||||
) {
|
||||
this._loadProblems();
|
||||
}
|
||||
},
|
||||
|
||||
fetchDashboard() {
|
||||
const versionChecks = this.siteSettings.version_checks;
|
||||
|
||||
if (this.get("isLoading") || !versionChecks) return;
|
||||
|
||||
if (
|
||||
!this.get("dashboardFetchedAt") ||
|
||||
moment()
|
||||
.subtract(30, "minutes")
|
||||
.toDate() > this.get("dashboardFetchedAt")
|
||||
) {
|
||||
this.set("isLoading", true);
|
||||
|
||||
AdminDashboardNext.fetch()
|
||||
.then(model => {
|
||||
let properties = {
|
||||
dashboardFetchedAt: new Date()
|
||||
};
|
||||
|
||||
if (versionChecks) {
|
||||
properties.versionCheck = VersionCheck.create(model.version_check);
|
||||
}
|
||||
|
||||
this.setProperties(properties);
|
||||
})
|
||||
.catch(e => {
|
||||
this.get("exceptionController").set("thrown", e.jqXHR);
|
||||
this.replaceRoute("exception");
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("isLoading", false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_loadProblems() {
|
||||
this.setProperties({
|
||||
loadingProblems: true,
|
||||
problemsFetchedAt: new Date()
|
||||
});
|
||||
|
||||
AdminDashboardNext.fetchProblems()
|
||||
.then(model => this.set("problems", model.problems))
|
||||
.finally(() => this.set("loadingProblems", false));
|
||||
},
|
||||
|
||||
@computed("problemsFetchedAt")
|
||||
problemsTimestamp(problemsFetchedAt) {
|
||||
return moment(problemsFetchedAt)
|
||||
.locale("en")
|
||||
.format("LLL");
|
||||
},
|
||||
|
||||
actions: {
|
||||
refreshProblems() {
|
||||
this._loadProblems();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,78 +1,90 @@
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import Report from "admin/models/report";
|
||||
import AdminUser from "admin/models/admin-user";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import VersionCheck from "admin/models/version-check";
|
||||
|
||||
const ATTRIBUTES = [
|
||||
"admins",
|
||||
"moderators",
|
||||
"silenced",
|
||||
"suspended",
|
||||
"top_traffic_sources",
|
||||
"top_referred_topics",
|
||||
"updated_at"
|
||||
];
|
||||
const PROBLEMS_CHECK_MINUTES = 1;
|
||||
|
||||
const REPORTS = [
|
||||
"global_reports",
|
||||
"page_view_reports",
|
||||
"private_message_reports",
|
||||
"http_reports",
|
||||
"user_reports",
|
||||
"mobile_reports"
|
||||
];
|
||||
|
||||
// This controller supports the default interface when you enter the admin section.
|
||||
export default Ember.Controller.extend({
|
||||
loading: null,
|
||||
versionCheck: null,
|
||||
isLoading: false,
|
||||
dashboardFetchedAt: null,
|
||||
exceptionController: Ember.inject.controller("exception"),
|
||||
showVersionChecks: setting("version_checks"),
|
||||
|
||||
@computed("problems.length")
|
||||
foundProblems(problemsLength) {
|
||||
return this.currentUser.get("admin") && (problemsLength || 0) > 0;
|
||||
},
|
||||
|
||||
fetchProblems() {
|
||||
if (this.isLoadingProblems) return;
|
||||
|
||||
if (
|
||||
!this.problemsFetchedAt ||
|
||||
moment()
|
||||
.subtract(PROBLEMS_CHECK_MINUTES, "minutes")
|
||||
.toDate() > this.problemsFetchedAt
|
||||
) {
|
||||
this._loadProblems();
|
||||
}
|
||||
},
|
||||
|
||||
fetchDashboard() {
|
||||
const versionChecks = this.siteSettings.version_checks;
|
||||
|
||||
if (this.isLoading || !versionChecks) return;
|
||||
|
||||
if (
|
||||
!this.get("dashboardFetchedAt") ||
|
||||
!this.dashboardFetchedAt ||
|
||||
moment()
|
||||
.subtract(30, "minutes")
|
||||
.toDate() > this.get("dashboardFetchedAt")
|
||||
.toDate() > this.dashboardFetchedAt
|
||||
) {
|
||||
this.set("loading", true);
|
||||
AdminDashboard.find()
|
||||
.then(d => {
|
||||
this.set("dashboardFetchedAt", new Date());
|
||||
this.set("isLoading", true);
|
||||
|
||||
REPORTS.forEach(name =>
|
||||
this.set(name, d[name].map(r => Report.create(r)))
|
||||
);
|
||||
AdminDashboard.fetch()
|
||||
.then(model => {
|
||||
let properties = {
|
||||
dashboardFetchedAt: new Date()
|
||||
};
|
||||
|
||||
const topReferrers = d.top_referrers;
|
||||
if (topReferrers && topReferrers.data) {
|
||||
d.top_referrers.data = topReferrers.data.map(user =>
|
||||
AdminUser.create(user)
|
||||
);
|
||||
this.set("top_referrers", topReferrers);
|
||||
if (versionChecks) {
|
||||
properties.versionCheck = VersionCheck.create(model.version_check);
|
||||
}
|
||||
|
||||
ATTRIBUTES.forEach(a => this.set(a, d[a]));
|
||||
this.setProperties(properties);
|
||||
})
|
||||
.catch(e => {
|
||||
this.get("exceptionController").set("thrown", e.jqXHR);
|
||||
this.exceptionController.set("thrown", e.jqXHR);
|
||||
this.replaceRoute("exception");
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
this.set("isLoading", false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@computed("updated_at")
|
||||
updatedTimestamp(updatedAt) {
|
||||
return moment(updatedAt).format("LLL");
|
||||
_loadProblems() {
|
||||
this.setProperties({
|
||||
loadingProblems: true,
|
||||
problemsFetchedAt: new Date()
|
||||
});
|
||||
|
||||
AdminDashboard.fetchProblems()
|
||||
.then(model => this.set("problems", model.problems))
|
||||
.finally(() => this.set("loadingProblems", false));
|
||||
},
|
||||
|
||||
@computed("problemsFetchedAt")
|
||||
problemsTimestamp(problemsFetchedAt) {
|
||||
return moment(problemsFetchedAt)
|
||||
.locale("en")
|
||||
.format("LLL");
|
||||
},
|
||||
|
||||
actions: {
|
||||
showTrafficReport() {
|
||||
this.set("showTrafficReport", true);
|
||||
refreshProblems() {
|
||||
this._loadProblems();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
ajax("/admin/email/advanced-test", {
|
||||
type: "POST",
|
||||
data: { email: this.get("email") }
|
||||
data: { email: this.email }
|
||||
})
|
||||
.then(data => {
|
||||
this.setProperties({
|
||||
|
@ -1,9 +1,8 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import debounce from "discourse/lib/debounce";
|
||||
import EmailLog from "admin/models/email-log";
|
||||
|
||||
export default AdminEmailLogsController.extend({
|
||||
filterEmailLogs: debounce(function() {
|
||||
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
||||
}, 250).observes("filter.{user,address,type}")
|
||||
this.loadLogs();
|
||||
}, 250).observes("filter.{status,user,address,type}")
|
||||
});
|
||||
|
@ -1,25 +0,0 @@
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
loading: false,
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (this.get("loading") || this.get("model.allLoaded")) {
|
||||
return;
|
||||
}
|
||||
this.set("loading", true);
|
||||
|
||||
IncomingEmail.findAll(this.get("filter"), this.get("model.length"))
|
||||
.then(incoming => {
|
||||
if (incoming.length < 50) {
|
||||
this.get("model").set("allLoaded", true);
|
||||
}
|
||||
this.get("model").addObjects(incoming);
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -30,10 +30,10 @@ export default Ember.Controller.extend({
|
||||
|
||||
ajax("/admin/email/test", {
|
||||
type: "POST",
|
||||
data: { email_address: this.get("testEmailAddress") }
|
||||
data: { email_address: this.testEmailAddress }
|
||||
})
|
||||
.then(response =>
|
||||
this.set("sentTestEmailMessage", response.send_test_email_message)
|
||||
this.set("sentTestEmailMessage", response.sent_test_email_message)
|
||||
)
|
||||
.catch(e => {
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
|
@ -3,23 +3,34 @@ import EmailLog from "admin/models/email-log";
|
||||
export default Ember.Controller.extend({
|
||||
loading: false,
|
||||
|
||||
loadLogs(sourceModel, loadMore) {
|
||||
if ((loadMore && this.loading) || this.get("model.allLoaded")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("loading", true);
|
||||
|
||||
sourceModel = sourceModel || EmailLog;
|
||||
|
||||
return sourceModel
|
||||
.findAll(this.filter, loadMore ? this.get("model.length") : null)
|
||||
.then(logs => {
|
||||
if (this.model && loadMore && logs.length < 50) {
|
||||
this.model.set("allLoaded", true);
|
||||
}
|
||||
|
||||
if (this.model && loadMore) {
|
||||
this.model.addObjects(logs);
|
||||
} else {
|
||||
this.set("model", logs);
|
||||
}
|
||||
})
|
||||
.finally(() => this.set("loading", false));
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
if (this.get("loading") || this.get("model.allLoaded")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("loading", true);
|
||||
return EmailLog.findAll(this.get("filter"), this.get("model.length"))
|
||||
.then(logs => {
|
||||
if (logs.length < 50) {
|
||||
this.get("model").set("allLoaded", true);
|
||||
}
|
||||
this.get("model").addObjects(logs);
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
this.loadLogs(EmailLog, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -12,18 +12,18 @@ export default Ember.Controller.extend({
|
||||
|
||||
actions: {
|
||||
refresh() {
|
||||
const model = this.get("model");
|
||||
const model = this.model;
|
||||
|
||||
this.set("loading", true);
|
||||
this.set("sentEmail", false);
|
||||
|
||||
let username = this.get("username");
|
||||
let username = this.username;
|
||||
if (!username) {
|
||||
username = this.currentUser.get("username");
|
||||
this.set("username", username);
|
||||
}
|
||||
|
||||
EmailPreview.findDigest(username, this.get("lastSeen")).then(email => {
|
||||
EmailPreview.findDigest(username, this.lastSeen).then(email => {
|
||||
model.setProperties(
|
||||
email.getProperties("html_content", "text_content")
|
||||
);
|
||||
@ -39,11 +39,7 @@ export default Ember.Controller.extend({
|
||||
this.set("sendingEmail", true);
|
||||
this.set("sentEmail", false);
|
||||
|
||||
EmailPreview.sendDigest(
|
||||
this.get("username"),
|
||||
this.get("lastSeen"),
|
||||
this.get("email")
|
||||
)
|
||||
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
|
||||
.then(result => {
|
||||
if (result.errors) {
|
||||
bootbox.alert(result.errors);
|
||||
|
@ -1,11 +1,15 @@
|
||||
import AdminEmailIncomingsController from "admin/controllers/admin-email-incomings";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import debounce from "discourse/lib/debounce";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
|
||||
export default AdminEmailIncomingsController.extend({
|
||||
export default AdminEmailLogsController.extend({
|
||||
filterIncomingEmails: debounce(function() {
|
||||
IncomingEmail.findAll(this.get("filter")).then(incomings =>
|
||||
this.set("model", incomings)
|
||||
);
|
||||
}, 250).observes("filter.{from,to,subject}")
|
||||
this.loadLogs(IncomingEmail);
|
||||
}, 250).observes("filter.{status,from,to,subject}"),
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,11 +1,15 @@
|
||||
import AdminEmailIncomingsController from "admin/controllers/admin-email-incomings";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import debounce from "discourse/lib/debounce";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
|
||||
export default AdminEmailIncomingsController.extend({
|
||||
export default AdminEmailLogsController.extend({
|
||||
filterIncomingEmails: debounce(function() {
|
||||
IncomingEmail.findAll(this.get("filter")).then(incomings =>
|
||||
this.set("model", incomings)
|
||||
);
|
||||
}, 250).observes("filter.{from,to,subject,error}")
|
||||
this.loadLogs(IncomingEmail);
|
||||
}, 250).observes("filter.{status,from,to,subject,error}"),
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,9 +1,8 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import debounce from "discourse/lib/debounce";
|
||||
import EmailLog from "admin/models/email-log";
|
||||
|
||||
export default AdminEmailLogsController.extend({
|
||||
filterEmailLogs: debounce(function() {
|
||||
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
||||
}, 250).observes("filter.{user,address,type,reply_key}")
|
||||
this.loadLogs();
|
||||
}, 250).observes("filter.{status,user,address,type,reply_key}")
|
||||
});
|
||||
|
@ -1,9 +1,8 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import debounce from "discourse/lib/debounce";
|
||||
import EmailLog from "admin/models/email-log";
|
||||
|
||||
export default AdminEmailLogsController.extend({
|
||||
filterEmailLogs: debounce(function() {
|
||||
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
||||
}, 250).observes("filter.{user,address,type}")
|
||||
this.loadLogs();
|
||||
}, 250).observes("filter.{status,user,address,type}")
|
||||
});
|
||||
|