Merge master
@ -8,10 +8,9 @@ lib/javascripts/locale/
|
||||
lib/javascripts/messageformat.js
|
||||
lib/highlight_js/
|
||||
plugins/**/lib/javascripts/locale
|
||||
public/javascripts/
|
||||
public/
|
||||
vendor/
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/fixtures
|
||||
test/javascripts/helpers/assertions.js
|
||||
app/assets/javascripts/discourse/tests/test_helper.js
|
||||
app/assets/javascripts/discourse/tests/fixtures
|
||||
node_modules/
|
||||
dist/
|
||||
|
15
.eslintrc
@ -1,7 +1,18 @@
|
||||
{
|
||||
"extends": "eslint-config-discourse",
|
||||
"plugins": ["discourse-ember"],
|
||||
"rules": {
|
||||
"discourse-ember/global-ember": 2
|
||||
"discourse-ember/global-ember": 2,
|
||||
"no-duplicate-imports": 2
|
||||
},
|
||||
"globals": {
|
||||
"moduleFor": "off",
|
||||
"moduleForComponent": "off",
|
||||
"testStart": "off",
|
||||
"testDone": "off",
|
||||
"sinon": "off",
|
||||
"currentURL": "off",
|
||||
"invisible": "off",
|
||||
"visible": "off",
|
||||
"count": "off",
|
||||
}
|
||||
}
|
||||
|
@ -28,3 +28,27 @@ c4644c61d97c823b7dd940ffaf0967a104f4b58c
|
||||
|
||||
# DEV: Fix indentation for routes.rb
|
||||
985900818ff985b04def6aa4c5d99c1aa6dbd45c
|
||||
|
||||
# Add rubocop to our build.
|
||||
5012d46cbd3bcf79b7351f7d2d41003496a796c5
|
||||
|
||||
# Make rubocop happy again.
|
||||
ad5082d969ab1f60b5c5b1e89a616117906289f8
|
||||
|
||||
# DEV: apply new coding standards (#10592)
|
||||
52672b9eabccb1184d85dc7f08062d5a7c18cb73
|
||||
|
||||
# DEV: apply coding standards to plugins (#10594)
|
||||
bf88410126f73aab47b7e694e3c5b46453cec1b6
|
||||
|
||||
# REFACTOR: Support bundling our `admin` section as an ember addon
|
||||
ce3fe2f4c4ddf166949ee3cec3d9ecbf9108ab52
|
||||
|
||||
# REFACTOR: Move qunit tests to a different directory structure
|
||||
bc97c79a35d8acd283d4d8b79aa079bce9d127c6
|
||||
|
||||
# REFACTOR: Move javascript tests inside discourse app
|
||||
23f24bfb510edb25b18b6a0d5485270c88df9b24
|
||||
|
||||
# DEV: Tidy up imports. (#11364)
|
||||
1c2358ba162eb9f9ba9095c9afe30cf51dd85e04
|
||||
|
38
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: bundler
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "08:00"
|
||||
timezone: Australia/Sydney
|
||||
open-pull-requests-limit: 10
|
||||
versioning-strategy: lockfile-only
|
||||
allow:
|
||||
- dependency-type: direct
|
||||
- dependency-type: indirect
|
||||
ignore:
|
||||
- dependency-name: aws-partitions
|
||||
versions:
|
||||
- "> 1.329.0"
|
||||
- "< 2"
|
||||
- dependency-name: aws-sdk-core
|
||||
versions:
|
||||
- "> 3.99.1"
|
||||
- "< 4"
|
||||
- dependency-name: aws-sdk-kms
|
||||
versions:
|
||||
- "> 1.31.0"
|
||||
- "< 2"
|
||||
- dependency-name: aws-sdk-s3
|
||||
versions:
|
||||
- "> 1.66.0"
|
||||
- "< 2"
|
||||
- dependency-name: aws-sdk-sns
|
||||
versions:
|
||||
- "> 1.25.1"
|
||||
- "< 2"
|
||||
- dependency-name: aws-sigv4
|
||||
versions:
|
||||
- "> 1.2.0"
|
||||
- "< 2"
|
1
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1 @@
|
||||
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in Javascript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
|
62
.github/workflows/ci.yml
vendored
@ -65,7 +65,7 @@ jobs:
|
||||
if: env.BUILD_TYPE != 'LINT'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev gifsicle jpegoptim optipng jhead
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev jpegoptim optipng jhead
|
||||
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh
|
||||
|
||||
- name: Update imagemagick
|
||||
@ -91,9 +91,10 @@ jobs:
|
||||
gem install bundler -v 2.1.4 --no-doc
|
||||
bundle config deployment 'true'
|
||||
bundle config without 'development'
|
||||
bundle config path vendor/bundle
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v2
|
||||
id: bundler-cache
|
||||
with:
|
||||
path: vendor/bundle
|
||||
@ -109,7 +110,7 @@ jobs:
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
@ -136,21 +137,56 @@ jobs:
|
||||
bin/rake parallel:create
|
||||
bin/rake parallel:migrate
|
||||
|
||||
- name: Rubocop
|
||||
if: env.BUILD_TYPE == 'LINT'
|
||||
- name: Rubocop (core and core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: bundle exec rubocop .
|
||||
|
||||
- name: ESLint
|
||||
if: env.BUILD_TYPE == 'LINT'
|
||||
run: |
|
||||
yarn eslint app/assets/javascripts test/javascripts
|
||||
yarn eslint --global I18n --ext .es6 plugins
|
||||
- name: Rubocop (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: bundle exec rubocop plugins
|
||||
|
||||
- name: Prettier
|
||||
if: env.BUILD_TYPE == 'LINT'
|
||||
- name: ESLint (core)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern app/assets/javascripts
|
||||
|
||||
- name: ESLint (core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern plugins/**/{test,assets}/javascripts
|
||||
|
||||
- name: ESLint (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern plugins/**/{test,assets}/javascripts
|
||||
|
||||
- name: Prettier (core and core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: |
|
||||
yarn prettier -v
|
||||
yarn prettier --list-different "app/assets/stylesheets/**/*.scss" "app/assets/javascripts/**/*.js" "app/assets/javascripts/**/*.es6" "test/javascripts/**/*.es6" "plugins/**/*.scss" "plugins/**/*.es6"
|
||||
yarn prettier --list-different \
|
||||
"app/assets/stylesheets/**/*.scss" \
|
||||
"app/assets/javascripts/**/*.{js,es6}" \
|
||||
"plugins/**/assets/stylesheets/**/*.scss" \
|
||||
"plugins/**/assets/javascripts/**/*.{js,es6}"
|
||||
|
||||
- name: Prettier (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: |
|
||||
yarn prettier -v
|
||||
yarn prettier --list-different \
|
||||
"plugins/**/assets/stylesheets/**/*.scss" \
|
||||
"plugins/**/assets/javascripts/**/*.{js,es6}"
|
||||
|
||||
- name: Ember template lint (core and core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: |
|
||||
yarn ember-template-lint \
|
||||
app/assets/javascripts \
|
||||
plugins/**/assets/javascripts
|
||||
|
||||
- name: Ember template lint (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: |
|
||||
yarn ember-template-lint \
|
||||
plugins/**/assets/javascripts
|
||||
|
||||
- name: Core English locale
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
|
11
.gitignore
vendored
@ -53,8 +53,8 @@ bootsnap-compile-cache/
|
||||
!/plugins/discourse-nginx-performance-report
|
||||
!/plugins/discourse-narrative-bot
|
||||
!/plugins/discourse-presence
|
||||
!/plugins/styleguide
|
||||
!/plugins/discourse-local-dates
|
||||
!/plugins/discourse-unsupported-browser
|
||||
/plugins/*/auto_generated/
|
||||
|
||||
/spec/fixtures/plugins/my_plugin/auto_generated
|
||||
@ -88,6 +88,7 @@ config/multisite.yml
|
||||
config/multisite1.yml
|
||||
config/fog_credentials.yml
|
||||
|
||||
/public/fonts
|
||||
/public/uploads
|
||||
/public/backups
|
||||
/public/stylesheet-cache/*
|
||||
@ -136,8 +137,16 @@ node_modules
|
||||
# ignore generated api documentation files
|
||||
openapi/*
|
||||
|
||||
# ignore VSCode config files
|
||||
.vscode
|
||||
|
||||
# ignore direnv
|
||||
.envrc
|
||||
|
||||
# ember-cli generated
|
||||
dist
|
||||
|
||||
# Copyright Deposits
|
||||
copyright
|
||||
|
||||
yarn-error.log
|
||||
|
12
.licensed.yml
Normal file
@ -0,0 +1,12 @@
|
||||
sources:
|
||||
yarn: true
|
||||
bundler: true
|
||||
allowed:
|
||||
- mit
|
||||
- apache-2.0
|
||||
- bsd-2-clause
|
||||
- bsd-3-clause
|
||||
- cc0-1.0
|
||||
- isc
|
||||
- other
|
||||
- none
|
@ -1,6 +1,25 @@
|
||||
app/assets/stylesheets/vendor/
|
||||
plugins/**/assets/stylesheets/vendor/
|
||||
plugins/**/assets/javascripts/vendor/
|
||||
package.json
|
||||
config/locales/**/*.yml
|
||||
!config/locales/**/*.en*.yml
|
||||
script/import_scripts/**/*.yml
|
||||
|
||||
app/assets/javascripts/env.js
|
||||
app/assets/javascripts/main_include_admin.js
|
||||
app/assets/javascripts/vendor.js
|
||||
app/assets/javascripts/locales/i18n.js
|
||||
app/assets/javascripts/ember-addons/
|
||||
app/assets/javascripts/discourse/lib/autosize.js
|
||||
lib/javascripts/locale/
|
||||
lib/javascripts/messageformat.js
|
||||
lib/highlight_js/
|
||||
plugins/**/lib/javascripts/locale
|
||||
public/
|
||||
vendor/
|
||||
app/assets/javascripts/discourse/tests/test_helper.js
|
||||
app/assets/javascripts/discourse/tests/fixtures
|
||||
node_modules/
|
||||
dist/
|
||||
**/*.rb
|
||||
|
1
.prettierrc
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -50,6 +50,6 @@ module.exports = {
|
||||
"simple-unless": true,
|
||||
"style-concatenation": true,
|
||||
"table-groups": true,
|
||||
"link-href-attributes": false
|
||||
}
|
||||
"link-href-attributes": false,
|
||||
},
|
||||
};
|
||||
|
99
.tx/config
@ -1,99 +0,0 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = el_GR: el, es_ES: es, fr_FR: fr, hu_HU: hu, ko_KR: ko, pt_PT: pt, sk_SK: sk, vi_VN: vi
|
||||
|
||||
[discourse-org.core-client-yml]
|
||||
file_filter = config/locales/client.<lang>.yml
|
||||
source_file = config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.core-server-yml]
|
||||
file_filter = config/locales/server.<lang>.yml
|
||||
source_file = config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.pollclientenyml]
|
||||
file_filter = plugins/poll/config/locales/client.<lang>.yml
|
||||
source_file = plugins/poll/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.pollserverenyml]
|
||||
file_filter = plugins/poll/config/locales/server.<lang>.yml
|
||||
source_file = plugins/poll/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.narrativeclientenyml]
|
||||
file_filter = plugins/discourse-narrative-bot/config/locales/client.<lang>.yml
|
||||
source_file = plugins/discourse-narrative-bot/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.narrativeserverenyml]
|
||||
file_filter = plugins/discourse-narrative-bot/config/locales/server.<lang>.yml
|
||||
source_file = plugins/discourse-narrative-bot/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.discourse-presenceclientenyml]
|
||||
file_filter = plugins/discourse-presence/config/locales/client.<lang>.yml
|
||||
source_file = plugins/discourse-presence/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.discourse-presenceserverenyml]
|
||||
file_filter = plugins/discourse-presence/config/locales/server.<lang>.yml
|
||||
source_file = plugins/discourse-presence/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.coreplugindetailsclientyml]
|
||||
file_filter = plugins/discourse-details/config/locales/client.<lang>.yml
|
||||
source_file = plugins/discourse-details/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.coreplugindetailsserveryml]
|
||||
file_filter = plugins/discourse-details/config/locales/server.<lang>.yml
|
||||
source_file = plugins/discourse-details/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.core-plugin-local-dates-client-yml]
|
||||
file_filter = plugins/discourse-local-dates/config/locales/client.<lang>.yml
|
||||
source_file = plugins/discourse-local-dates/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.core-plugin-local-dates-server-yml]
|
||||
file_filter = plugins/discourse-local-dates/config/locales/server.<lang>.yml
|
||||
source_file = plugins/discourse-local-dates/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.403html]
|
||||
file_filter = public/403.<lang>.html
|
||||
source_file = public/403.html
|
||||
source_lang = en
|
||||
type = HTML
|
||||
|
||||
[discourse-org.422html]
|
||||
file_filter = public/422.<lang>.html
|
||||
source_file = public/422.html
|
||||
source_lang = en
|
||||
type = HTML
|
||||
|
||||
[discourse-org.500html]
|
||||
file_filter = public/500.<lang>.html
|
||||
source_file = public/500.html
|
||||
source_lang = en
|
||||
type = HTML
|
||||
|
||||
[discourse-org.503html]
|
||||
file_filter = public/503.<lang>.html
|
||||
source_file = public/503.html
|
||||
source_lang = en
|
||||
type = HTML
|
@ -17,7 +17,7 @@ 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).")
|
||||
fail("Please submit your non-English translation updates via [Crowdin](https://translate.discourse.org/). You can read more on how to contribute translations [here](https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882).")
|
||||
end
|
||||
|
||||
files = (git.added_files + git.modified_files)
|
||||
|
39
Gemfile
@ -18,13 +18,13 @@ else
|
||||
# this allows us to include the bits of rails we use without pieces we do not.
|
||||
#
|
||||
# To issue a rails update bump the version number here
|
||||
gem 'actionmailer', '6.0.3.1'
|
||||
gem 'actionpack', '6.0.3.1'
|
||||
gem 'actionview', '6.0.3.1'
|
||||
gem 'activemodel', '6.0.3.1'
|
||||
gem 'activerecord', '6.0.3.1'
|
||||
gem 'activesupport', '6.0.3.1'
|
||||
gem 'railties', '6.0.3.1'
|
||||
gem 'actionmailer', '6.0.3.3'
|
||||
gem 'actionpack', '6.0.3.3'
|
||||
gem 'actionview', '6.0.3.3'
|
||||
gem 'activemodel', '6.0.3.3'
|
||||
gem 'activerecord', '6.0.3.3'
|
||||
gem 'activesupport', '6.0.3.3'
|
||||
gem 'railties', '6.0.3.3'
|
||||
gem 'sprockets-rails'
|
||||
end
|
||||
|
||||
@ -66,9 +66,10 @@ gem 'http_accept_language', require: false
|
||||
|
||||
# Ember related gems need to be pinned cause they control client side
|
||||
# behavior, we will push these versions up when upgrading ember
|
||||
gem 'ember-rails', '0.18.5'
|
||||
gem 'discourse-ember-rails', '0.18.6', require: 'ember-rails'
|
||||
gem 'discourse-ember-source', '~> 3.12.2'
|
||||
gem 'ember-handlebars-template', '0.8.0'
|
||||
gem 'discourse-fonts'
|
||||
|
||||
gem 'barber'
|
||||
|
||||
@ -76,10 +77,9 @@ gem 'message_bus'
|
||||
|
||||
gem 'rails_multisite'
|
||||
|
||||
gem 'fast_xs', platform: :mri
|
||||
gem 'fast_xs', platform: :ruby
|
||||
|
||||
# may move to xorcist post: https://github.com/fny/xorcist/issues/4
|
||||
gem 'fast_xor', platform: :mri
|
||||
gem 'xorcist'
|
||||
|
||||
gem 'fastimage'
|
||||
|
||||
@ -101,7 +101,6 @@ gem 'css_parser', require: false
|
||||
gem 'omniauth'
|
||||
gem 'omniauth-facebook'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-instagram'
|
||||
gem 'omniauth-github'
|
||||
|
||||
gem 'omniauth-oauth2', require: false
|
||||
@ -125,10 +124,9 @@ gem 'mini_scheduler'
|
||||
gem 'execjs', require: false
|
||||
gem 'mini_racer'
|
||||
|
||||
# TODO: determine why highline is being held back and upgrade to latest
|
||||
gem 'highline', '~> 1.7.0', require: false
|
||||
gem 'highline', require: false
|
||||
|
||||
gem 'rack', '2.2.2'
|
||||
gem 'rack'
|
||||
|
||||
gem 'rack-protection' # security
|
||||
gem 'cbor', require: false
|
||||
@ -160,10 +158,6 @@ group :test, :development do
|
||||
|
||||
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
|
||||
|
||||
# TODO determine if we can update this to 0.10, API changes happened
|
||||
# we would like to upgrade it if possible
|
||||
gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
|
||||
|
||||
gem 'rspec-rails'
|
||||
|
||||
gem 'shoulda-matchers', require: false
|
||||
@ -187,7 +181,7 @@ end
|
||||
# this is an optional gem, it provides a high performance replacement
|
||||
# to String#blank? a method that is called quite frequently in current
|
||||
# ActiveRecord, this may change in the future
|
||||
gem 'fast_blank', platform: :mri
|
||||
gem 'fast_blank', platform: :ruby
|
||||
|
||||
# this provides a very efficient lru cache
|
||||
gem 'lru_redux'
|
||||
@ -201,7 +195,7 @@ gem 'htmlentities', require: false
|
||||
gem 'flamegraph', require: false
|
||||
gem 'rack-mini-profiler', require: ['enable_rails_patches']
|
||||
|
||||
gem 'unicorn', require: false, platform: :mri
|
||||
gem 'unicorn', require: false, platform: :ruby
|
||||
gem 'puma', require: false
|
||||
gem 'rbtrace', require: false, platform: :mri
|
||||
gem 'gc_tracer', require: false, platform: :mri
|
||||
@ -225,6 +219,7 @@ gem 'sassc', '2.0.1', require: false
|
||||
gem "sassc-rails"
|
||||
|
||||
gem 'rotp', require: false
|
||||
|
||||
gem 'rqrcode'
|
||||
|
||||
gem 'rubyzip', require: false
|
||||
@ -232,7 +227,7 @@ gem 'rubyzip', require: false
|
||||
gem 'sshkey', require: false
|
||||
|
||||
gem 'rchardet', require: false
|
||||
gem 'lz4-ruby', require: false, platform: :mri
|
||||
gem 'lz4-ruby', require: false, platform: :ruby
|
||||
|
||||
if ENV["IMPORT"] == "1"
|
||||
gem 'mysql2'
|
||||
|
295
Gemfile.lock
@ -1,38 +1,38 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
activejob (= 6.0.3.1)
|
||||
actionmailer (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actionpack (6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
actionview (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
actionview_precompiler (0.2.2)
|
||||
actionview_precompiler (0.2.3)
|
||||
actionview (>= 6.0.a)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activejob (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activerecord (6.0.3.1)
|
||||
activemodel (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activesupport (6.0.3.1)
|
||||
activemodel (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activerecord (6.0.3.3)
|
||||
activemodel (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activesupport (6.0.3.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
@ -45,34 +45,34 @@ GEM
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.329.0)
|
||||
aws-sdk-core (3.99.1)
|
||||
aws-partitions (1.390.0)
|
||||
aws-sdk-core (3.109.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.31.0)
|
||||
aws-sdk-core (~> 3, >= 3.71.0)
|
||||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.66.0)
|
||||
aws-sdk-core (~> 3, >= 3.96.1)
|
||||
aws-sdk-s3 (1.83.2)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-sns (1.25.1)
|
||||
aws-sdk-core (~> 3, >= 3.99.0)
|
||||
aws-sdk-sns (1.35.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.0)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
barber (0.12.2)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
execjs (>= 1.2, < 3)
|
||||
better_errors (2.7.1)
|
||||
better_errors (2.9.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.4.6)
|
||||
bootsnap (1.5.1)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.0)
|
||||
@ -81,24 +81,31 @@ GEM
|
||||
byebug (11.1.3)
|
||||
cbor (0.5.9.6)
|
||||
certified (1.0.0)
|
||||
chunky_png (1.3.11)
|
||||
chunky_png (1.3.14)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.6)
|
||||
concurrent-ruby (1.1.7)
|
||||
connection_pool (2.2.3)
|
||||
cose (1.0.0)
|
||||
cose (1.2.0)
|
||||
cbor (~> 0.5.9)
|
||||
openssl-signature_algorithm (~> 0.4.0)
|
||||
openssl-signature_algorithm (~> 1.0)
|
||||
cppjieba_rb (0.3.3)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
crack (0.4.4)
|
||||
crass (1.0.6)
|
||||
css_parser (1.7.1)
|
||||
addressable
|
||||
debug_inspector (0.0.3)
|
||||
diff-lcs (1.4.1)
|
||||
diffy (3.3.0)
|
||||
discourse-ember-source (3.12.2.0)
|
||||
diff-lcs (1.4.4)
|
||||
diffy (3.4.0)
|
||||
discourse-ember-rails (0.18.6)
|
||||
active_model_serializers
|
||||
ember-data-source (>= 1.0.0.beta.5)
|
||||
ember-handlebars-template (>= 0.1.1, < 1.0)
|
||||
ember-source (>= 1.1.0)
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
discourse-ember-source (3.12.2.2)
|
||||
discourse-fonts (0.0.5)
|
||||
discourse_image_optim (0.26.2)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
fspath (~> 3.0)
|
||||
@ -112,28 +119,19 @@ GEM
|
||||
ember-handlebars-template (0.8.0)
|
||||
barber (>= 0.11.0)
|
||||
sprockets (>= 3.3, < 4.1)
|
||||
ember-rails (0.18.5)
|
||||
active_model_serializers
|
||||
ember-data-source (>= 1.0.0.beta.5)
|
||||
ember-handlebars-template (>= 0.1.1, < 1.0)
|
||||
ember-source (>= 1.1.0)
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
ember-source (2.18.2)
|
||||
erubi (1.9.0)
|
||||
excon (0.75.0)
|
||||
erubi (1.10.0)
|
||||
excon (0.78.0)
|
||||
execjs (2.7.0)
|
||||
exifr (1.3.6)
|
||||
exifr (1.3.9)
|
||||
fabrication (2.21.1)
|
||||
fakeweb (1.3.0)
|
||||
faraday (1.0.1)
|
||||
faraday (1.1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
fast_blank (1.0.0)
|
||||
fast_xor (1.1.3)
|
||||
rake
|
||||
rake-compiler
|
||||
fast_xs (0.8.0)
|
||||
fastimage (2.1.7)
|
||||
fastimage (2.2.0)
|
||||
ffi (1.13.1)
|
||||
flamegraph (0.9.5)
|
||||
fspath (3.1.2)
|
||||
@ -143,11 +141,11 @@ GEM
|
||||
guess_html_encoding (0.0.11)
|
||||
hashdiff (1.0.1)
|
||||
hashie (4.1.0)
|
||||
highline (1.7.10)
|
||||
highline (2.0.3)
|
||||
hkdf (0.3.0)
|
||||
htmlentities (4.3.4)
|
||||
http_accept_language (2.1.1)
|
||||
i18n (1.8.3)
|
||||
i18n (1.8.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_size (1.5.0)
|
||||
in_threads (1.5.4)
|
||||
@ -156,13 +154,13 @@ GEM
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.3.0)
|
||||
json (2.3.1)
|
||||
json-schema (2.8.1)
|
||||
addressable (>= 2.4)
|
||||
jwt (2.2.1)
|
||||
jwt (2.2.2)
|
||||
kgio (2.11.3)
|
||||
libv8 (8.4.255.0)
|
||||
listen (3.2.1)
|
||||
listen (3.3.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
lograge (0.11.2)
|
||||
@ -173,8 +171,8 @@ GEM
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.9.0)
|
||||
loofah (2.6.0)
|
||||
logster (2.9.4)
|
||||
loofah (2.8.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
@ -183,28 +181,28 @@ GEM
|
||||
mini_mime (>= 0.1.1)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (0.9.14)
|
||||
message_bus (3.3.1)
|
||||
message_bus (3.3.4)
|
||||
rack (>= 1.1.3)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
mini_racer (0.3.1)
|
||||
libv8 (~> 8.4.255)
|
||||
mini_scheduler (0.12.2)
|
||||
mini_scheduler (0.12.3)
|
||||
sidekiq
|
||||
mini_sql (0.2.5)
|
||||
mini_sql (0.3)
|
||||
mini_suffix (0.3.0)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.14.1)
|
||||
minitest (5.14.2)
|
||||
mocha (1.11.2)
|
||||
mock_redis (0.24.0)
|
||||
mock_redis (0.26.0)
|
||||
msgpack (1.3.3)
|
||||
multi_json (1.14.1)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
mustache (1.1.1)
|
||||
nio4r (2.5.2)
|
||||
nokogiri (1.10.9)
|
||||
nio4r (2.5.4)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nokogumbo (2.0.2)
|
||||
nokogiri (~> 1.8, >= 1.8.4)
|
||||
@ -215,11 +213,11 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.10.6)
|
||||
oj (3.10.16)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-facebook (6.0.0)
|
||||
omniauth-facebook (8.0.0)
|
||||
omniauth-oauth2 (~> 1.2)
|
||||
omniauth-github (1.4.0)
|
||||
omniauth (~> 1.5)
|
||||
@ -228,31 +226,28 @@ GEM
|
||||
jwt (>= 2.0)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (>= 1.6)
|
||||
omniauth-instagram (1.3.0)
|
||||
omniauth (~> 1)
|
||||
omniauth-oauth2 (~> 1)
|
||||
omniauth-oauth (1.1.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.6.0)
|
||||
oauth2 (~> 1.1)
|
||||
omniauth-oauth2 (1.7.0)
|
||||
oauth2 (~> 1.4)
|
||||
omniauth (~> 1.9)
|
||||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
onebox (1.9.29)
|
||||
onebox (2.1.7)
|
||||
addressable (~> 2.7.0)
|
||||
htmlentities (~> 4.3)
|
||||
multi_json (~> 1.11)
|
||||
mustache
|
||||
nokogiri (~> 1.7)
|
||||
sanitize
|
||||
openssl-signature_algorithm (0.4.0)
|
||||
openssl-signature_algorithm (1.0.0)
|
||||
optimist (3.0.1)
|
||||
parallel (1.19.2)
|
||||
parallel_tests (3.0.0)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.4.0)
|
||||
parallel
|
||||
parser (2.7.1.4)
|
||||
parser (2.7.2.0)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.2.3)
|
||||
progress (3.5.2)
|
||||
@ -264,14 +259,14 @@ GEM
|
||||
pry (~> 0.13.0)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.5)
|
||||
puma (4.3.5)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.0.4)
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
rack (2.2.2)
|
||||
rack-mini-profiler (2.0.2)
|
||||
rack (2.2.3)
|
||||
rack-mini-profiler (2.2.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (2.0.8.1)
|
||||
rack-protection (2.1.0)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
@ -280,60 +275,58 @@ GEM
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
loofah (~> 2.3)
|
||||
rails_failover (0.5.5)
|
||||
rails_failover (0.6.2)
|
||||
activerecord (~> 6.0)
|
||||
concurrent-ruby
|
||||
railties (~> 6.0)
|
||||
rails_multisite (2.3.0)
|
||||
rails_multisite (2.5.0)
|
||||
activerecord (> 5.0, < 7)
|
||||
railties (> 5.0, < 7)
|
||||
railties (6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
railties (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.1)
|
||||
rake (13.0.1)
|
||||
rake-compiler (1.1.0)
|
||||
rake
|
||||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rbtrace (0.4.13)
|
||||
rbtrace (0.4.14)
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
redis (4.2.1)
|
||||
redis-namespace (1.7.0)
|
||||
redis (4.2.5)
|
||||
redis-namespace (1.8.0)
|
||||
redis (>= 3.0.4)
|
||||
regexp_parser (1.7.1)
|
||||
regexp_parser (2.0.0)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.4)
|
||||
rinku (2.0.6)
|
||||
rotp (5.1.0)
|
||||
addressable (~> 2.5)
|
||||
rotp (6.2.0)
|
||||
rqrcode (1.1.2)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.2)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.2)
|
||||
rspec-support (~> 3.9.3)
|
||||
rspec-expectations (3.9.2)
|
||||
rspec (3.10.0)
|
||||
rspec-core (~> 3.10.0)
|
||||
rspec-expectations (~> 3.10.0)
|
||||
rspec-mocks (~> 3.10.0)
|
||||
rspec-core (3.10.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-html-matchers (0.9.2)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-html-matchers (0.9.4)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a, < 4)
|
||||
rspec-mocks (3.9.1)
|
||||
rspec-mocks (3.10.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-rails (4.0.1)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
@ -342,35 +335,36 @@ GEM
|
||||
rspec-expectations (~> 3.9)
|
||||
rspec-mocks (~> 3.9)
|
||||
rspec-support (~> 3.9)
|
||||
rspec-support (3.9.3)
|
||||
rspec-support (3.10.0)
|
||||
rswag-specs (2.3.1)
|
||||
activesupport (>= 3.1, < 7.0)
|
||||
json-schema (~> 2.2)
|
||||
railties (>= 3.1, < 7.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (0.86.0)
|
||||
rubocop (1.4.2)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.0.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.7)
|
||||
regexp_parser (>= 1.8)
|
||||
rexml
|
||||
rubocop-ast (>= 0.0.3, < 1.0)
|
||||
rubocop-ast (>= 1.1.1)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (0.0.3)
|
||||
parser (>= 2.7.0.1)
|
||||
rubocop-discourse (2.2.0)
|
||||
rubocop (>= 0.69.0)
|
||||
rubocop-rspec (>= 1.39.0)
|
||||
rubocop-rspec (1.40.0)
|
||||
rubocop (>= 0.68.1)
|
||||
ruby-prof (1.4.1)
|
||||
rubocop-ast (1.2.0)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.0.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-prof (1.4.2)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-readability (0.7.0)
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
ruby2_keywords (0.0.2)
|
||||
rubyzip (2.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sanitize (5.2.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.8.0)
|
||||
@ -387,31 +381,32 @@ GEM
|
||||
seed-fu (2.3.9)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
shoulda-matchers (4.3.0)
|
||||
shoulda-matchers (4.4.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (6.0.7)
|
||||
sidekiq (6.1.2)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
rack-protection (>= 2.0.0)
|
||||
redis (>= 4.1.0)
|
||||
simplecov (0.18.5)
|
||||
redis (>= 4.2.0)
|
||||
simplecov (0.20.0)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov-html (0.12.2)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov_json_formatter (0.1.2)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.1)
|
||||
sprockets-rails (3.2.2)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.15)
|
||||
test-prof (0.11.3)
|
||||
stackprof (0.2.16)
|
||||
test-prof (0.12.2)
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
tzinfo (1.2.7)
|
||||
tzinfo (1.2.8)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
@ -419,32 +414,33 @@ GEM
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
unicorn (5.5.5)
|
||||
unicorn (5.7.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.13.0)
|
||||
webmock (3.8.3)
|
||||
webmock (3.10.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpush (1.0.0)
|
||||
webpush (1.1.0)
|
||||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
xorcist (1.1.2)
|
||||
yaml-lint (0.0.10)
|
||||
zeitwerk (2.3.0)
|
||||
zeitwerk (2.4.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 6.0.3.1)
|
||||
actionpack (= 6.0.3.1)
|
||||
actionview (= 6.0.3.1)
|
||||
actionmailer (= 6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
actionview_precompiler
|
||||
active_model_serializers (~> 0.8.3)
|
||||
activemodel (= 6.0.3.1)
|
||||
activerecord (= 6.0.3.1)
|
||||
activesupport (= 6.0.3.1)
|
||||
activemodel (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
addressable
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
@ -462,22 +458,22 @@ DEPENDENCIES
|
||||
cppjieba_rb
|
||||
css_parser
|
||||
diffy
|
||||
discourse-ember-rails (= 0.18.6)
|
||||
discourse-ember-source (~> 3.12.2)
|
||||
discourse-fonts
|
||||
discourse_image_optim
|
||||
email_reply_trimmer
|
||||
ember-handlebars-template (= 0.8.0)
|
||||
ember-rails (= 0.18.5)
|
||||
excon
|
||||
execjs
|
||||
fabrication
|
||||
fakeweb
|
||||
fast_blank
|
||||
fast_xor
|
||||
fast_xs
|
||||
fastimage
|
||||
flamegraph
|
||||
gc_tracer
|
||||
highline (~> 1.7.0)
|
||||
highline
|
||||
htmlentities
|
||||
http_accept_language
|
||||
json
|
||||
@ -508,7 +504,6 @@ DEPENDENCIES
|
||||
omniauth-facebook
|
||||
omniauth-github
|
||||
omniauth-google-oauth2
|
||||
omniauth-instagram
|
||||
omniauth-oauth2
|
||||
omniauth-twitter
|
||||
onebox
|
||||
@ -518,15 +513,14 @@ DEPENDENCIES
|
||||
pry-rails
|
||||
puma
|
||||
r2
|
||||
rack (= 2.2.2)
|
||||
rack
|
||||
rack-mini-profiler
|
||||
rack-protection
|
||||
rails_failover
|
||||
rails_multisite
|
||||
railties (= 6.0.3.1)
|
||||
railties (= 6.0.3.3)
|
||||
rake
|
||||
rb-fsevent
|
||||
rb-inotify (~> 0.9)
|
||||
rbtrace
|
||||
rchardet
|
||||
redis
|
||||
@ -560,6 +554,7 @@ DEPENDENCIES
|
||||
unicorn
|
||||
webmock
|
||||
webpush
|
||||
xorcist
|
||||
yaml-lint
|
||||
|
||||
BUNDLED WITH
|
||||
|
@ -17,8 +17,9 @@ To learn more about the philosophy and goals of the project, [visit **discourse.
|
||||
|
||||
<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>
|
||||
<a href="https://discuss.atom.io/"><img src="https://user-images.githubusercontent.com/1681963/89088039-6735f080-d364-11ea-93a6-5629ea8738fe.png" width="720px"></a>
|
||||
<a href="https://forums.gearboxsoftware.com/"><img src="https://user-images.githubusercontent.com/1681963/89088042-68ffb400-d364-11ea-93be-161ea04d8b29.png" width="720px"></a>
|
||||
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/1681963/52239118-b304f800-289b-11e9-9904-16450680d9ec.jpg" alt="Mobile" width="414">
|
||||
|
||||
@ -61,6 +62,7 @@ Discourse supports the **latest, stable releases** of all major browsers and pla
|
||||
- [Ember.js](https://github.com/emberjs/ember.js) — Our front end is an Ember.js app that communicates with the Rails API.
|
||||
- [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.
|
||||
- [BrowserStack](https://www.browserstack.com/) — We use BrowserStack to test on real devices and browsers.
|
||||
|
||||
Plus *lots* of Ruby Gems, a complete list of which is at [/master/Gemfile](https://github.com/discourse/discourse/blob/master/Gemfile).
|
||||
|
||||
@ -90,7 +92,6 @@ We take security very seriously at Discourse; all our code is 100% open source a
|
||||
|
||||
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
|
||||
|
||||
Copyright 2014 - 2020 Civilized Discourse Construction Kit, Inc.
|
||||
|
Before ![]() (image error) Size: 2.9 KiB After ![]() (image error) Size: 2.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.5 KiB After ![]() (image error) Size: 1.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.4 KiB After ![]() (image error) Size: 2.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.5 KiB After ![]() (image error) Size: 3.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.7 KiB After ![]() (image error) Size: 3.0 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.4 KiB After ![]() (image error) Size: 1.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 882 B After ![]() (image error) Size: 810 B ![]() ![]() |
Before ![]() (image error) Size: 1.8 KiB After ![]() (image error) Size: 1.6 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.0 KiB After ![]() (image error) Size: 937 B ![]() ![]() |
Before ![]() (image error) Size: 984 B After ![]() (image error) Size: 898 B ![]() ![]() |
Before ![]() (image error) Size: 895 B After ![]() (image error) Size: 822 B ![]() ![]() |
Before ![]() (image error) Size: 4.7 KiB After ![]() (image error) Size: 2.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 24 KiB After ![]() (image error) Size: 22 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.5 KiB After ![]() (image error) Size: 2.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.9 KiB After ![]() (image error) Size: 2.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.1 KiB After ![]() (image error) Size: 2.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.8 KiB After ![]() (image error) Size: 1.6 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.2 KiB After ![]() (image error) Size: 2.0 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.2 KiB After ![]() (image error) Size: 3.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.8 KiB After ![]() (image error) Size: 2.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.4 KiB After ![]() (image error) Size: 947 B ![]() ![]() |
Before ![]() (image error) Size: 4.5 KiB After ![]() (image error) Size: 4.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.1 KiB After ![]() (image error) Size: 2.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.8 KiB After ![]() (image error) Size: 2.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 3.1 KiB After ![]() (image error) Size: 2.7 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.8 KiB After ![]() (image error) Size: 1.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.7 KiB After ![]() (image error) Size: 1.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.6 KiB After ![]() (image error) Size: 1.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.8 KiB After ![]() (image error) Size: 1.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.8 KiB After ![]() (image error) Size: 1.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 613 B After ![]() (image error) Size: 525 B ![]() ![]() |
Before ![]() (image error) Size: 845 B After ![]() (image error) Size: 759 B ![]() ![]() |
@ -1,23 +1,18 @@
|
||||
// discourse-skip-module
|
||||
(function() {
|
||||
setTimeout(function() {
|
||||
(function () {
|
||||
setTimeout(function () {
|
||||
const $activateButton = $("#activate-account-button");
|
||||
$activateButton.on("click", function() {
|
||||
$activateButton.on("click", function () {
|
||||
$activateButton.prop("disabled", true);
|
||||
const hpPath = document.getElementById("data-activate-account").dataset
|
||||
.path;
|
||||
$.ajax(hpPath)
|
||||
.then(function(hp) {
|
||||
.then(function (hp) {
|
||||
$("#password_confirmation").val(hp.value);
|
||||
$("#challenge").val(
|
||||
hp.challenge
|
||||
.split("")
|
||||
.reverse()
|
||||
.join("")
|
||||
);
|
||||
$("#challenge").val(hp.challenge.split("").reverse().join(""));
|
||||
$("#activate-account-form").submit();
|
||||
})
|
||||
.fail(function() {
|
||||
.fail(function () {
|
||||
$activateButton.prop("disabled", false);
|
||||
});
|
||||
});
|
||||
|
@ -1,11 +1,13 @@
|
||||
import RESTAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default RESTAdapter.extend({
|
||||
jsonMode: true,
|
||||
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
},
|
||||
|
||||
apiNameFor() {
|
||||
return "key";
|
||||
}
|
||||
},
|
||||
});
|
@ -6,6 +6,6 @@ export default function buildPluginAdapter(pluginName) {
|
||||
return (
|
||||
"/admin/plugins/" + pluginName + this._super(store, type, findArgs)
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
@ -3,5 +3,5 @@ import RestAdapter from "discourse/adapters/rest";
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/customize/";
|
||||
}
|
||||
},
|
||||
});
|
@ -3,5 +3,5 @@ import RestAdapter from "discourse/adapters/rest";
|
||||
export default RestAdapter.extend({
|
||||
pathFor() {
|
||||
return "/admin/customize/email_style";
|
||||
}
|
||||
},
|
||||
});
|
@ -3,5 +3,5 @@ import RestAdapter from "discourse/adapters/rest";
|
||||
export default RestAdapter.extend({
|
||||
pathFor() {
|
||||
return "/admin/customize/embedding";
|
||||
}
|
||||
},
|
||||
});
|
@ -3,5 +3,5 @@ import RestAdapter from "discourse/adapters/rest";
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/logs/";
|
||||
}
|
||||
},
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default RestAdapter.extend({
|
||||
jsonMode: true
|
||||
jsonMode: true,
|
||||
});
|
@ -7,20 +7,20 @@ export default RestAdapter.extend({
|
||||
|
||||
afterFindAll(results) {
|
||||
let map = {};
|
||||
results.forEach(theme => {
|
||||
results.forEach((theme) => {
|
||||
map[theme.id] = theme;
|
||||
});
|
||||
results.forEach(theme => {
|
||||
results.forEach((theme) => {
|
||||
let mapped = theme.get("child_themes") || [];
|
||||
mapped = mapped.map(t => map[t.id]);
|
||||
mapped = mapped.map((t) => map[t.id]);
|
||||
theme.set("childThemes", mapped);
|
||||
|
||||
let mappedParents = theme.get("parent_themes") || [];
|
||||
mappedParents = mappedParents.map(t => map[t.id]);
|
||||
mappedParents = mappedParents.map((t) => map[t.id]);
|
||||
theme.set("parentThemes", mappedParents);
|
||||
});
|
||||
return results;
|
||||
},
|
||||
|
||||
jsonMode: true
|
||||
jsonMode: true,
|
||||
});
|
@ -3,5 +3,5 @@ import RESTAdapter from "discourse/adapters/rest";
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
}
|
||||
},
|
||||
});
|
@ -3,5 +3,5 @@ import RESTAdapter from "discourse/adapters/rest";
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
}
|
||||
},
|
||||
});
|
@ -1,5 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { on } from "@ember/object/evented";
|
||||
|
||||
@ -32,6 +33,15 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
@observes("placeholder")
|
||||
placeholderChanged() {
|
||||
if (this._editor) {
|
||||
this._editor.setOptions({
|
||||
placeholder: this.placeholder,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@observes("disabled")
|
||||
disabledStateChanged() {
|
||||
this.changeDisabledState();
|
||||
@ -44,13 +54,13 @@ export default Component.extend({
|
||||
editor.setOptions({
|
||||
readOnly: disabled,
|
||||
highlightActiveLine: !disabled,
|
||||
highlightGutterLine: !disabled
|
||||
highlightGutterLine: !disabled,
|
||||
});
|
||||
editor.container.parentNode.setAttribute("data-disabled", disabled);
|
||||
}
|
||||
},
|
||||
|
||||
_destroyEditor: on("willDestroyElement", function() {
|
||||
_destroyEditor: on("willDestroyElement", function () {
|
||||
if (this._editor) {
|
||||
this._editor.destroy();
|
||||
this._editor = null;
|
||||
@ -71,9 +81,11 @@ export default Component.extend({
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
loadScript("/javascripts/ace/ace.js").then(() => {
|
||||
window.ace.require(["ace/ace"], loadedAce => {
|
||||
window.ace.require(["ace/ace"], (loadedAce) => {
|
||||
loadedAce.config.set("loadWorkerFromBlob", false);
|
||||
loadedAce.config.set("workerPath", getURL("/javascripts/ace")); // Do not use CDN for workers
|
||||
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -81,7 +93,7 @@ export default Component.extend({
|
||||
|
||||
editor.setTheme("ace/theme/chrome");
|
||||
editor.setShowPrintMargin(false);
|
||||
editor.setOptions({ fontSize: "14px" });
|
||||
editor.setOptions({ fontSize: "14px", placeholder: this.placeholder });
|
||||
editor.getSession().setMode("ace/mode/" + this.mode);
|
||||
editor.on("change", () => {
|
||||
this._skipContentChangeEvent = true;
|
||||
@ -117,6 +129,6 @@ export default Component.extend({
|
||||
this._editor.focus();
|
||||
this._editor.navigateFileEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -35,9 +35,11 @@ export default Component.extend({
|
||||
|
||||
@on("init")
|
||||
@observes("logs.[]")
|
||||
_updateFormattedLogs: discourseDebounce(function() {
|
||||
_updateFormattedLogs: discourseDebounce(function () {
|
||||
const logs = this.logs;
|
||||
if (logs.length === 0) return;
|
||||
if (logs.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do the log formatting only once for HELLish performance
|
||||
let formattedLogs = this.formattedLogs;
|
||||
@ -49,7 +51,7 @@ export default Component.extend({
|
||||
// update the formatted logs & cache index
|
||||
this.setProperties({
|
||||
formattedLogs: formattedLogs,
|
||||
index: logs.length
|
||||
index: logs.length,
|
||||
});
|
||||
// force rerender
|
||||
this.renderLogs();
|
||||
@ -70,5 +72,5 @@ export default Component.extend({
|
||||
} else {
|
||||
this.set("showLoadingSpinner", false);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
@ -19,6 +19,6 @@ export default Component.extend({
|
||||
save() {
|
||||
// Action has to toggle 'editing' property.
|
||||
this.action(this.buffer);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: ["row"]
|
||||
classNames: ["row"],
|
||||
});
|
@ -11,15 +11,15 @@ export default Component.extend({
|
||||
const rawData = this.get("model.data");
|
||||
|
||||
var data = {
|
||||
labels: rawData.map(r => r.x),
|
||||
labels: rawData.map((r) => r.x),
|
||||
datasets: [
|
||||
{
|
||||
data: rawData.map(r => r.y),
|
||||
data: rawData.map((r) => r.y),
|
||||
label: model.get("title"),
|
||||
backgroundColor: `rgba(200,220,240,${this.type === "bar" ? 1 : 0.3})`,
|
||||
borderColor: "#08C"
|
||||
}
|
||||
]
|
||||
borderColor: "#08C",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const config = {
|
||||
@ -29,21 +29,21 @@ export default Component.extend({
|
||||
responsive: true,
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
title: context =>
|
||||
moment(context[0].xLabel, "YYYY-MM-DD").format("LL")
|
||||
}
|
||||
title: (context) =>
|
||||
moment(context[0].xLabel, "YYYY-MM-DD").format("LL"),
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
display: true,
|
||||
ticks: {
|
||||
stepSize: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
stepSize: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
this._chart = new window.Chart(ctx, config);
|
||||
@ -53,5 +53,5 @@ export default Component.extend({
|
||||
loadScript("/javascripts/Chart.min.js").then(() =>
|
||||
this.refreshChart.apply(this)
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: ""
|
||||
tagName: "",
|
||||
});
|
@ -8,6 +8,7 @@ export default Component.extend({
|
||||
classNames: ["admin-report-chart"],
|
||||
limit: 8,
|
||||
total: 0,
|
||||
options: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@ -46,21 +47,27 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
_renderChart(model, chartCanvas) {
|
||||
if (!chartCanvas) return;
|
||||
if (!chartCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const context = chartCanvas.getContext("2d");
|
||||
const chartData = makeArray(model.get("chartData") || model.get("data"));
|
||||
const chartData = this._applyChartGrouping(
|
||||
model,
|
||||
makeArray(model.get("chartData") || model.get("data"), "weekly"),
|
||||
this.options
|
||||
);
|
||||
const prevChartData = makeArray(
|
||||
model.get("prevChartData") || model.get("prev_data")
|
||||
);
|
||||
|
||||
const labels = chartData.map(d => d.x);
|
||||
const labels = chartData.map((d) => d.x);
|
||||
|
||||
const data = {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
data: chartData.map(d => Math.round(parseFloat(d.y))),
|
||||
data: chartData.map((d) => Math.round(parseFloat(d.y))),
|
||||
backgroundColor: prevChartData.length
|
||||
? "transparent"
|
||||
: model.secondary_color,
|
||||
@ -68,19 +75,19 @@ export default Component.extend({
|
||||
pointRadius: 3,
|
||||
borderWidth: 1,
|
||||
pointBackgroundColor: model.primary_color,
|
||||
pointBorderColor: model.primary_color
|
||||
}
|
||||
]
|
||||
pointBorderColor: model.primary_color,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (prevChartData.length) {
|
||||
data.datasets.push({
|
||||
data: prevChartData.map(d => Math.round(parseFloat(d.y))),
|
||||
data: prevChartData.map((d) => Math.round(parseFloat(d.y))),
|
||||
borderColor: model.primary_color,
|
||||
borderDash: [5, 5],
|
||||
backgroundColor: "transparent",
|
||||
borderWidth: 1,
|
||||
pointRadius: 0
|
||||
pointRadius: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@ -91,52 +98,57 @@ export default Component.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
this._chart = new window.Chart(context, this._buildChartConfig(data));
|
||||
this._chart = new window.Chart(
|
||||
context,
|
||||
this._buildChartConfig(data, this.options)
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
_buildChartConfig(data) {
|
||||
_buildChartConfig(data, options) {
|
||||
return {
|
||||
type: "line",
|
||||
data,
|
||||
options: {
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
title: tooltipItem =>
|
||||
moment(tooltipItem[0].xLabel, "YYYY-MM-DD").format("LL")
|
||||
}
|
||||
title: (tooltipItem) =>
|
||||
moment(tooltipItem[0].xLabel, "YYYY-MM-DD").format("LL"),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
display: false,
|
||||
},
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
responsiveAnimationDuration: 0,
|
||||
animation: {
|
||||
duration: 0
|
||||
duration: 0,
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0
|
||||
}
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
display: true,
|
||||
ticks: {
|
||||
userCallback: label => {
|
||||
if (Math.floor(label) === label) return label;
|
||||
userCallback: (label) => {
|
||||
if (Math.floor(label) === label) {
|
||||
return label;
|
||||
}
|
||||
},
|
||||
callback: label => number(label),
|
||||
callback: (label) => number(label),
|
||||
sampleSize: 5,
|
||||
maxRotation: 25,
|
||||
minRotation: 25
|
||||
}
|
||||
}
|
||||
minRotation: 25,
|
||||
},
|
||||
},
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
@ -144,17 +156,17 @@ export default Component.extend({
|
||||
gridLines: { display: false },
|
||||
type: "time",
|
||||
time: {
|
||||
parser: "YYYY-MM-DD"
|
||||
unit: this._unitForGrouping(options),
|
||||
},
|
||||
ticks: {
|
||||
sampleSize: 5,
|
||||
maxRotation: 50,
|
||||
minRotation: 50
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
minRotation: 50,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -163,5 +175,65 @@ export default Component.extend({
|
||||
this._chart.destroy();
|
||||
this._chart = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_applyChartGrouping(model, data, options) {
|
||||
if (!options.chartGrouping || options.chartGrouping === "daily") {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (
|
||||
options.chartGrouping === "weekly" ||
|
||||
options.chartGrouping === "monthly"
|
||||
) {
|
||||
const isoKind = options.chartGrouping === "weekly" ? "isoWeek" : "month";
|
||||
const kind = options.chartGrouping === "weekly" ? "week" : "month";
|
||||
const startMoment = moment(model.start_date, "YYYY-MM-DD");
|
||||
|
||||
let currentIndex = 0;
|
||||
let currentStart = startMoment.clone().startOf(isoKind);
|
||||
let currentEnd = startMoment.clone().endOf(isoKind);
|
||||
const transformedData = [
|
||||
{
|
||||
x: currentStart.format("YYYY-MM-DD"),
|
||||
y: 0,
|
||||
},
|
||||
];
|
||||
|
||||
data.forEach((d) => {
|
||||
let date = moment(d.x, "YYYY-MM-DD");
|
||||
|
||||
if (!date.isBetween(currentStart, currentEnd)) {
|
||||
currentIndex += 1;
|
||||
currentStart = currentStart.add(1, kind).startOf(isoKind);
|
||||
currentEnd = currentEnd.add(1, kind).endOf(isoKind);
|
||||
}
|
||||
|
||||
if (transformedData[currentIndex]) {
|
||||
transformedData[currentIndex].y += d.y;
|
||||
} else {
|
||||
transformedData[currentIndex] = {
|
||||
x: d.x,
|
||||
y: d.y,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return transformedData;
|
||||
}
|
||||
|
||||
// ensure we return something if grouping is unknown
|
||||
return data;
|
||||
},
|
||||
|
||||
_unitForGrouping(options) {
|
||||
switch (options.chartGrouping) {
|
||||
case "monthly":
|
||||
return "month";
|
||||
case "weekly":
|
||||
return "week";
|
||||
default:
|
||||
return "day";
|
||||
}
|
||||
},
|
||||
});
|
@ -2,5 +2,5 @@ import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: ["admin-report-counters"],
|
||||
|
||||
attributeBindings: ["model.description:title"]
|
||||
attributeBindings: ["model.description:title"],
|
||||
});
|
@ -7,5 +7,5 @@ export default Component.extend({
|
||||
"report.type",
|
||||
/^(time_to_first_response|topics_with_no_response)$/
|
||||
),
|
||||
classNameBindings: ["reverseColors"]
|
||||
classNameBindings: ["reverseColors"],
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: ["admin-report-inline-table"]
|
||||
classNames: ["admin-report-inline-table"],
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "tr"
|
||||
tagName: "tr",
|
||||
});
|
@ -48,7 +48,9 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
_renderChart(model, chartCanvas) {
|
||||
if (!chartCanvas) return;
|
||||
if (!chartCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const context = chartCanvas.getContext("2d");
|
||||
|
||||
@ -56,14 +58,14 @@ export default Component.extend({
|
||||
|
||||
const data = {
|
||||
labels: chartData[0].data.mapBy("x"),
|
||||
datasets: chartData.map(cd => {
|
||||
datasets: chartData.map((cd) => {
|
||||
return {
|
||||
label: cd.label,
|
||||
stack: "pageviews-stack",
|
||||
data: cd.data.map(d => Math.round(parseFloat(d.y))),
|
||||
backgroundColor: cd.color
|
||||
data: cd.data.map((d) => Math.round(parseFloat(d.y))),
|
||||
backgroundColor: cd.color,
|
||||
};
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
loadScript("/javascripts/Chart.min.js").then(() => {
|
||||
@ -83,30 +85,30 @@ export default Component.extend({
|
||||
responsiveAnimationDuration: 0,
|
||||
hover: { mode: "index" },
|
||||
animation: {
|
||||
duration: 0
|
||||
duration: 0,
|
||||
},
|
||||
tooltips: {
|
||||
mode: "index",
|
||||
intersect: false,
|
||||
callbacks: {
|
||||
beforeFooter: tooltipItem => {
|
||||
beforeFooter: (tooltipItem) => {
|
||||
let total = 0;
|
||||
tooltipItem.forEach(
|
||||
item => (total += parseInt(item.yLabel || 0, 10))
|
||||
(item) => (total += parseInt(item.yLabel || 0, 10))
|
||||
);
|
||||
return `= ${total}`;
|
||||
},
|
||||
title: tooltipItem =>
|
||||
moment(tooltipItem[0].xLabel, "YYYY-MM-DD").format("LL")
|
||||
}
|
||||
title: (tooltipItem) =>
|
||||
moment(tooltipItem[0].xLabel, "YYYY-MM-DD").format("LL"),
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0
|
||||
}
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
yAxes: [
|
||||
@ -114,15 +116,17 @@ export default Component.extend({
|
||||
stacked: true,
|
||||
display: true,
|
||||
ticks: {
|
||||
userCallback: label => {
|
||||
if (Math.floor(label) === label) return label;
|
||||
userCallback: (label) => {
|
||||
if (Math.floor(label) === label) {
|
||||
return label;
|
||||
}
|
||||
},
|
||||
callback: label => number(label),
|
||||
callback: (label) => number(label),
|
||||
sampleSize: 5,
|
||||
maxRotation: 25,
|
||||
minRotation: 25
|
||||
}
|
||||
}
|
||||
minRotation: 25,
|
||||
},
|
||||
},
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
@ -132,17 +136,17 @@ export default Component.extend({
|
||||
offset: true,
|
||||
time: {
|
||||
parser: "YYYY-MM-DD",
|
||||
minUnit: "day"
|
||||
minUnit: "day",
|
||||
},
|
||||
ticks: {
|
||||
sampleSize: 5,
|
||||
maxRotation: 50,
|
||||
minRotation: 50
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
minRotation: 50,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -151,5 +155,5 @@ export default Component.extend({
|
||||
this._chart.destroy();
|
||||
this._chart = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
@ -39,5 +39,5 @@ export default Component.extend({
|
||||
@discourseComputed("uploadStats.free_bytes")
|
||||
freeUploadSpace(bytes) {
|
||||
return I18n.toHumanSize(bytes);
|
||||
}
|
||||
},
|
||||
});
|
@ -16,5 +16,5 @@ export default Component.extend({
|
||||
type: alias("label.type"),
|
||||
property: alias("label.mainProperty"),
|
||||
formatedValue: alias("computedLabel.formatedValue"),
|
||||
value: alias("computedLabel.value")
|
||||
value: alias("computedLabel.value"),
|
||||
});
|
@ -15,5 +15,5 @@ export default Component.extend({
|
||||
@discourseComputed("currentSortDirection")
|
||||
sortIcon(currentSortDirection) {
|
||||
return currentSortDirection === 1 ? "caret-up" : "caret-down";
|
||||
}
|
||||
},
|
||||
});
|
@ -2,5 +2,5 @@ import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "tr",
|
||||
classNames: ["admin-report-table-row"],
|
||||
options: null
|
||||
options: null,
|
||||
});
|
@ -26,7 +26,7 @@ export default Component.extend({
|
||||
showTotalForSample(totalsForSample, total, datesFiltering) {
|
||||
// check if we have at least one cell which contains a value
|
||||
const sum = totalsForSample
|
||||
.map(t => t.value)
|
||||
.map((t) => t.value)
|
||||
.compact()
|
||||
.reduce((s, v) => s + v, 0);
|
||||
|
||||
@ -64,7 +64,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("totalsForSampleRow", "model.computedLabels")
|
||||
totalsForSample(row, labels) {
|
||||
return labels.map(label => {
|
||||
return labels.map((label) => {
|
||||
const computedLabel = label.compute(row);
|
||||
computedLabel.type = label.type;
|
||||
computedLabel.property = label.mainProperty;
|
||||
@ -74,11 +74,13 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("model.data", "model.computedLabels")
|
||||
totalsForSampleRow(rows, labels) {
|
||||
if (!rows || !rows.length) return {};
|
||||
if (!rows || !rows.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
let totalsRow = {};
|
||||
|
||||
labels.forEach(label => {
|
||||
labels.forEach((label) => {
|
||||
const reducer = (sum, row) => {
|
||||
const computedLabel = label.compute(row);
|
||||
const value = computedLabel.value;
|
||||
@ -130,18 +132,20 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("model.data", "perPage", "page")
|
||||
pages(data, perPage, page) {
|
||||
if (!data || data.length <= perPage) return [];
|
||||
if (!data || data.length <= perPage) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const pagesIndexes = [];
|
||||
for (let i = 0; i < Math.ceil(data.length / perPage); i++) {
|
||||
pagesIndexes.push(i);
|
||||
}
|
||||
|
||||
let pages = pagesIndexes.map(v => {
|
||||
let pages = pagesIndexes.map((v) => {
|
||||
return {
|
||||
page: v + 1,
|
||||
index: v,
|
||||
class: v === page ? "is-current" : null
|
||||
class: v === page ? "is-current" : null,
|
||||
};
|
||||
});
|
||||
|
||||
@ -165,6 +169,6 @@ export default Component.extend({
|
||||
} else {
|
||||
this.set("sortLabel", label);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "tr"
|
||||
tagName: "tr",
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { alias, or, and, equal, notEmpty, not } from "@ember/object/computed";
|
||||
import { alias, or, and, equal, notEmpty } from "@ember/object/computed";
|
||||
import EmberObject, { computed, action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
@ -16,7 +16,7 @@ const TABLE_OPTIONS = {
|
||||
perPage: 8,
|
||||
total: true,
|
||||
limit: 20,
|
||||
formatNumbers: true
|
||||
formatNumbers: true,
|
||||
};
|
||||
|
||||
const CHART_OPTIONS = {};
|
||||
@ -43,10 +43,11 @@ function collapseWeekly(data, average) {
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [
|
||||
"isVisible",
|
||||
"isHidden:hidden",
|
||||
"isHidden::is-visible",
|
||||
"isEnabled",
|
||||
"isLoading",
|
||||
"dasherizedDataSourceName"
|
||||
"dasherizedDataSourceName",
|
||||
],
|
||||
classNames: ["admin-report"],
|
||||
isEnabled: true,
|
||||
@ -67,7 +68,6 @@ export default Component.extend({
|
||||
showDatesOptions: alias("model.dates_filtering"),
|
||||
showRefresh: or("showDatesOptions", "model.available_filters.length"),
|
||||
shouldDisplayTrend: and("showTrend", "model.prev_period"),
|
||||
isVisible: not("isHidden"),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@ -75,14 +75,14 @@ export default Component.extend({
|
||||
this._reports = [];
|
||||
},
|
||||
|
||||
isHidden: computed("siteSettings.dashboard_hidden_reports", function() {
|
||||
isHidden: computed("siteSettings.dashboard_hidden_reports", function () {
|
||||
return (this.siteSettings.dashboard_hidden_reports || "")
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.includes(this.dataSourceName);
|
||||
}),
|
||||
|
||||
startDate: computed("filters.startDate", function() {
|
||||
startDate: computed("filters.startDate", function () {
|
||||
if (this.filters && isPresent(this.filters.startDate)) {
|
||||
return moment(this.filters.startDate, "YYYY-MM-DD");
|
||||
} else {
|
||||
@ -90,7 +90,7 @@ export default Component.extend({
|
||||
}
|
||||
}),
|
||||
|
||||
endDate: computed("filters.endDate", function() {
|
||||
endDate: computed("filters.endDate", function () {
|
||||
if (this.filters && isPresent(this.filters.endDate)) {
|
||||
return moment(this.filters.endDate, "YYYY-MM-DD");
|
||||
} else {
|
||||
@ -131,18 +131,30 @@ export default Component.extend({
|
||||
return displayedModesLength > 1;
|
||||
},
|
||||
|
||||
@discourseComputed("currentMode")
|
||||
isChartMode(currentMode) {
|
||||
return currentMode === "chart";
|
||||
},
|
||||
|
||||
@action
|
||||
changeGrouping(grouping) {
|
||||
this.send("refreshReport", {
|
||||
chartGrouping: grouping,
|
||||
});
|
||||
},
|
||||
|
||||
@discourseComputed("currentMode", "model.modes", "forcedModes")
|
||||
displayedModes(currentMode, reportModes, forcedModes) {
|
||||
const modes = forcedModes ? forcedModes.split(",") : reportModes;
|
||||
|
||||
return makeArray(modes).map(mode => {
|
||||
return makeArray(modes).map((mode) => {
|
||||
const base = `btn-default mode-btn ${mode}`;
|
||||
const cssClass = currentMode === mode ? `${base} is-current` : base;
|
||||
|
||||
return {
|
||||
mode,
|
||||
cssClass,
|
||||
icon: mode === "table" ? "table" : "signal"
|
||||
icon: mode === "table" ? "table" : "signal",
|
||||
};
|
||||
});
|
||||
},
|
||||
@ -159,7 +171,9 @@ export default Component.extend({
|
||||
"filters.customFilters"
|
||||
)
|
||||
reportKey(dataSourceName, startDate, endDate, customFilters) {
|
||||
if (!dataSourceName || !startDate || !endDate) return null;
|
||||
if (!dataSourceName || !startDate || !endDate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
startDate = startDate.toISOString(true).split("T")[0];
|
||||
endDate = endDate.toISOString(true).split("T")[0];
|
||||
@ -175,20 +189,33 @@ export default Component.extend({
|
||||
customFilters
|
||||
? JSON.stringify(customFilters, (k, v) => (k ? `${v}` : v))
|
||||
: null,
|
||||
SCHEMA_VERSION
|
||||
SCHEMA_VERSION,
|
||||
]
|
||||
.filter(x => x)
|
||||
.map(x => x.toString())
|
||||
.filter((x) => x)
|
||||
.map((x) => x.toString())
|
||||
.join(":");
|
||||
|
||||
return reportKey;
|
||||
},
|
||||
|
||||
@discourseComputed("reportOptions.chartGrouping")
|
||||
chartGroupings(chartGrouping) {
|
||||
chartGrouping = chartGrouping || "daily";
|
||||
|
||||
return ["daily", "weekly", "monthly"].map((id) => {
|
||||
return {
|
||||
id,
|
||||
label: `admin.dashboard.reports.${id}`,
|
||||
class: `chart-grouping ${chartGrouping === id ? "active" : "inactive"}`,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
onChangeDateRange(range) {
|
||||
this.send("refreshReport", {
|
||||
startDate: range.from,
|
||||
endDate: range.to
|
||||
endDate: range.to,
|
||||
});
|
||||
},
|
||||
|
||||
@ -203,14 +230,19 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
this.send("refreshReport", {
|
||||
filters: customFilters
|
||||
filters: customFilters,
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
refreshReport(options = {}) {
|
||||
if (!this.attrs.onRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.attrs.onRefresh({
|
||||
type: this.get("model.type"),
|
||||
chartGrouping: options.chartGrouping,
|
||||
startDate:
|
||||
typeof options.startDate === "undefined"
|
||||
? this.startDate
|
||||
@ -220,7 +252,7 @@ export default Component.extend({
|
||||
filters:
|
||||
typeof options.filters === "undefined"
|
||||
? this.get("filters.customFilters")
|
||||
: options.filters
|
||||
: options.filters,
|
||||
});
|
||||
},
|
||||
|
||||
@ -229,7 +261,7 @@ export default Component.extend({
|
||||
const args = {
|
||||
name: this.get("model.type"),
|
||||
start_date: this.startDate.toISOString(true).split("T")[0],
|
||||
end_date: this.endDate.toISOString(true).split("T")[0]
|
||||
end_date: this.endDate.toISOString(true).split("T")[0],
|
||||
};
|
||||
|
||||
const customFilters = this.get("filters.customFilters");
|
||||
@ -243,6 +275,10 @@ export default Component.extend({
|
||||
@action
|
||||
changeMode(mode) {
|
||||
this.set("currentMode", mode);
|
||||
|
||||
this.send("refreshReport", {
|
||||
chartGrouping: null,
|
||||
});
|
||||
},
|
||||
|
||||
_computeReport() {
|
||||
@ -261,7 +297,7 @@ export default Component.extend({
|
||||
let filteredReports = this._reports.uniqBy("report_key");
|
||||
let report;
|
||||
|
||||
const sort = r => {
|
||||
const sort = (r) => {
|
||||
if (r.length > 1) {
|
||||
return r.findBy("type", this.dataSourceName);
|
||||
} else {
|
||||
@ -273,10 +309,12 @@ export default Component.extend({
|
||||
report = sort(filteredReports)[0];
|
||||
} else {
|
||||
report = sort(
|
||||
filteredReports.filter(r => r.report_key.includes(this.reportKey))
|
||||
filteredReports.filter((r) => r.report_key.includes(this.reportKey))
|
||||
)[0];
|
||||
|
||||
if (!report) return;
|
||||
if (!report) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (report.error === "not_found") {
|
||||
@ -293,7 +331,7 @@ export default Component.extend({
|
||||
this.setProperties({
|
||||
model: report,
|
||||
currentMode,
|
||||
options: this._buildOptions(currentMode)
|
||||
options: this._buildOptions(currentMode),
|
||||
});
|
||||
},
|
||||
|
||||
@ -305,7 +343,7 @@ export default Component.extend({
|
||||
next(() => {
|
||||
let payload = this._buildPayload(["prev_period"]);
|
||||
|
||||
const callback = response => {
|
||||
const callback = (response) => {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -364,7 +402,9 @@ export default Component.extend({
|
||||
} else {
|
||||
const chartOptions = JSON.parse(JSON.stringify(CHART_OPTIONS));
|
||||
return EmberObject.create(
|
||||
Object.assign(chartOptions, this.get("reportOptions.chart") || {})
|
||||
Object.assign(chartOptions, this.get("reportOptions.chart") || {}, {
|
||||
chartGrouping: this.get("reportOptions.chartGrouping"),
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -373,13 +413,13 @@ export default Component.extend({
|
||||
Report.fillMissingDates(jsonReport, { filledField: "chartData" });
|
||||
|
||||
if (jsonReport.chartData && jsonReport.modes[0] === "stacked_chart") {
|
||||
jsonReport.chartData = jsonReport.chartData.map(chartData => {
|
||||
jsonReport.chartData = jsonReport.chartData.map((chartData) => {
|
||||
if (chartData.length > 40) {
|
||||
return {
|
||||
data: collapseWeekly(chartData.data),
|
||||
req: chartData.req,
|
||||
label: chartData.label,
|
||||
color: chartData.color
|
||||
color: chartData.color,
|
||||
};
|
||||
} else {
|
||||
return chartData;
|
||||
@ -397,7 +437,7 @@ export default Component.extend({
|
||||
filledField: "prevChartData",
|
||||
dataField: "prev_data",
|
||||
starDate: jsonReport.prev_startDate,
|
||||
endDate: jsonReport.prev_endDate
|
||||
endDate: jsonReport.prev_endDate,
|
||||
});
|
||||
|
||||
if (jsonReport.prevChartData && jsonReport.prevChartData.length > 40) {
|
||||
@ -409,5 +449,5 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
return Report.create(jsonReport);
|
||||
}
|
||||
},
|
||||
});
|
@ -1,3 +1,4 @@
|
||||
import I18n from "I18n";
|
||||
import { next } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
@ -6,7 +7,7 @@ import { fmt } from "discourse/lib/computed";
|
||||
export default Component.extend({
|
||||
@discourseComputed("theme.targets", "onlyOverridden", "showAdvanced")
|
||||
visibleTargets(targets, onlyOverridden, showAdvanced) {
|
||||
return targets.filter(target => {
|
||||
return targets.filter((target) => {
|
||||
if (target.advanced && !showAdvanced) {
|
||||
return false;
|
||||
}
|
||||
@ -21,18 +22,32 @@ export default Component.extend({
|
||||
visibleFields(targetName, onlyOverridden, fields) {
|
||||
fields = fields[targetName];
|
||||
if (onlyOverridden) {
|
||||
fields = fields.filter(field => field.edited);
|
||||
fields = fields.filter((field) => field.edited);
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
|
||||
@discourseComputed("currentTargetName", "fieldName")
|
||||
activeSectionMode(targetName, fieldName) {
|
||||
if (["settings", "translations"].includes(targetName)) return "yaml";
|
||||
if (["extra_scss"].includes(targetName)) return "scss";
|
||||
if (["settings", "translations"].includes(targetName)) {
|
||||
return "yaml";
|
||||
}
|
||||
if (["extra_scss"].includes(targetName)) {
|
||||
return "scss";
|
||||
}
|
||||
if (["color_definitions"].includes(fieldName)) {
|
||||
return "scss";
|
||||
}
|
||||
return fieldName && fieldName.indexOf("scss") > -1 ? "scss" : "html";
|
||||
},
|
||||
|
||||
@discourseComputed("currentTargetName", "fieldName")
|
||||
placeholder(targetName, fieldName) {
|
||||
return fieldName && fieldName === "color_definitions"
|
||||
? I18n.t("admin.customize.theme.color_definitions.placeholder")
|
||||
: "";
|
||||
},
|
||||
|
||||
@discourseComputed("fieldName", "currentTargetName", "theme")
|
||||
activeSection: {
|
||||
get(fieldName, target, model) {
|
||||
@ -41,7 +56,7 @@ export default Component.extend({
|
||||
set(value, fieldName, target, model) {
|
||||
model.setField(target, fieldName, value);
|
||||
return value;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
editorId: fmt("fieldName", "currentTargetName", "%@|%@"),
|
||||
@ -53,7 +68,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("currentTargetName", "theme.targets")
|
||||
showAddField(currentTargetName, targets) {
|
||||
return targets.find(t => t.name === currentTargetName).customNames;
|
||||
return targets.find((t) => t.name === currentTargetName).customNames;
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
@ -79,20 +94,22 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
addField(name) {
|
||||
if (!name) return;
|
||||
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() {
|
||||
toggleMaximize: function () {
|
||||
this.toggleProperty("maximized");
|
||||
next(() => this.appEvents.trigger("ace:resize"));
|
||||
},
|
||||
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -6,11 +6,10 @@ import Component from "@ember/component";
|
||||
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 { propertyEqual, i18n } from "discourse/lib/computed";
|
||||
import discourseComputed, {
|
||||
observes,
|
||||
on
|
||||
on,
|
||||
} from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend(bufferedProperty("userField"), {
|
||||
@ -103,6 +102,6 @@ export default Component.extend(bufferedProperty("userField"), {
|
||||
this.rollbackBuffer();
|
||||
this.set("editing", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import Component from "@ember/component";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["watched-word"],
|
||||
@ -18,12 +19,12 @@ export default Component.extend({
|
||||
.then(() => {
|
||||
this.action(this.word);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch((e) => {
|
||||
bootbox.alert(
|
||||
I18n.t("generic_error_with_reason", {
|
||||
error: `http: ${e.status} - ${e.body}`
|
||||
error: `http: ${e.status} - ${e.body}`,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
@ -19,7 +19,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("model.[]", "typeName")
|
||||
eventTypeExists(eventTypes, typeName) {
|
||||
return eventTypes.any(event => event.name === typeName);
|
||||
return eventTypes.any((event) => event.name === typeName);
|
||||
},
|
||||
|
||||
@discourseComputed("eventTypeExists")
|
||||
@ -36,12 +36,12 @@ export default Component.extend({
|
||||
model.addObject(type);
|
||||
} else {
|
||||
model.removeObjects(
|
||||
model.filter(eventType => eventType.name === type.name)
|
||||
model.filter((eventType) => eventType.name === type.name)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -4,6 +4,7 @@ import Component from "@ember/component";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { ensureJSON, plainJSON, prettyJSON } from "discourse/lib/formatter";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "li",
|
||||
@ -13,7 +14,9 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("model.status")
|
||||
statusColorClasses(status) {
|
||||
if (!status) return "";
|
||||
if (!status) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (status >= 200 && status <= 299) {
|
||||
return "text-successful";
|
||||
@ -53,7 +56,7 @@ export default Component.extend({
|
||||
I18n.t("admin.web_hooks.events.redeliver_confirm"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
result => {
|
||||
(result) => {
|
||||
if (result) {
|
||||
ajax(
|
||||
`/admin/api/web_hooks/${this.get(
|
||||
@ -61,7 +64,7 @@ export default Component.extend({
|
||||
)}/events/${this.get("model.id")}/redeliver`,
|
||||
{ type: "POST" }
|
||||
)
|
||||
.then(json => {
|
||||
.then((json) => {
|
||||
this.set("model", json.web_hook_event);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
@ -74,10 +77,10 @@ export default Component.extend({
|
||||
const expandDetailsKey = this.expandDetailsRequestKey;
|
||||
|
||||
if (this.expandDetails !== expandDetailsKey) {
|
||||
let headers = _.extend(
|
||||
let headers = Object.assign(
|
||||
{
|
||||
"Request URL": this.get("model.request_url"),
|
||||
"Request method": "POST"
|
||||
"Request method": "POST",
|
||||
},
|
||||
ensureJSON(this.get("model.headers"))
|
||||
);
|
||||
@ -85,7 +88,7 @@ export default Component.extend({
|
||||
headers: plainJSON(headers),
|
||||
body: prettyJSON(this.get("model.payload")),
|
||||
expandDetails: expandDetailsKey,
|
||||
bodyLabel: I18n.t("admin.web_hooks.events.payload")
|
||||
bodyLabel: I18n.t("admin.web_hooks.events.payload"),
|
||||
});
|
||||
} else {
|
||||
this.set("expandDetails", null);
|
||||
@ -100,11 +103,11 @@ export default Component.extend({
|
||||
headers: plainJSON(this.get("model.response_headers")),
|
||||
body: this.get("model.response_body"),
|
||||
expandDetails: expandDetailsKey,
|
||||
bodyLabel: I18n.t("admin.web_hooks.events.body")
|
||||
bodyLabel: I18n.t("admin.web_hooks.events.body"),
|
||||
});
|
||||
} else {
|
||||
this.set("expandDetails", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -11,7 +11,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("deliveryStatuses", "model.last_delivery_status")
|
||||
status(deliveryStatuses, lastDeliveryStatus) {
|
||||
return deliveryStatuses.find(s => s.id === lastDeliveryStatus);
|
||||
return deliveryStatuses.find((s) => s.id === lastDeliveryStatus);
|
||||
},
|
||||
|
||||
@discourseComputed("status.id", "icons")
|
||||
@ -34,5 +34,5 @@ export default Component.extend({
|
||||
"deliveryStatus",
|
||||
I18n.t(`admin.web_hooks.delivery_status.${this.get("status.name")}`)
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
@ -8,5 +8,5 @@ export default Component.extend({
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
$("body").removeClass("admin-interface");
|
||||
}
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: ""
|
||||
tagName: "",
|
||||
});
|
@ -18,7 +18,7 @@ export default Component.extend({
|
||||
|
||||
styleSelection: true,
|
||||
|
||||
maxlength: computed("onlyHex", function() {
|
||||
maxlength: computed("onlyHex", function () {
|
||||
return this.onlyHex ? 6 : null;
|
||||
}),
|
||||
|
||||
@ -28,7 +28,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
@observes("hexValue", "brightnessValue", "valid")
|
||||
hexValueChanged: function() {
|
||||
hexValueChanged: function () {
|
||||
const hex = this.hexValue;
|
||||
let text = this.element.querySelector("input.hex-input");
|
||||
|
||||
@ -47,7 +47,7 @@ export default Component.extend({
|
||||
|
||||
if (this.pickerLoaded) {
|
||||
$(this.element.querySelector(".picker")).spectrum({
|
||||
color: "#" + hex
|
||||
color: "#" + hex,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -69,5 +69,5 @@ export default Component.extend({
|
||||
});
|
||||
});
|
||||
schedule("afterRender", () => this.hexValueChanged());
|
||||
}
|
||||
},
|
||||
});
|
@ -2,6 +2,7 @@ import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { reads } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
editorId: reads("fieldName"),
|
||||
@ -27,18 +28,18 @@ export default Component.extend({
|
||||
set(value, styles, fieldName) {
|
||||
styles.setField(fieldName, value);
|
||||
return value;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
reset() {
|
||||
bootbox.confirm(
|
||||
I18n.t("admin.customize.email_style.reset_confirm", {
|
||||
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`)
|
||||
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`),
|
||||
}),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
result => {
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.styles.setField(
|
||||
this.fieldName,
|
||||
@ -48,6 +49,6 @@ export default Component.extend({
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,13 +1,16 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import discourseComputed, {
|
||||
on,
|
||||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { or } from "@ember/object/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { on, observes } from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import Category from "discourse/models/category";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend(bufferedProperty("host"), {
|
||||
editToggled: false,
|
||||
@ -42,7 +45,7 @@ export default Component.extend(bufferedProperty("host"), {
|
||||
|
||||
const props = this.buffered.getProperties(
|
||||
"host",
|
||||
"path_whitelist",
|
||||
"allowed_paths",
|
||||
"class_name"
|
||||
);
|
||||
props.category_id = this.categoryId;
|
||||
@ -59,7 +62,7 @@ export default Component.extend(bufferedProperty("host"), {
|
||||
},
|
||||
|
||||
delete() {
|
||||
bootbox.confirm(I18n.t("admin.embedding.confirm_delete"), result => {
|
||||
bootbox.confirm(I18n.t("admin.embedding.confirm_delete"), (result) => {
|
||||
if (result) {
|
||||
this.host.destroyRecord().then(() => {
|
||||
this.deleteHost(this.host);
|
||||
@ -76,6 +79,6 @@ export default Component.extend(bufferedProperty("host"), {
|
||||
this.rollbackBuffer();
|
||||
this.set("editToggled", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -27,6 +27,6 @@ export default Component.extend({
|
||||
set(value) {
|
||||
this.set("value", value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: ["flag-user-lists"]
|
||||
classNames: ["flag-user-lists"],
|
||||
});
|
@ -5,7 +5,7 @@ import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
export default Component.extend({
|
||||
@on("didInsertElement")
|
||||
@observes("code")
|
||||
_refresh: function() {
|
||||
highlightSyntax($(this.element));
|
||||
}
|
||||
_refresh() {
|
||||
highlightSyntax(this.element, this.siteSettings, this.session);
|
||||
},
|
||||
});
|
@ -0,0 +1,44 @@
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["inline-edit"],
|
||||
|
||||
buffer: null,
|
||||
bufferModelId: null,
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.modelId !== this.bufferModelId) {
|
||||
// HACK: The condition above ensures this method is called only when its
|
||||
// attributes are changed (i.e. only when `checked` changes).
|
||||
//
|
||||
// Reproduction steps: navigate to theme #1, switch to theme #2 from the
|
||||
// left-side panel, then switch back to theme #1 and click on the <input>
|
||||
// element wrapped by this component. It will call `didReceiveAttrs` even
|
||||
// though none of the attributes have changed (only `buffer` does).
|
||||
this.setProperties({
|
||||
buffer: this.checked,
|
||||
bufferModelId: this.modelId,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("checked", "buffer")
|
||||
changed(checked, buffer) {
|
||||
return !!checked !== !!buffer;
|
||||
},
|
||||
|
||||
@action
|
||||
apply() {
|
||||
this.set("checked", this.buffer);
|
||||
this.action();
|
||||
},
|
||||
|
||||
@action
|
||||
cancel() {
|
||||
this.set("buffer", this.checked);
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
classNames: ["install-theme-item"]
|
||||
classNames: ["install-theme-item"],
|
||||
});
|
@ -6,6 +6,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import AdminUser from "admin/models/admin-user";
|
||||
import copyText from "discourse/lib/copy-text";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["ip-lookup"],
|
||||
@ -23,7 +24,9 @@ export default Component.extend({
|
||||
this.set("show", true);
|
||||
|
||||
if (!this.location) {
|
||||
ajax("/admin/users/ip-info", { data: { ip: this.ip } }).then(location =>
|
||||
ajax("/admin/users/ip-info", {
|
||||
data: { ip: this.ip },
|
||||
}).then((location) =>
|
||||
this.set("location", EmberObject.create(location))
|
||||
);
|
||||
}
|
||||
@ -34,17 +37,17 @@ export default Component.extend({
|
||||
const data = {
|
||||
ip: this.ip,
|
||||
exclude: this.userId,
|
||||
order: "trust_level DESC"
|
||||
order: "trust_level DESC",
|
||||
};
|
||||
|
||||
ajax("/admin/users/total-others-with-same-ip", { data }).then(result =>
|
||||
this.set("totalOthersWithSameIP", result.total)
|
||||
);
|
||||
ajax("/admin/users/total-others-with-same-ip", {
|
||||
data,
|
||||
}).then((result) => this.set("totalOthersWithSameIP", result.total));
|
||||
|
||||
AdminUser.findAll("active", data).then(users => {
|
||||
AdminUser.findAll("active", data).then((users) => {
|
||||
this.setProperties({
|
||||
other_accounts: users,
|
||||
otherAccountsLoading: false
|
||||
otherAccountsLoading: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -90,12 +93,12 @@ export default Component.extend({
|
||||
I18n.t("ip_lookup.confirm_delete_other_accounts"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
confirmed => {
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
this.setProperties({
|
||||
other_accounts: null,
|
||||
otherAccountsLoading: true,
|
||||
totalOthersWithSameIP: null
|
||||
totalOthersWithSameIP: null,
|
||||
});
|
||||
|
||||
ajax("/admin/users/delete-others-with-same-ip.json", {
|
||||
@ -103,12 +106,12 @@ export default Component.extend({
|
||||
data: {
|
||||
ip: this.ip,
|
||||
exclude: this.userId,
|
||||
order: "trust_level DESC"
|
||||
}
|
||||
order: "trust_level DESC",
|
||||
},
|
||||
}).then(() => this.send("lookup"));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
tagName: "tr"
|
||||
tagName: "tr",
|
||||
});
|
@ -1,8 +1,9 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import discourseComputed, {
|
||||
afterRender,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { afterRender } from "discourse-common/utils/decorators";
|
||||
|
||||
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
||||
|
||||
@ -13,7 +14,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed
|
||||
penaltyActions() {
|
||||
return ACTIONS.map(id => {
|
||||
return ACTIONS.map((id) => {
|
||||
return { id, name: I18n.t(`admin.user.penalty_post_${id}`) };
|
||||
});
|
||||
},
|
||||
@ -28,7 +29,7 @@ export default Component.extend({
|
||||
if (postAction === "edit") {
|
||||
this._focusEditTextarea();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@afterRender
|
||||
@ -37,5 +38,5 @@ export default Component.extend({
|
||||
const body = elem.closest(".modal-body");
|
||||
body.scrollTo(0, body.clientHeight);
|
||||
elem.querySelector(".post-editor").focus();
|
||||
}
|
||||
},
|
||||
});
|
@ -4,6 +4,7 @@ import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import Permalink from "admin/models/permalink";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["permalink-form"],
|
||||
@ -18,7 +19,7 @@ export default Component.extend({
|
||||
{ id: "post_id", name: I18n.t("admin.permalink.post_id") },
|
||||
{ id: "category_id", name: I18n.t("admin.permalink.category_id") },
|
||||
{ id: "tag_name", name: I18n.t("admin.permalink.tag_name") },
|
||||
{ id: "external_url", name: I18n.t("admin.permalink.external_url") }
|
||||
{ id: "external_url", name: I18n.t("admin.permalink.external_url") },
|
||||
];
|
||||
},
|
||||
|
||||
@ -26,7 +27,7 @@ export default Component.extend({
|
||||
this._super(...arguments);
|
||||
|
||||
schedule("afterRender", () => {
|
||||
$(this.element.querySelector(".external-url")).keydown(e => {
|
||||
$(this.element.querySelector(".external-url")).keydown((e) => {
|
||||
// enter key
|
||||
if (e.keyCode === 13) {
|
||||
this.send("submit");
|
||||
@ -49,28 +50,28 @@ export default Component.extend({
|
||||
Permalink.create({
|
||||
url: this.url,
|
||||
permalink_type: this.permalinkType,
|
||||
permalink_type_value: this.permalink_type_value
|
||||
permalink_type_value: this.permalink_type_value,
|
||||
})
|
||||
.save()
|
||||
.then(
|
||||
result => {
|
||||
(result) => {
|
||||
this.setProperties({
|
||||
url: "",
|
||||
permalink_type_value: "",
|
||||
formSubmitted: false
|
||||
formSubmitted: false,
|
||||
});
|
||||
|
||||
this.action(Permalink.create(result.permalink));
|
||||
|
||||
this.focusPermalink();
|
||||
},
|
||||
e => {
|
||||
(e) => {
|
||||
this.set("formSubmitted", false);
|
||||
|
||||
let error;
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
error = I18n.t("generic_error_with_reason", {
|
||||
error: e.responseJSON.errors.join(". ")
|
||||
error: e.responseJSON.errors.join(". "),
|
||||
});
|
||||
} else {
|
||||
error = I18n.t("generic_error");
|
||||
@ -83,6 +84,6 @@ export default Component.extend({
|
||||
|
||||
onChangePermalinkType(type) {
|
||||
this.set("permalinkType", type);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|