Merge master
13
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Discourse",
|
||||
"image": "discourse/discourse_dev:release",
|
||||
"workspaceMount": "source=${localWorkspaceFolder}/../..,target=/var/www/discourse,type=bind",
|
||||
"workspaceFolder": "/var/www/discourse",
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
"postCreateCommand": "sudo /sbin/boot",
|
||||
"extensions": ["rebornix.Ruby"],
|
||||
"forwardPorts": [9292],
|
||||
"remoteUser": "discourse"
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
app/assets/javascripts/browser-update.js
|
||||
app/assets/javascripts/discourse-loader.js
|
||||
app/assets/javascripts/env.js
|
||||
app/assets/javascripts/main_include_admin.js
|
||||
app/assets/javascripts/vendor.js
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"extends": "eslint-config-discourse",
|
||||
"rules": {
|
||||
"discourse-ember/global-ember": 2,
|
||||
"no-duplicate-imports": 2
|
||||
"eol-last": 2
|
||||
},
|
||||
"globals": {
|
||||
"moduleFor": "off",
|
||||
@ -13,6 +13,6 @@
|
||||
"currentURL": "off",
|
||||
"invisible": "off",
|
||||
"visible": "off",
|
||||
"count": "off",
|
||||
"count": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,10 +45,13 @@ bf88410126f73aab47b7e694e3c5b46453cec1b6
|
||||
ce3fe2f4c4ddf166949ee3cec3d9ecbf9108ab52
|
||||
|
||||
# REFACTOR: Move qunit tests to a different directory structure
|
||||
bc97c79a35d8acd283d4d8b79aa079bce9d127c6
|
||||
445d6ba45fe954fb7de11ce7b1392232160e2b63
|
||||
|
||||
# REFACTOR: Move javascript tests inside discourse app
|
||||
23f24bfb510edb25b18b6a0d5485270c88df9b24
|
||||
|
||||
# DEV: Tidy up imports. (#11364)
|
||||
1c2358ba162eb9f9ba9095c9afe30cf51dd85e04
|
||||
|
||||
# DEV: Sort imports alphabetically (#11382)
|
||||
bbe5d8d5cf1220165842985c0e2cd4c454d501cd
|
||||
|
||||
4
.github/dependabot.yml
vendored
@ -1,5 +1,9 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: bundler
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
||||
222
.github/workflows/ci.yml
vendored
@ -1,222 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- "tests-passed"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "${{ matrix.target }}-${{ matrix.build_types }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
DISCOURSE_HOSTNAME: www.example.com
|
||||
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
|
||||
BUILD_TYPE: ${{ matrix.build_types }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
RAILS_ENV: test
|
||||
PGHOST: localhost
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
build_types: ["BACKEND", "FRONTEND", "LINT"]
|
||||
target: ["PLUGINS", "CORE"]
|
||||
os: [ubuntu-latest]
|
||||
ruby: ["2.6"]
|
||||
postgres: ["12"]
|
||||
redis: ["4.x"]
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:${{ matrix.postgres }}
|
||||
ports:
|
||||
- 5432:5432
|
||||
env:
|
||||
POSTGRES_USER: discourse
|
||||
POSTGRES_PASSWORD: discourse
|
||||
POSTGRES_DB: discourse_test
|
||||
options: >-
|
||||
--mount type=tmpfs,destination=/var/lib/postgresql/data
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Setup packages
|
||||
if: env.BUILD_TYPE != 'LINT'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
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
|
||||
if: env.BUILD_TYPE == 'BACKEND'
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-imagemagick
|
||||
chmod +x install-imagemagick
|
||||
sudo ./install-imagemagick
|
||||
|
||||
- name: Setup redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
if: env.BUILD_TYPE != 'LINT'
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
|
||||
- name: Setup ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
|
||||
- name: Setup bundler
|
||||
run: |
|
||||
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@v2
|
||||
id: bundler-cache
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: bundle install --jobs 4
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ matrix.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install --dev
|
||||
|
||||
- name: "Checkout official plugins"
|
||||
if: env.TARGET == 'PLUGINS'
|
||||
run: bin/rake plugin:install_all_official
|
||||
|
||||
- name: Create database
|
||||
if: env.BUILD_TYPE != 'LINT'
|
||||
run: |
|
||||
bin/rake db:create
|
||||
bin/rake db:migrate
|
||||
|
||||
- name: Create parallel databases
|
||||
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'CORE'
|
||||
run: |
|
||||
bin/rake parallel:create
|
||||
bin/rake parallel:migrate
|
||||
|
||||
- name: Rubocop (core and core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: bundle exec rubocop .
|
||||
|
||||
- name: Rubocop (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: bundle exec rubocop plugins
|
||||
|
||||
- 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,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'
|
||||
run: bundle exec ruby script/i18n_lint.rb "config/**/locales/{client,server}.en.yml"
|
||||
|
||||
- name: Plugin English locale
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: bundle exec ruby script/i18n_lint.rb "plugins/**/locales/{client,server}.en.yml"
|
||||
|
||||
- name: Core RSpec
|
||||
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'CORE'
|
||||
run: |
|
||||
bin/turbo_rspec
|
||||
bin/rake plugin:spec
|
||||
|
||||
- name: Plugin RSpec
|
||||
if: env.BUILD_TYPE == 'BACKEND' && env.TARGET == 'PLUGINS'
|
||||
run: bin/rake plugin:spec
|
||||
|
||||
- name: Core QUnit
|
||||
if: env.BUILD_TYPE == 'FRONTEND' && env.TARGET == 'CORE'
|
||||
run: bundle exec rake qunit:test['1200000']
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Wizard QUnit
|
||||
if: env.BUILD_TYPE == 'FRONTEND' && env.TARGET == 'CORE'
|
||||
run: bundle exec rake qunit:test['1200000','/wizard/qunit']
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Plugin QUnit # Tests core plugins in TARGET=CORE, and all plugins in TARGET=PLUGINS
|
||||
if: env.BUILD_TYPE == 'FRONTEND'
|
||||
run: bundle exec rake plugin:qunit['*','1200000']
|
||||
timeout-minutes: 30
|
||||
47
.github/workflows/ember.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Ember CLI tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: run
|
||||
runs-on: ubuntu-latest
|
||||
container: discourse/discourse_test:release
|
||||
timeout-minutes: 40
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
working-directory: ./app/assets/javascripts/discourse
|
||||
run: yarn install
|
||||
|
||||
- name: Core QUnit
|
||||
working-directory: ./app/assets/javascripts/discourse
|
||||
run: yarn ember test
|
||||
timeout-minutes: 30
|
||||
94
.github/workflows/linting.yml
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
name: Linting
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: run
|
||||
runs-on: ubuntu-latest
|
||||
container: discourse/discourse_test:release
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: |
|
||||
bundle config --local path vendor/bundle
|
||||
bundle config --local deployment true
|
||||
bundle config --local without development
|
||||
bundle install --jobs 4
|
||||
bundle clean
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install
|
||||
|
||||
- name: Rubocop
|
||||
if: ${{ always() }}
|
||||
run: bundle exec rubocop .
|
||||
|
||||
- name: ESLint (core)
|
||||
if: ${{ always() }}
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern app/assets/javascripts
|
||||
|
||||
- name: ESLint (core plugins)
|
||||
if: ${{ always() }}
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern plugins/**/{test,assets}/javascripts
|
||||
|
||||
- name: Prettier
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
yarn prettier -v
|
||||
yarn prettier --list-different \
|
||||
"app/assets/stylesheets/**/*.scss" \
|
||||
"app/assets/javascripts/**/*.{js,es6}" \
|
||||
"plugins/**/assets/stylesheets/**/*.scss" \
|
||||
"plugins/**/assets/javascripts/**/*.{js,es6}"
|
||||
|
||||
- name: Ember template lint
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
yarn ember-template-lint \
|
||||
app/assets/javascripts \
|
||||
plugins/**/assets/javascripts
|
||||
|
||||
- name: English locale lint (core)
|
||||
if: ${{ always() }}
|
||||
run: bundle exec ruby script/i18n_lint.rb "config/**/locales/{client,server}.en.yml"
|
||||
|
||||
- name: English locale lint (core plugins)
|
||||
if: ${{ always() }}
|
||||
run: bundle exec ruby script/i18n_lint.rb "plugins/**/locales/{client,server}.en.yml"
|
||||
133
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.target }} ${{ matrix.build_type }}
|
||||
runs-on: ubuntu-latest
|
||||
container: discourse/discourse_test:release
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
DISCOURSE_HOSTNAME: www.example.com
|
||||
RUBY_GLOBAL_METHOD_CACHE_SIZE: 131072
|
||||
RAILS_ENV: test
|
||||
PGHOST: postgres
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
build_type: [backend, frontend]
|
||||
target: [core, plugins]
|
||||
postgres: ["13"]
|
||||
redis: ["6.x"]
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:${{ matrix.postgres }}
|
||||
ports:
|
||||
- 5432:5432
|
||||
env:
|
||||
POSTGRES_USER: discourse
|
||||
POSTGRES_PASSWORD: discourse
|
||||
POSTGRES_DB: discourse_test
|
||||
options: >-
|
||||
--mount type=tmpfs,destination=/var/lib/postgresql/data
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Setup redis
|
||||
uses: shogo82148/actions-setup-redis@v1
|
||||
with:
|
||||
redis-version: ${{ matrix.redis }}
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: |
|
||||
bundle config --local path vendor/bundle
|
||||
bundle config --local deployment true
|
||||
bundle config --local without development
|
||||
bundle install --jobs 4
|
||||
bundle clean
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install
|
||||
|
||||
- name: Checkout official plugins
|
||||
if: matrix.target == 'plugins'
|
||||
run: bin/rake plugin:install_all_official
|
||||
|
||||
- name: Create database
|
||||
run: |
|
||||
bin/rake db:create
|
||||
bin/rake db:migrate
|
||||
|
||||
- name: Create parallel databases
|
||||
if: matrix.build_type == 'backend' && matrix.target == 'core'
|
||||
run: |
|
||||
bin/rake parallel:create
|
||||
bin/rake parallel:migrate
|
||||
|
||||
- name: Core RSpec
|
||||
if: matrix.build_type == 'backend' && matrix.target == 'core'
|
||||
run: bin/turbo_rspec
|
||||
|
||||
- name: Plugin RSpec
|
||||
if: matrix.build_type == 'backend' && matrix.target == 'plugins'
|
||||
run: bin/rake plugin:spec
|
||||
|
||||
- name: Core QUnit
|
||||
if: matrix.build_type == 'frontend' && matrix.target == 'core'
|
||||
run: bin/rake qunit:test['1200000']
|
||||
timeout-minutes: 30
|
||||
|
||||
- name: Wizard QUnit
|
||||
if: matrix.build_type == 'frontend' && matrix.target == 'core'
|
||||
run: bin/rake qunit:test['600000','/wizard/qunit']
|
||||
timeout-minutes: 10
|
||||
|
||||
- name: Plugin QUnit
|
||||
if: matrix.build_type == 'frontend' && matrix.target == 'plugins'
|
||||
run: bin/rake plugin:qunit['*','1200000']
|
||||
timeout-minutes: 30
|
||||
157
.gitignore
vendored
@ -1,33 +1,26 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
#
|
||||
# If you find yourself ignoring temporary files generated by your text editor
|
||||
# or operating system, you probably want to add a global ignore instead:
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
/copyright
|
||||
/coverage
|
||||
/data
|
||||
/log
|
||||
/tmp
|
||||
|
||||
.DS_Store
|
||||
._.DS_Store
|
||||
dump.rdb
|
||||
/.env
|
||||
/.procfile
|
||||
/dump.rdb
|
||||
|
||||
bin/*
|
||||
/config/discourse.conf
|
||||
/config/discourse.pill
|
||||
/config/multisite.yml
|
||||
# `discourse_dev` gem
|
||||
/config/dev.yml
|
||||
|
||||
data/
|
||||
|
||||
.sass-cache/*
|
||||
public/csv/*
|
||||
public/plugins/*
|
||||
public/tombstone/*
|
||||
|
||||
# Ignore bundler config
|
||||
/.bundle
|
||||
/cache
|
||||
/coverage/*
|
||||
|
||||
/public/assets/*
|
||||
/public/tombstone/*
|
||||
/bundle/*
|
||||
|
||||
config/discourse.pill
|
||||
config/discourse.conf
|
||||
/public/assets
|
||||
/public/backups
|
||||
/public/csv
|
||||
/public/fonts
|
||||
/public/plugins
|
||||
/public/tombstone
|
||||
/public/uploads
|
||||
|
||||
# Ignore the default SQLite database and db dumps
|
||||
*.sql
|
||||
@ -36,117 +29,31 @@ config/discourse.conf
|
||||
/db/*.sqlite3
|
||||
/db/structure.sql
|
||||
/db/schema.rb
|
||||
/db/schema_cache.yml
|
||||
|
||||
# Ignore all logfiles and tempfiles.
|
||||
/log/*.log
|
||||
/tmp
|
||||
/logfile
|
||||
log/
|
||||
bootsnap-load-path-cache
|
||||
bootsnap-compile-cache/
|
||||
|
||||
# Ignore plugins except for the bundled ones.
|
||||
# Plugins except for the bundled ones
|
||||
/plugins/*
|
||||
!/plugins/lazy-yt/
|
||||
!/plugins/poll/
|
||||
!/plugins/discourse-details/
|
||||
!/plugins/discourse-nginx-performance-report
|
||||
!/plugins/discourse-local-dates
|
||||
!/plugins/discourse-narrative-bot
|
||||
!/plugins/discourse-presence
|
||||
!/plugins/lazy-yt/
|
||||
!/plugins/poll/
|
||||
!/plugins/styleguide
|
||||
!/plugins/discourse-local-dates
|
||||
/plugins/*/auto_generated/
|
||||
|
||||
/spec/fixtures/plugins/my_plugin/auto_generated
|
||||
|
||||
# Ignore Eclipse .project file
|
||||
/.project
|
||||
|
||||
# Ignore Eclipse .buildpath file
|
||||
/.buildpath
|
||||
|
||||
# Ignore byebug history
|
||||
/.byebug_history
|
||||
|
||||
# Ignore RubyMine settings
|
||||
/.idea
|
||||
|
||||
# Ignore gem that is copied in
|
||||
MiniProfiler/Ruby/rack-mini-profiler-2.0.1a.gem
|
||||
|
||||
discourse.sublime-workspace
|
||||
|
||||
# Vim temp files
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.swm
|
||||
|
||||
# don't check in multisite config
|
||||
config/multisite.yml
|
||||
# don't check in my renamed multisite config as well :)
|
||||
config/multisite1.yml
|
||||
config/fog_credentials.yml
|
||||
|
||||
/public/fonts
|
||||
/public/uploads
|
||||
/public/backups
|
||||
/public/stylesheet-cache/*
|
||||
|
||||
# Scripts used for downloading/refreshing db
|
||||
script/download_db
|
||||
script/refresh_db
|
||||
|
||||
# .procfile
|
||||
.procfile
|
||||
|
||||
# .env, local environment variables for use with foreman
|
||||
.env
|
||||
|
||||
# exclude our git version file for now
|
||||
config/version.rb
|
||||
|
||||
# ignore the Ruby Version manager (rvm)
|
||||
.rvmrc
|
||||
.ruby-version
|
||||
.ruby-gemset
|
||||
.rbenv
|
||||
bundler_stubs/*
|
||||
|
||||
vendor/bundle/*
|
||||
*.db
|
||||
|
||||
# ignore jetbrains ide file
|
||||
*.iml
|
||||
|
||||
# vim swap
|
||||
*.swn
|
||||
|
||||
# ignore nodejs files
|
||||
node_modules
|
||||
/package-lock.json
|
||||
|
||||
/vendor/bundle/*
|
||||
/vendor/data/GeoLite2-City.mmdb
|
||||
|
||||
# Vagrant
|
||||
.vagrant
|
||||
# Front-end
|
||||
dist
|
||||
node_modules
|
||||
yarn-error.log
|
||||
|
||||
# ignore auto-generated plugin js assets
|
||||
# Auto-generated plugin JS assets
|
||||
/app/assets/javascripts/plugins/*
|
||||
|
||||
# ignore generated api documentation files
|
||||
# Generated API documentation files
|
||||
openapi/*
|
||||
|
||||
# ignore VSCode config files
|
||||
.vscode
|
||||
|
||||
# ignore direnv
|
||||
.envrc
|
||||
|
||||
# ember-cli generated
|
||||
dist
|
||||
|
||||
# Copyright Deposits
|
||||
copyright
|
||||
|
||||
yarn-error.log
|
||||
|
||||
@ -6,6 +6,8 @@ config/locales/**/*.yml
|
||||
!config/locales/**/*.en*.yml
|
||||
script/import_scripts/**/*.yml
|
||||
|
||||
app/assets/javascripts/browser-update.js
|
||||
app/assets/javascripts/discourse-loader.js
|
||||
app/assets/javascripts/env.js
|
||||
app/assets/javascripts/main_include_admin.js
|
||||
app/assets/javascripts/vendor.js
|
||||
|
||||
@ -2,12 +2,10 @@ module.exports = {
|
||||
extends: "recommended",
|
||||
ignore: ["**/*.raw"],
|
||||
|
||||
// Pending:
|
||||
// "eol-last": "always",
|
||||
|
||||
rules: {
|
||||
"block-indentation": true,
|
||||
"deprecated-render-helper": true,
|
||||
"eol-last": "always",
|
||||
"linebreak-style": true,
|
||||
"link-rel-noopener": "strict",
|
||||
"no-abstract-roles": true,
|
||||
|
||||
19
.vscode-sample/launch.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Discourse",
|
||||
"type": "Ruby",
|
||||
"request": "launch",
|
||||
"cwd": "/home/discourse/workspace/discourse",
|
||||
// run bundle install before rails server
|
||||
"preLaunchTask": "Prepare discourse",
|
||||
"env": { "DISCOURSE_DEV_HOSTS": "${env:CLOUDENV_ENVIRONMENT_ID}-9292.apps.codespaces.githubusercontent.com", "UNICORN_BIND_ALL": "1", "UNICORN_WORKERS": "4", "DISCOURSE_DEV_ALLOW_ANON_TO_IMPERSONATE": "1" },
|
||||
"program": "bin/unicorn",
|
||||
"args": ["-x"],
|
||||
}
|
||||
]
|
||||
}
|
||||
12
.vscode-sample/tasks.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Prepare discourse",
|
||||
"type": "shell",
|
||||
"command": "cd /home/discourse/workspace/discourse && bundle install && yarn && bin/rake db:migrate"
|
||||
},
|
||||
],
|
||||
}
|
||||
73
Dangerfile
@ -1,73 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
if github.pr_json && (github.pr_json["additions"] || 0) > 250 || (github.pr_json["deletions"] || 0) > 250
|
||||
warn("This pull request is big! We prefer smaller PRs whenever possible, as they are easier to review. Can this be split into a few smaller PRs?")
|
||||
end
|
||||
|
||||
prettier_offenses = `yarn --silent prettier --list-different "app/assets/stylesheets/**/*.scss" "app/assets/javascripts/**/*.js" "app/assets/javascripts/**/*.es6" "test/javascripts/**/*.es6"`.split("\n")
|
||||
|
||||
unless prettier_offenses.empty?
|
||||
fail(%{
|
||||
This PR doesn't match our required code formatting standards, as enforced by prettier.io. <a href='https://meta.discourse.org/t/prettier-code-formatting-tool/93212'>Here's how to set up prettier in your code editor.</a>\n
|
||||
#{prettier_offenses.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
||||
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 [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)
|
||||
.select { |path| !path.start_with?("plugins/") }
|
||||
.select { |path| path.end_with?("es6") || path.end_with?("js") || path.end_with?("rb") }
|
||||
|
||||
js_files = files.select { |path| path.end_with?(".js.es6") || path.end_with?(".js") }
|
||||
js_test_files = js_files.select { |path| path.end_with?("-test.js.es6") }
|
||||
|
||||
super_offenses = []
|
||||
self_offenses = []
|
||||
js_files.each do |path|
|
||||
diff = git.diff_for_file(path)
|
||||
|
||||
next if !diff
|
||||
|
||||
diff.patch.lines.grep(/^\+\s\s/).each do |added_line|
|
||||
super_offenses << path if added_line['this._super()']
|
||||
self_offenses << path if added_line[/(?:(^|\W)self\.?)/]
|
||||
end
|
||||
end
|
||||
|
||||
jquery_find_offenses = []
|
||||
js_test_files.each do |path|
|
||||
diff = git.diff_for_file(path)
|
||||
|
||||
next if !diff
|
||||
|
||||
diff.patch.lines.grep(/^\+\s\s/).each do |added_line|
|
||||
jquery_find_offenses << path if added_line['this.$(']
|
||||
end
|
||||
end
|
||||
|
||||
if !self_offenses.empty?
|
||||
warn(%{
|
||||
Use fat arrow instead of self pattern.\n
|
||||
#{self_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
||||
if !super_offenses.empty?
|
||||
warn(%{
|
||||
When possible use `this._super(...arguments)` instead of `this._super()`\n
|
||||
#{super_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
|
||||
if !jquery_find_offenses.empty?
|
||||
warn(%{
|
||||
Use `find()` instead of `this.$` in js tests`\n
|
||||
#{jquery_find_offenses.uniq.map { |o| github.html_link(o) }.join("\n")}
|
||||
})
|
||||
end
|
||||
20
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.7'
|
||||
gem 'actionpack', '6.0.3.7'
|
||||
gem 'actionview', '6.0.3.7'
|
||||
gem 'activemodel', '6.0.3.7'
|
||||
gem 'activerecord', '6.0.3.7'
|
||||
gem 'activesupport', '6.0.3.7'
|
||||
gem 'railties', '6.0.3.7'
|
||||
gem 'actionmailer', '6.1.3.2'
|
||||
gem 'actionpack', '6.1.3.2'
|
||||
gem 'actionview', '6.1.3.2'
|
||||
gem 'activemodel', '6.1.3.2'
|
||||
gem 'activerecord', '6.1.3.2'
|
||||
gem 'activesupport', '6.1.3.2'
|
||||
gem 'railties', '6.1.3.2'
|
||||
gem 'sprockets-rails'
|
||||
end
|
||||
|
||||
@ -40,7 +40,7 @@ gem 'actionview_precompiler', require: false
|
||||
|
||||
gem 'seed-fu'
|
||||
|
||||
gem 'mail', require: false
|
||||
gem 'mail', git: 'https://github.com/discourse/mail.git', require: false
|
||||
gem 'mini_mime'
|
||||
gem 'mini_suffix'
|
||||
|
||||
@ -96,6 +96,7 @@ gem 'discourse_image_optim', require: 'image_optim'
|
||||
gem 'multi_json'
|
||||
gem 'mustache'
|
||||
gem 'nokogiri'
|
||||
gem 'loofah'
|
||||
gem 'css_parser', require: false
|
||||
|
||||
gem 'omniauth'
|
||||
@ -132,6 +133,7 @@ gem 'rack-protection' # security
|
||||
gem 'cbor', require: false
|
||||
gem 'cose', require: false
|
||||
gem 'addressable'
|
||||
gem 'json_schemer'
|
||||
|
||||
# Gems used only for assets and not required in production environments by default.
|
||||
# Allow everywhere for now cause we are allowing asset debugging in production
|
||||
@ -176,6 +178,7 @@ group :development do
|
||||
gem 'binding_of_caller'
|
||||
gem 'yaml-lint'
|
||||
gem 'annotate'
|
||||
gem 'discourse_dev'
|
||||
end
|
||||
|
||||
# this is an optional gem, it provides a high performance replacement
|
||||
@ -192,7 +195,6 @@ gem 'htmlentities', require: false
|
||||
# If you want to amend mini profiler to do the monkey patches in the railties
|
||||
# we are open to it. by deferring require to the initializer we can configure discourse installs without it
|
||||
|
||||
gem 'flamegraph', require: false
|
||||
gem 'rack-mini-profiler', require: ['enable_rails_patches']
|
||||
|
||||
gem 'unicorn', require: false, platform: :ruby
|
||||
|
||||
338
Gemfile.lock
@ -1,21 +1,29 @@
|
||||
GIT
|
||||
remote: https://github.com/discourse/mail.git
|
||||
revision: 5b700fc95ee66378e0cf2559abc73c8bc3062a4b
|
||||
specs:
|
||||
mail (2.8.0.edge)
|
||||
mini_mime (>= 0.1.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (6.0.3.7)
|
||||
actionpack (= 6.0.3.7)
|
||||
actionview (= 6.0.3.7)
|
||||
activejob (= 6.0.3.7)
|
||||
actionmailer (6.1.3.2)
|
||||
actionpack (= 6.1.3.2)
|
||||
actionview (= 6.1.3.2)
|
||||
activejob (= 6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.7)
|
||||
actionview (= 6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
actionpack (6.1.3.2)
|
||||
actionview (= 6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
actionview (6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
@ -24,44 +32,44 @@ GEM
|
||||
actionview (>= 6.0.a)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
activejob (6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
activerecord (6.0.3.7)
|
||||
activemodel (= 6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
activesupport (6.0.3.7)
|
||||
activemodel (6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
activerecord (6.1.3.2)
|
||||
activemodel (= 6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
activesupport (6.1.3.2)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
zeitwerk (~> 2.2, >= 2.2.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
annotate (3.1.1)
|
||||
activerecord (>= 3.2, < 7.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.390.0)
|
||||
aws-sdk-core (3.109.2)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.1.1)
|
||||
aws-partitions (1.432.0)
|
||||
aws-sdk-core (3.112.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (1.42.0)
|
||||
aws-sdk-core (~> 3, >= 3.112.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.83.2)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-s3 (1.90.0)
|
||||
aws-sdk-core (~> 3, >= 3.112.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-sns (1.35.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-sns (1.38.0)
|
||||
aws-sdk-core (~> 3, >= 3.112.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-sigv4 (1.2.3)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
barber (0.12.2)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
@ -70,31 +78,32 @@ GEM
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.8.0)
|
||||
binding_of_caller (1.0.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.5.1)
|
||||
bootsnap (1.7.5)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.0)
|
||||
bullet (6.1.4)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (11.1.3)
|
||||
cbor (0.5.9.6)
|
||||
certified (1.0.0)
|
||||
chunky_png (1.3.14)
|
||||
chunky_png (1.4.0)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.8)
|
||||
connection_pool (2.2.3)
|
||||
connection_pool (2.2.5)
|
||||
cose (1.2.0)
|
||||
cbor (~> 0.5.9)
|
||||
openssl-signature_algorithm (~> 1.0)
|
||||
cppjieba_rb (0.3.3)
|
||||
crack (0.4.4)
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
css_parser (1.7.1)
|
||||
css_parser (1.9.0)
|
||||
addressable
|
||||
debug_inspector (0.0.3)
|
||||
debug_inspector (1.1.0)
|
||||
diff-lcs (1.4.4)
|
||||
diffy (3.4.0)
|
||||
discourse-ember-rails (0.18.6)
|
||||
@ -104,15 +113,19 @@ GEM
|
||||
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-ember-source (3.12.2.3)
|
||||
discourse-fonts (0.0.8)
|
||||
discourse_dev (0.2.1)
|
||||
faker (~> 2.16)
|
||||
discourse_image_optim (0.26.2)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
fspath (~> 3.0)
|
||||
image_size (~> 1.5)
|
||||
in_threads (~> 1.3)
|
||||
progress (~> 3.0, >= 3.0.1)
|
||||
docile (1.3.2)
|
||||
docile (1.4.0)
|
||||
ecma-re-validator (0.3.0)
|
||||
regexp_parser (~> 2.0)
|
||||
email_reply_trimmer (0.1.13)
|
||||
ember-data-source (3.0.2)
|
||||
ember-source (>= 2, < 3.0)
|
||||
@ -121,24 +134,32 @@ GEM
|
||||
sprockets (>= 3.3, < 4.1)
|
||||
ember-source (2.18.2)
|
||||
erubi (1.10.0)
|
||||
excon (0.78.0)
|
||||
execjs (2.7.0)
|
||||
excon (0.81.0)
|
||||
execjs (2.8.1)
|
||||
exifr (1.3.9)
|
||||
fabrication (2.21.1)
|
||||
fabrication (2.22.0)
|
||||
faker (2.17.0)
|
||||
i18n (>= 1.6, < 2)
|
||||
fakeweb (1.3.0)
|
||||
faraday (1.1.0)
|
||||
faraday (1.4.1)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.1.0)
|
||||
fast_blank (1.0.0)
|
||||
fast_xs (0.8.0)
|
||||
fastimage (2.2.0)
|
||||
ffi (1.13.1)
|
||||
flamegraph (0.9.5)
|
||||
fastimage (2.2.3)
|
||||
ffi (1.15.0)
|
||||
fspath (3.1.2)
|
||||
gc_tracer (1.5.1)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
guess_html_encoding (0.0.11)
|
||||
hana (1.3.7)
|
||||
hashdiff (1.0.1)
|
||||
hashie (4.1.0)
|
||||
highline (2.0.3)
|
||||
@ -154,18 +175,23 @@ GEM
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.3.1)
|
||||
json (2.5.1)
|
||||
json-schema (2.8.1)
|
||||
addressable (>= 2.4)
|
||||
jwt (2.2.2)
|
||||
json_schemer (0.2.18)
|
||||
ecma-re-validator (~> 0.3)
|
||||
hana (~> 1.3)
|
||||
regexp_parser (~> 2.0)
|
||||
uri_template (~> 0.7)
|
||||
jwt (2.2.3)
|
||||
kgio (2.11.3)
|
||||
libv8 (8.4.255.0)
|
||||
libv8 (8.4.255.0-universal-darwin-20)
|
||||
libv8 (8.4.255.0-x86_64-darwin-18)
|
||||
libv8 (8.4.255.0-x86_64-darwin-19)
|
||||
libv8 (8.4.255.0-x86_64-darwin-20)
|
||||
libv8 (8.4.255.0-x86_64-linux)
|
||||
listen (3.3.1)
|
||||
libv8-node (15.14.0.1)
|
||||
libv8-node (15.14.0.1-arm64-darwin-20)
|
||||
libv8-node (15.14.0.1-x86_64-darwin-18)
|
||||
libv8-node (15.14.0.1-x86_64-darwin-19)
|
||||
libv8-node (15.14.0.1-x86_64-darwin-20)
|
||||
libv8-node (15.14.0.1-x86_64-linux)
|
||||
listen (3.5.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
lograge (0.11.2)
|
||||
@ -176,37 +202,36 @@ GEM
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.9.4)
|
||||
logster (2.9.6)
|
||||
loofah (2.9.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
lz4-ruby (0.3.3)
|
||||
mail (2.7.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (0.9.14)
|
||||
message_bus (3.3.4)
|
||||
memory_profiler (1.0.0)
|
||||
message_bus (3.3.5)
|
||||
rack (>= 1.1.3)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.1.0)
|
||||
mini_portile2 (2.5.1)
|
||||
mini_racer (0.3.1)
|
||||
libv8 (~> 8.4.255)
|
||||
mini_scheduler (0.12.3)
|
||||
sidekiq
|
||||
mini_sql (0.3)
|
||||
mini_suffix (0.3.0)
|
||||
mini_racer (0.4.0)
|
||||
libv8-node (~> 15.14.0.0)
|
||||
mini_scheduler (0.13.0)
|
||||
sidekiq (>= 4.2.3)
|
||||
mini_sql (1.1.3)
|
||||
mini_suffix (0.3.2)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.14.4)
|
||||
mocha (1.11.2)
|
||||
mock_redis (0.26.0)
|
||||
msgpack (1.3.3)
|
||||
mocha (1.12.0)
|
||||
mock_redis (0.28.0)
|
||||
ruby2_keywords
|
||||
msgpack (1.4.2)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
mustache (1.1.1)
|
||||
nio4r (2.5.4)
|
||||
nio4r (2.5.7)
|
||||
nokogiri (1.11.3)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
racc (~> 1.4)
|
||||
@ -216,16 +241,16 @@ GEM
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.11.3-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
nokogumbo (2.0.2)
|
||||
nokogumbo (2.0.5)
|
||||
nokogiri (~> 1.8, >= 1.8.4)
|
||||
oauth (0.5.4)
|
||||
oauth2 (1.4.4)
|
||||
oauth (0.5.6)
|
||||
oauth2 (1.4.7)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.10.16)
|
||||
oj (3.11.5)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
@ -234,35 +259,38 @@ GEM
|
||||
omniauth-github (1.4.0)
|
||||
omniauth (~> 1.5)
|
||||
omniauth-oauth2 (>= 1.4.0, < 2.0)
|
||||
omniauth-google-oauth2 (0.8.0)
|
||||
omniauth-google-oauth2 (0.8.2)
|
||||
jwt (>= 2.0)
|
||||
omniauth (>= 1.1.1)
|
||||
oauth2 (~> 1.1)
|
||||
omniauth (~> 1.1)
|
||||
omniauth-oauth2 (>= 1.6)
|
||||
omniauth-oauth (1.1.0)
|
||||
omniauth-oauth (1.2.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.7.0)
|
||||
omniauth (>= 1.0, < 3)
|
||||
omniauth-oauth2 (1.7.1)
|
||||
oauth2 (~> 1.4)
|
||||
omniauth (~> 1.9)
|
||||
omniauth (>= 1.9, < 3)
|
||||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
onebox (2.2.1)
|
||||
onebox (2.2.15)
|
||||
addressable (~> 2.7.0)
|
||||
htmlentities (~> 4.3)
|
||||
multi_json (~> 1.11)
|
||||
mustache
|
||||
nokogiri (~> 1.7)
|
||||
sanitize
|
||||
openssl-signature_algorithm (1.0.0)
|
||||
openssl (2.2.0)
|
||||
openssl-signature_algorithm (1.1.1)
|
||||
openssl (~> 2.0)
|
||||
optimist (3.0.1)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.4.0)
|
||||
parallel_tests (3.7.0)
|
||||
parallel
|
||||
parser (2.7.2.0)
|
||||
parser (3.0.1.1)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.2.3)
|
||||
progress (3.5.2)
|
||||
progress (3.6.0)
|
||||
pry (0.13.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
@ -272,12 +300,12 @@ GEM
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.0.4)
|
||||
puma (5.3.1)
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
racc (1.5.2)
|
||||
rack (2.2.3)
|
||||
rack-mini-profiler (2.2.0)
|
||||
rack-mini-profiler (2.3.2)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (2.1.0)
|
||||
rack
|
||||
@ -288,23 +316,23 @@ GEM
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
loofah (~> 2.3)
|
||||
rails_failover (0.6.2)
|
||||
rails_failover (0.7.3)
|
||||
activerecord (~> 6.0)
|
||||
concurrent-ruby
|
||||
railties (~> 6.0)
|
||||
rails_multisite (2.5.0)
|
||||
rails_multisite (3.0.0)
|
||||
activerecord (> 5.0, < 7)
|
||||
railties (> 5.0, < 7)
|
||||
railties (6.0.3.7)
|
||||
actionpack (= 6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
railties (6.1.3.2)
|
||||
actionpack (= 6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
thor (~> 1.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.1)
|
||||
rake (13.0.3)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rbtrace (0.4.14)
|
||||
@ -313,72 +341,72 @@ GEM
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
redis (4.2.5)
|
||||
redis-namespace (1.8.0)
|
||||
redis-namespace (1.8.1)
|
||||
redis (>= 3.0.4)
|
||||
regexp_parser (2.0.0)
|
||||
regexp_parser (2.1.1)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.4)
|
||||
rexml (3.2.5)
|
||||
rinku (2.0.6)
|
||||
rotp (6.2.0)
|
||||
rqrcode (1.1.2)
|
||||
rqrcode (2.0.0)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.2)
|
||||
rqrcode_core (~> 1.0)
|
||||
rqrcode_core (1.0.0)
|
||||
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-core (3.10.1)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.0)
|
||||
rspec-expectations (3.10.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-html-matchers (0.9.4)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a, < 4)
|
||||
rspec-mocks (3.10.0)
|
||||
rspec-mocks (3.10.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-rails (4.0.1)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
railties (>= 4.2)
|
||||
rspec-core (~> 3.9)
|
||||
rspec-expectations (~> 3.9)
|
||||
rspec-mocks (~> 3.9)
|
||||
rspec-support (~> 3.9)
|
||||
rspec-support (3.10.0)
|
||||
rswag-specs (2.3.1)
|
||||
rspec-rails (5.0.1)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rspec-core (~> 3.10)
|
||||
rspec-expectations (~> 3.10)
|
||||
rspec-mocks (~> 3.10)
|
||||
rspec-support (~> 3.10)
|
||||
rspec-support (3.10.2)
|
||||
rswag-specs (2.4.0)
|
||||
activesupport (>= 3.1, < 7.0)
|
||||
json-schema (~> 2.2)
|
||||
railties (>= 3.1, < 7.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (1.4.2)
|
||||
rubocop (1.14.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.5)
|
||||
parser (>= 3.0.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml
|
||||
rubocop-ast (>= 1.1.1)
|
||||
rubocop-ast (>= 1.5.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (1.2.0)
|
||||
parser (>= 2.7.1.5)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.5.0)
|
||||
parser (>= 3.0.1.1)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.0.0)
|
||||
rubocop-rspec (2.3.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-prof (1.4.2)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-prof (1.4.3)
|
||||
ruby-progressbar (1.11.0)
|
||||
ruby-readability (0.7.0)
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
ruby2_keywords (0.0.2)
|
||||
ruby2_keywords (0.0.4)
|
||||
rubyzip (2.3.0)
|
||||
sanitize (5.2.1)
|
||||
sanitize (5.2.3)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.8.0)
|
||||
nokogumbo (~> 2.0)
|
||||
@ -394,18 +422,18 @@ GEM
|
||||
seed-fu (2.3.9)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
shoulda-matchers (4.4.1)
|
||||
shoulda-matchers (4.5.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (6.1.2)
|
||||
sidekiq (6.2.1)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
redis (>= 4.2.0)
|
||||
simplecov (0.20.0)
|
||||
simplecov (0.21.2)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov_json_formatter (0.1.2)
|
||||
simplecov_json_formatter (0.1.3)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
@ -414,24 +442,24 @@ GEM
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.16)
|
||||
test-prof (0.12.2)
|
||||
stackprof (0.2.17)
|
||||
test-prof (1.0.5)
|
||||
thor (1.1.0)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
tzinfo (1.2.9)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (2.0.4)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
unicorn (5.7.0)
|
||||
unicode-display_width (2.0.0)
|
||||
unicorn (6.0.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.13.0)
|
||||
webmock (3.10.0)
|
||||
uniform_notifier (1.14.2)
|
||||
uri_template (0.7.0)
|
||||
webmock (3.12.2)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@ -451,14 +479,14 @@ PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 6.0.3.7)
|
||||
actionpack (= 6.0.3.7)
|
||||
actionview (= 6.0.3.7)
|
||||
actionmailer (= 6.1.3.2)
|
||||
actionpack (= 6.1.3.2)
|
||||
actionview (= 6.1.3.2)
|
||||
actionview_precompiler
|
||||
active_model_serializers (~> 0.8.3)
|
||||
activemodel (= 6.0.3.7)
|
||||
activerecord (= 6.0.3.7)
|
||||
activesupport (= 6.0.3.7)
|
||||
activemodel (= 6.1.3.2)
|
||||
activerecord (= 6.1.3.2)
|
||||
activesupport (= 6.1.3.2)
|
||||
addressable
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
@ -479,6 +507,7 @@ DEPENDENCIES
|
||||
discourse-ember-rails (= 0.18.6)
|
||||
discourse-ember-source (~> 3.12.2)
|
||||
discourse-fonts
|
||||
discourse_dev
|
||||
discourse_image_optim
|
||||
email_reply_trimmer
|
||||
ember-handlebars-template (= 0.8.0)
|
||||
@ -489,20 +518,21 @@ DEPENDENCIES
|
||||
fast_blank
|
||||
fast_xs
|
||||
fastimage
|
||||
flamegraph
|
||||
gc_tracer
|
||||
highline
|
||||
htmlentities
|
||||
http_accept_language
|
||||
json
|
||||
json_schemer
|
||||
listen
|
||||
lograge
|
||||
logstash-event
|
||||
logstash-logger
|
||||
logster
|
||||
loofah
|
||||
lru_redux
|
||||
lz4-ruby
|
||||
mail
|
||||
mail!
|
||||
maxminddb
|
||||
memory_profiler
|
||||
message_bus
|
||||
@ -536,7 +566,7 @@ DEPENDENCIES
|
||||
rack-protection
|
||||
rails_failover
|
||||
rails_multisite
|
||||
railties (= 6.0.3.7)
|
||||
railties (= 6.1.3.2)
|
||||
rake
|
||||
rb-fsevent
|
||||
rbtrace
|
||||
@ -576,4 +606,4 @@ DEPENDENCIES
|
||||
yaml-lint
|
||||
|
||||
BUNDLED WITH
|
||||
2.2.15
|
||||
2.2.16
|
||||
|
||||
@ -35,7 +35,7 @@ To get your environment setup, follow the community setup guide for your operati
|
||||
|
||||
If you're familiar with how Rails works and are comfortable setting up your own environment, you can also try out the [**Discourse Advanced Developer Guide**](docs/DEVELOPER-ADVANCED.md), which is aimed primarily at Ubuntu and macOS environments.
|
||||
|
||||
Before you get started, ensure you have the following minimum versions: [Ruby 2.6+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 10+](https://www.postgresql.org/download/), [Redis 4.0+](https://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
||||
Before you get started, ensure you have the following minimum versions: [Ruby 2.7+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 13+](https://www.postgresql.org/download/), [Redis 6.0+](https://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
||||
|
||||
## Setting up Discourse
|
||||
|
||||
@ -43,6 +43,8 @@ If you want to set up a Discourse forum for production use, see our [**Discourse
|
||||
|
||||
If you're looking for business class hosting, see [discourse.org/buy](https://www.discourse.org/buy/).
|
||||
|
||||
If you're looking for our remote work solution, see [teams.discourse.com](https://teams.discourse.com/).
|
||||
|
||||
## Requirements
|
||||
|
||||
Discourse is built for the *next* 10 years of the Internet, so our requirements are high.
|
||||
@ -94,7 +96,7 @@ The original Discourse code contributors can be found in [**AUTHORS.MD**](docs/A
|
||||
|
||||
## Copyright / License
|
||||
|
||||
Copyright 2014 - 2020 Civilized Discourse Construction Kit, Inc.
|
||||
Copyright 2014 - 2021 Civilized Discourse Construction Kit, Inc.
|
||||
|
||||
Licensed under the GNU General Public License Version 2.0 (or later);
|
||||
you may not use this work except in compliance with the License.
|
||||
|
||||
4
Rakefile
@ -7,7 +7,3 @@
|
||||
require File.expand_path('../config/application', __FILE__)
|
||||
|
||||
Discourse::Application.load_tasks
|
||||
|
||||
# this prevents crashes when migrating a database in production in certain
|
||||
# PostgreSQL configuations when trying to create structure.sql
|
||||
Rake::Task["db:structure:dump"].clear if Rails.env.production?
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 759 B |
|
Before Width: | Height: | Size: 11 KiB |
@ -3,10 +3,10 @@ require_asset("main_include_admin.js")
|
||||
|
||||
DiscoursePluginRegistry.admin_javascripts.each { |js| require_asset(js) }
|
||||
|
||||
DiscoursePluginRegistry.each_globbed_asset(admin: true) do |f, ext|
|
||||
DiscoursePluginRegistry.each_globbed_asset(admin: true) do |f|
|
||||
if File.directory?(f)
|
||||
depend_on(f)
|
||||
elsif f.to_s.end_with?(".#{ext}")
|
||||
else
|
||||
require_asset(f)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
import Component from "@ember/component";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import I18n from "I18n";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { on } from "@ember/object/evented";
|
||||
|
||||
const COLOR_VARS_REGEX = /\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
|
||||
|
||||
export default Component.extend({
|
||||
mode: "css",
|
||||
classNames: ["ace-wrapper"],
|
||||
_editor: null,
|
||||
_skipContentChangeEvent: null,
|
||||
disabled: false,
|
||||
htmlPlaceholder: false,
|
||||
|
||||
@observes("editorId")
|
||||
editorIdChanged() {
|
||||
@ -18,6 +22,10 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
didRender() {
|
||||
this._skipContentChangeEvent = false;
|
||||
},
|
||||
|
||||
@observes("content")
|
||||
contentChanged() {
|
||||
const content = this.content || "";
|
||||
@ -86,6 +94,10 @@ export default Component.extend({
|
||||
loadedAce.config.set("loadWorkerFromBlob", false);
|
||||
loadedAce.config.set("workerPath", getURL("/javascripts/ace")); // Do not use CDN for workers
|
||||
|
||||
if (this.htmlPlaceholder) {
|
||||
this._overridePlaceholder(loadedAce);
|
||||
}
|
||||
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -98,14 +110,28 @@ export default Component.extend({
|
||||
editor.on("change", () => {
|
||||
this._skipContentChangeEvent = true;
|
||||
this.set("content", editor.getSession().getValue());
|
||||
this._skipContentChangeEvent = false;
|
||||
});
|
||||
if (this.attrs.save) {
|
||||
editor.commands.addCommand({
|
||||
name: "save",
|
||||
exec: () => {
|
||||
this.attrs.save();
|
||||
},
|
||||
bindKey: { mac: "cmd-s", win: "ctrl-s" },
|
||||
});
|
||||
}
|
||||
|
||||
editor.on("blur", () => {
|
||||
this.warnSCSSDeprecations();
|
||||
});
|
||||
|
||||
editor.$blockScrolling = Infinity;
|
||||
editor.renderer.setScrollMargin(10, 10);
|
||||
|
||||
this.element.setAttribute("data-editor", editor);
|
||||
this._editor = editor;
|
||||
this.changeDisabledState();
|
||||
this.warnSCSSDeprecations();
|
||||
|
||||
$(window)
|
||||
.off("ace:resize")
|
||||
@ -123,6 +149,38 @@ export default Component.extend({
|
||||
});
|
||||
},
|
||||
|
||||
warnSCSSDeprecations() {
|
||||
if (
|
||||
this.mode !== "scss" ||
|
||||
this.editorId.startsWith("color_definitions") ||
|
||||
!this._editor
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let warnings = this.content
|
||||
.split("\n")
|
||||
.map((line, row) => {
|
||||
if (line.match(COLOR_VARS_REGEX)) {
|
||||
return {
|
||||
row,
|
||||
column: 0,
|
||||
text: I18n.t("admin.customize.theme.scss_warning_inline"),
|
||||
type: "warning",
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
this._editor.getSession().setAnnotations(warnings);
|
||||
|
||||
this.setWarning(
|
||||
warnings.length
|
||||
? I18n.t("admin.customize.theme.scss_color_variables_warning")
|
||||
: false
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
focus() {
|
||||
if (this._editor) {
|
||||
@ -131,4 +189,32 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
_overridePlaceholder(loadedAce) {
|
||||
const originalPlaceholderSetter =
|
||||
loadedAce.config.$defaultOptions.editor.placeholder.set;
|
||||
|
||||
loadedAce.config.$defaultOptions.editor.placeholder.set = function () {
|
||||
if (!this.$updatePlaceholder) {
|
||||
const originalRendererOn = this.renderer.on;
|
||||
this.renderer.on = function () {};
|
||||
originalPlaceholderSetter.call(this, ...arguments);
|
||||
this.renderer.on = originalRendererOn;
|
||||
|
||||
const originalUpdatePlaceholder = this.$updatePlaceholder;
|
||||
|
||||
this.$updatePlaceholder = function () {
|
||||
originalUpdatePlaceholder.call(this, ...arguments);
|
||||
|
||||
if (this.renderer.placeholderNode) {
|
||||
this.renderer.placeholderNode.innerHTML = this.$placeholder || "";
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.on("input", this.$updatePlaceholder);
|
||||
}
|
||||
|
||||
this.$updatePlaceholder();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import I18n from "I18n";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import discourseDebounce from "discourse/lib/debounce";
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["admin-backups-logs"],
|
||||
@ -33,9 +33,7 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
@on("init")
|
||||
@observes("logs.[]")
|
||||
_updateFormattedLogs: discourseDebounce(function () {
|
||||
_updateFormattedLogsFunc: function () {
|
||||
const logs = this.logs;
|
||||
if (logs.length === 0) {
|
||||
return;
|
||||
@ -57,7 +55,13 @@ export default Component.extend({
|
||||
this.renderLogs();
|
||||
|
||||
scheduleOnce("afterRender", this, this._scrollDown);
|
||||
}, 150),
|
||||
},
|
||||
|
||||
@on("init")
|
||||
@observes("logs.[]")
|
||||
_updateFormattedLogs() {
|
||||
discourseDebounce(this, this._updateFormattedLogsFunc, 150);
|
||||
},
|
||||
|
||||
renderLogs() {
|
||||
const formattedLogs = this.formattedLogs;
|
||||
|
||||
@ -10,7 +10,7 @@ export default Component.extend({
|
||||
const model = this.model;
|
||||
const rawData = this.get("model.data");
|
||||
|
||||
var data = {
|
||||
let data = {
|
||||
labels: rawData.map((r) => r.x),
|
||||
datasets: [
|
||||
{
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { debounce, schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import { number } from "discourse/lib/formatter";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { number } from "discourse/lib/formatter";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["admin-report-chart"],
|
||||
@ -14,7 +15,7 @@ export default Component.extend({
|
||||
this._super(...arguments);
|
||||
|
||||
this.resizeHandler = () =>
|
||||
debounce(this, this._scheduleChartRendering, 500);
|
||||
discourseDebounce(this, this._scheduleChartRendering, 500);
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
@ -34,7 +35,7 @@ export default Component.extend({
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
debounce(this, this._scheduleChartRendering, 100);
|
||||
discourseDebounce(this, this._scheduleChartRendering, 100);
|
||||
},
|
||||
|
||||
_scheduleChartRendering() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { match } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { match } from "@ember/object/computed";
|
||||
export default Component.extend({
|
||||
allTime: true,
|
||||
tagName: "tr",
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { debounce, schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import { number } from "discourse/lib/formatter";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { number } from "discourse/lib/formatter";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["admin-report-chart", "admin-report-stacked-chart"],
|
||||
@ -11,7 +12,7 @@ export default Component.extend({
|
||||
this._super(...arguments);
|
||||
|
||||
this.resizeHandler = () =>
|
||||
debounce(this, this._scheduleChartRendering, 500);
|
||||
discourseDebounce(this, this._scheduleChartRendering, 500);
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
@ -31,7 +32,7 @@ export default Component.extend({
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
debounce(this, this._scheduleChartRendering, 100);
|
||||
discourseDebounce(this, this._scheduleChartRendering, 100);
|
||||
},
|
||||
|
||||
_scheduleChartRendering() {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
|
||||
export default Component.extend({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "td",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "th",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Component from "@ember/component";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
|
||||
const PAGES_LIMIT = 8;
|
||||
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
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";
|
||||
import ReportLoader from "discourse/lib/reports-loader";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import EmberObject, { action, computed } from "@ember/object";
|
||||
import Report, { SCHEMA_VERSION } from "admin/models/report";
|
||||
import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import ReportLoader from "discourse/lib/reports-loader";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { next } from "@ember/runloop";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
|
||||
const TABLE_OPTIONS = {
|
||||
perPage: 8,
|
||||
@ -68,6 +68,8 @@ export default Component.extend({
|
||||
showDatesOptions: alias("model.dates_filtering"),
|
||||
showRefresh: or("showDatesOptions", "model.available_filters.length"),
|
||||
shouldDisplayTrend: and("showTrend", "model.prev_period"),
|
||||
endDate: null,
|
||||
startDate: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@ -82,25 +84,21 @@ export default Component.extend({
|
||||
.includes(this.dataSourceName);
|
||||
}),
|
||||
|
||||
startDate: computed("filters.startDate", function () {
|
||||
if (this.filters && isPresent(this.filters.startDate)) {
|
||||
return moment(this.filters.startDate, "YYYY-MM-DD");
|
||||
} else {
|
||||
return moment();
|
||||
}
|
||||
}),
|
||||
|
||||
endDate: computed("filters.endDate", function () {
|
||||
if (this.filters && isPresent(this.filters.endDate)) {
|
||||
return moment(this.filters.endDate, "YYYY-MM-DD");
|
||||
} else {
|
||||
return moment();
|
||||
}
|
||||
}),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
let startDate = moment();
|
||||
if (this.filters && isPresent(this.filters.startDate)) {
|
||||
startDate = moment(this.filters.startDate, "YYYY-MM-DD");
|
||||
}
|
||||
this.set("startDate", startDate);
|
||||
|
||||
let endDate = moment();
|
||||
if (this.filters && isPresent(this.filters.endDate)) {
|
||||
endDate = moment(this.filters.endDate, "YYYY-MM-DD");
|
||||
}
|
||||
this.set("endDate", endDate);
|
||||
|
||||
if (this.report) {
|
||||
this._renderReport(this.report, this.forcedModes, this.currentMode);
|
||||
} else if (this.dataSourceName) {
|
||||
@ -213,7 +211,7 @@ export default Component.extend({
|
||||
|
||||
@action
|
||||
onChangeDateRange(range) {
|
||||
this.send("refreshReport", {
|
||||
this.setProperties({
|
||||
startDate: range.from,
|
||||
endDate: range.to,
|
||||
});
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import I18n from "I18n";
|
||||
import { next } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { next } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
warning: null,
|
||||
|
||||
@discourseComputed("theme.targets", "onlyOverridden", "showAdvanced")
|
||||
visibleTargets(targets, onlyOverridden, showAdvanced) {
|
||||
return targets.filter((target) => {
|
||||
@ -43,9 +46,17 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("currentTargetName", "fieldName")
|
||||
placeholder(targetName, fieldName) {
|
||||
return fieldName && fieldName === "color_definitions"
|
||||
? I18n.t("admin.customize.theme.color_definitions.placeholder")
|
||||
: "";
|
||||
if (fieldName && fieldName === "color_definitions") {
|
||||
const example =
|
||||
":root {\n" +
|
||||
" --mytheme-tertiary-or-quaternary: #{dark-light-choose($tertiary, $quaternary)};\n" +
|
||||
"}";
|
||||
|
||||
return I18n.t("admin.customize.theme.color_definitions.placeholder", {
|
||||
example: isDocumentRTL() ? `<div dir="ltr">${example}</div>` : example,
|
||||
});
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
@discourseComputed("fieldName", "currentTargetName", "theme")
|
||||
@ -111,5 +122,13 @@ export default Component.extend({
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
},
|
||||
|
||||
save() {
|
||||
this.attrs.save();
|
||||
},
|
||||
|
||||
setWarning(message) {
|
||||
this.set("warning", message);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import I18n from "I18n";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
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, i18n } from "discourse/lib/computed";
|
||||
import discourseComputed, {
|
||||
observes,
|
||||
on,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { i18n, propertyEqual } from "discourse/lib/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import UserField from "admin/models/user-field";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
|
||||
export default Component.extend(bufferedProperty("userField"), {
|
||||
editing: empty("userField.id"),
|
||||
@ -44,25 +44,25 @@ export default Component.extend(bufferedProperty("userField"), {
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"userField.editable",
|
||||
"userField.required",
|
||||
"userField.show_on_profile",
|
||||
"userField.show_on_user_card"
|
||||
"userField.{editable,required,show_on_profile,show_on_user_card,searchable}"
|
||||
)
|
||||
flags(editable, required, showOnProfile, showOnUserCard) {
|
||||
flags(userField) {
|
||||
const ret = [];
|
||||
if (editable) {
|
||||
if (userField.editable) {
|
||||
ret.push(I18n.t("admin.user_fields.editable.enabled"));
|
||||
}
|
||||
if (required) {
|
||||
if (userField.required) {
|
||||
ret.push(I18n.t("admin.user_fields.required.enabled"));
|
||||
}
|
||||
if (showOnProfile) {
|
||||
if (userField.showOnProfile) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_profile.enabled"));
|
||||
}
|
||||
if (showOnUserCard) {
|
||||
if (userField.showOnUserCard) {
|
||||
ret.push(I18n.t("admin.user_fields.show_on_user_card.enabled"));
|
||||
}
|
||||
if (userField.searchable) {
|
||||
ret.push(I18n.t("admin.user_fields.searchable.enabled"));
|
||||
}
|
||||
|
||||
return ret.join(", ");
|
||||
},
|
||||
@ -78,6 +78,7 @@ export default Component.extend(bufferedProperty("userField"), {
|
||||
"required",
|
||||
"show_on_profile",
|
||||
"show_on_user_card",
|
||||
"searchable",
|
||||
"options"
|
||||
);
|
||||
|
||||
|
||||
@ -1,17 +1,9 @@
|
||||
import I18n from "I18n";
|
||||
import Component from "@ember/component";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["watched-word"],
|
||||
watchedWord: null,
|
||||
xIcon: iconHTML("times").htmlSafe(),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("watchedWord", this.get("word.word"));
|
||||
},
|
||||
|
||||
click() {
|
||||
this.word
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["hook-event"],
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
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 Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "li",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default Component.extend({
|
||||
|
||||
@ -2,11 +2,13 @@ import Component from "@ember/component";
|
||||
export default Component.extend({
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
$("body").addClass("admin-interface");
|
||||
document.querySelector("html").classList.add("admin-area");
|
||||
document.querySelector("body").classList.add("admin-interface");
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
$("body").removeClass("admin-interface");
|
||||
document.querySelector("html").classList.remove("admin-area");
|
||||
document.querySelector("body").classList.remove("admin-interface");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import { computed, action } from "@ember/object";
|
||||
import { action, computed } from "@ember/object";
|
||||
import loadScript, { loadCSS } from "discourse/lib/load-script";
|
||||
import Component from "@ember/component";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
/**
|
||||
An input field for a color.
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import Component from "@ember/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default Component.extend({
|
||||
newFeatures: null,
|
||||
classNames: ["section", "dashboard-new-features"],
|
||||
classNameBindings: ["hasUnseenFeatures:ordered-first"],
|
||||
releaseNotesLink: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
ajax("/admin/dashboard/new-features.json").then((json) => {
|
||||
this.setProperties({
|
||||
newFeatures: json.new_features,
|
||||
hasUnseenFeatures: json.has_unseen_features,
|
||||
releaseNotesLink: json.release_notes_link,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
columnCountClass: computed("newFeatures", function () {
|
||||
return this.newFeatures.length > 2 ? "three-or-more-items" : "";
|
||||
}),
|
||||
|
||||
@action
|
||||
dismissNewFeatures() {
|
||||
ajax("/admin/dashboard/mark-new-features-as-seen.json", {
|
||||
type: "PUT",
|
||||
}).then(() => this.set("hasUnseenFeatures", false));
|
||||
},
|
||||
});
|
||||
@ -1,8 +1,8 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
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"),
|
||||
@ -50,5 +50,8 @@ export default Component.extend({
|
||||
}
|
||||
);
|
||||
},
|
||||
save() {
|
||||
this.attrs.save();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
import Category from "discourse/models/category";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed, {
|
||||
on,
|
||||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import bootbox from "bootbox";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import discourseComputed 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 { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import Category from "discourse/models/category";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend(bufferedProperty("host"), {
|
||||
editToggled: false,
|
||||
@ -19,14 +15,6 @@ export default Component.extend(bufferedProperty("host"), {
|
||||
|
||||
editing: or("host.isNew", "editToggled"),
|
||||
|
||||
@on("didInsertElement")
|
||||
@observes("editing")
|
||||
_focusOnInput() {
|
||||
schedule("afterRender", () => {
|
||||
this.element.querySelector(".host-name").focus();
|
||||
});
|
||||
},
|
||||
|
||||
@discourseComputed("buffered.host", "host.isSaving")
|
||||
cantSave(host, isSaving) {
|
||||
return isSaving || isEmpty(host);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["embed-setting"],
|
||||
|
||||
@ -0,0 +1,168 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { emojiUrlFor } from "discourse/lib/text";
|
||||
import { action, set, setProperties } from "@ember/object";
|
||||
import { later, schedule } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":value-list", ":emoji-list"],
|
||||
values: null,
|
||||
validationMessage: null,
|
||||
emojiPickerIsActive: false,
|
||||
isEditorFocused: false,
|
||||
|
||||
@discourseComputed("values")
|
||||
collection(values) {
|
||||
values = values || "";
|
||||
|
||||
return values
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.map((value) => {
|
||||
return {
|
||||
isEditable: true,
|
||||
isEditing: false,
|
||||
value,
|
||||
emojiUrl: emojiUrlFor(value),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
closeEmojiPicker() {
|
||||
this.collection.setEach("isEditing", false);
|
||||
this.set("emojiPickerIsActive", false);
|
||||
this.set("isEditorFocused", false);
|
||||
},
|
||||
|
||||
@action
|
||||
emojiSelected(code) {
|
||||
if (!this._validateInput(code)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.collection.findBy("isEditing");
|
||||
if (item) {
|
||||
setProperties(item, {
|
||||
value: code,
|
||||
emojiUrl: emojiUrlFor(code),
|
||||
isEditing: false,
|
||||
});
|
||||
|
||||
this._saveValues();
|
||||
} else {
|
||||
const newCollectionValue = {
|
||||
value: code,
|
||||
emojiUrl: emojiUrlFor(code),
|
||||
isEditable: true,
|
||||
isEditing: false,
|
||||
};
|
||||
this.collection.addObject(newCollectionValue);
|
||||
this._saveValues();
|
||||
}
|
||||
|
||||
this.set("emojiPickerIsActive", false);
|
||||
this.set("isEditorFocused", false);
|
||||
},
|
||||
|
||||
@discourseComputed("collection")
|
||||
showUpDownButtons(collection) {
|
||||
return collection.length - 1 ? true : false;
|
||||
},
|
||||
|
||||
_splitValues(values) {
|
||||
if (values && values.length) {
|
||||
const emojiList = [];
|
||||
const emojis = values.split("|").filter(Boolean);
|
||||
emojis.forEach((emojiName) => {
|
||||
const emoji = {
|
||||
isEditable: true,
|
||||
isEditing: false,
|
||||
};
|
||||
emoji.value = emojiName;
|
||||
emoji.emojiUrl = emojiUrlFor(emojiName);
|
||||
|
||||
emojiList.push(emoji);
|
||||
});
|
||||
|
||||
return emojiList;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
editValue(index) {
|
||||
this.closeEmojiPicker();
|
||||
schedule("afterRender", () => {
|
||||
if (parseInt(index, 10) >= 0) {
|
||||
const item = this.collection[index];
|
||||
if (item.isEditable) {
|
||||
set(item, "isEditing", true);
|
||||
}
|
||||
}
|
||||
|
||||
this.set("isEditorFocused", true);
|
||||
later(() => {
|
||||
if (this.element && !this.isDestroying && !this.isDestroyed) {
|
||||
this.set("emojiPickerIsActive", true);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
removeValue(value) {
|
||||
this._removeValue(value);
|
||||
},
|
||||
|
||||
@action
|
||||
shift(operation, index) {
|
||||
let futureIndex = index + operation;
|
||||
|
||||
if (futureIndex > this.collection.length - 1) {
|
||||
futureIndex = 0;
|
||||
} else if (futureIndex < 0) {
|
||||
futureIndex = this.collection.length - 1;
|
||||
}
|
||||
|
||||
const shiftedEmoji = this.collection[index];
|
||||
this.collection.removeAt(index);
|
||||
this.collection.insertAt(futureIndex, shiftedEmoji);
|
||||
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_validateInput(input) {
|
||||
this.set("validationMessage", null);
|
||||
|
||||
if (!emojiUrlFor(input)) {
|
||||
this.set(
|
||||
"validationMessage",
|
||||
I18n.t("admin.site_settings.emoji_list.invalid_input")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeValue(value) {
|
||||
this.collection.removeObject(value);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_replaceValue(index, newValue) {
|
||||
const item = this.collection[index];
|
||||
if (item.value === newValue) {
|
||||
return;
|
||||
}
|
||||
set(item, "value", newValue);
|
||||
this._saveValues();
|
||||
},
|
||||
|
||||
_saveValues() {
|
||||
this.set("values", this.collection.mapBy("value").join("|"));
|
||||
},
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { on, observes } from "discourse-common/utils/decorators";
|
||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
|
||||
export default Component.extend({
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import I18n from "I18n";
|
||||
import EmberObject from "@ember/object";
|
||||
import { later } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
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 Component from "@ember/component";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import bootbox from "bootbox";
|
||||
import copyText from "discourse/lib/copy-text";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { later } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["ip-lookup"],
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed, {
|
||||
afterRender,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { equal } from "@ember/object/computed";
|
||||
|
||||
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import I18n from "I18n";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import I18n from "I18n";
|
||||
import Permalink from "admin/models/permalink";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["permalink-form"],
|
||||
@ -69,9 +69,13 @@ export default Component.extend({
|
||||
this.set("formSubmitted", false);
|
||||
|
||||
let error;
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
if (
|
||||
e.jqXHR &&
|
||||
e.jqXHR.responseJSON &&
|
||||
e.jqXHR.responseJSON.errors
|
||||
) {
|
||||
error = I18n.t("generic_error_with_reason", {
|
||||
error: e.responseJSON.errors.join(". "),
|
||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||
});
|
||||
} else {
|
||||
error = I18n.t("generic_error");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { action } from "@ember/object";
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
checked: false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
import { action } from "@ember/object";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
category: readOnly("filter.default"),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { computed } from "@ember/object";
|
||||
import FilterComponent from "admin/components/report-filters/filter";
|
||||
import { computed } from "@ember/object";
|
||||
|
||||
export default FilterComponent.extend({
|
||||
classNames: ["group-filter"],
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import { later, schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
|
||||
/*global Resumable:true */
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import bootbox from "bootbox";
|
||||
import I18n from "I18n";
|
||||
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
||||
import bootbox from "bootbox";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
/**
|
||||
A form to create an IP address that will be blocked or allowed.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import Component from "@ember/component";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
import { set } from "@ember/object";
|
||||
|
||||
@ -94,9 +94,9 @@ export default Component.extend({
|
||||
_splitValues(values, delimiter) {
|
||||
if (values && values.length) {
|
||||
const keys = ["key", "secret"];
|
||||
var res = [];
|
||||
let res = [];
|
||||
values.split(delimiter).forEach(function (str) {
|
||||
var object = {};
|
||||
let object = {};
|
||||
str.split("|").forEach(function (a, i) {
|
||||
object[keys[i]] = a;
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { empty } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Component from "@ember/component";
|
||||
import BufferedContent from "discourse/mixins/buffered-content";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
import Component from "@ember/component";
|
||||
import SettingComponent from "admin/mixins/setting-component";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
|
||||
export default Component.extend(BufferedContent, SettingComponent, {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
@discourseComputed("value")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Component from "@ember/component";
|
||||
import Category from "discourse/models/category";
|
||||
import Component from "@ember/component";
|
||||
import { computed } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { action, computed } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import { computed, action } from "@ember/object";
|
||||
|
||||
function RGBToHex(rgb) {
|
||||
// Choose correct separator
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { computed } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import { computed } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
tokenSeparator: "|",
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
import { action } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Component.extend({
|
||||
@action
|
||||
launchJsonEditorModal() {
|
||||
const schemaModal = showModal("json-schema-editor", {
|
||||
model: {
|
||||
value: this.value,
|
||||
settingName: this.setting.setting,
|
||||
jsonSchema: this.setting.json_schema,
|
||||
},
|
||||
});
|
||||
|
||||
schemaModal.set("onClose", () => {
|
||||
this.set("value", schemaModal.model.value);
|
||||
});
|
||||
},
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
@discourseComputed("value")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Component from "@ember/component";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
import highlightHTML from "discourse/lib/highlight-html";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["site-text"],
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { equal } from "@ember/object/computed";
|
||||
|
||||
const CUSTOM_REASON_KEY = "custom";
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import UploadMixin from "discourse/mixins/upload";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend(UploadMixin, {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Component from "@ember/component";
|
||||
import BufferedContent from "discourse/mixins/buffered-content";
|
||||
import Component from "@ember/component";
|
||||
import SettingComponent from "admin/mixins/setting-component";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { url } from "discourse/lib/computed";
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Component from "@ember/component";
|
||||
import BufferedContent from "discourse/mixins/buffered-content";
|
||||
import Component from "@ember/component";
|
||||
import SettingComponent from "admin/mixins/setting-component";
|
||||
|
||||
export default Component.extend(BufferedContent, SettingComponent, {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import BufferedContent from "discourse/mixins/buffered-content";
|
||||
import Component from "@ember/component";
|
||||
import SettingComponent from "admin/mixins/setting-component";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default Component.extend(BufferedContent, SettingComponent, {
|
||||
layoutName: "admin/templates/components/site-setting",
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { gt, and } from "@ember/object/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import Component from "@ember/component";
|
||||
import { and, gt } from "@ember/object/computed";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import Component from "@ember/component";
|
||||
import { escape } from "pretty-text/sanitizer";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
const MAX_COMPONENTS = 4;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { gt, equal } from "@ember/object/computed";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import { equal, gt } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { THEMES, COMPONENTS } from "admin/models/theme";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { empty, reads } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":value-list"],
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import I18n from "I18n";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import discourseComputed, {
|
||||
observes,
|
||||
on,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import WatchedWord from "admin/models/watched-word";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed, {
|
||||
on,
|
||||
observes,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { schedule } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["watched-word-form"],
|
||||
@ -15,6 +16,9 @@ export default Component.extend({
|
||||
actionKey: null,
|
||||
showMessage: false,
|
||||
|
||||
canReplace: equal("actionKey", "replace"),
|
||||
canTag: equal("actionKey", "tag"),
|
||||
|
||||
@discourseComputed("regularExpressions")
|
||||
placeholderKey(regularExpressions) {
|
||||
return (
|
||||
@ -56,6 +60,7 @@ export default Component.extend({
|
||||
|
||||
const watchedWord = WatchedWord.create({
|
||||
word: this.word,
|
||||
replacement: this.canReplace || this.canTag ? this.replacement : null,
|
||||
action: this.actionKey,
|
||||
});
|
||||
|
||||
@ -64,6 +69,7 @@ export default Component.extend({
|
||||
.then((result) => {
|
||||
this.setProperties({
|
||||
word: "",
|
||||
replacement: "",
|
||||
formSubmitted: false,
|
||||
showMessage: true,
|
||||
message: I18n.t("admin.watched_words.form.success"),
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import UploadMixin from "discourse/mixins/upload";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend(UploadMixin, {
|
||||
type: "txt",
|
||||
classNames: "watched-words-uploader",
|
||||
uploadUrl: "/admin/logs/watched_words/upload",
|
||||
uploadUrl: "/admin/customize/watched_words/upload",
|
||||
addDisabled: alias("uploading"),
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import Controller from "@ember/controller";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend({
|
||||
actions: {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import I18n from "I18n";
|
||||
import { isBlank } from "@ember/utils";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isBlank } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { get } from "@ember/object";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Controller.extend({
|
||||
@ -30,6 +31,10 @@ export default Controller.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
updateUsername(selected) {
|
||||
this.set("model.username", get(selected, "firstObject"));
|
||||
},
|
||||
|
||||
changeUserMode(value) {
|
||||
if (value === "all") {
|
||||
this.model.set("username", null);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import Controller from "@ember/controller";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Controller.extend(bufferedProperty("model"), {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import I18n from "I18n";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import { i18n, setting } from "discourse/lib/computed";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { setting, i18n } from "discourse/lib/computed";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend({
|
||||
adminBackups: controller(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
adminBackups: controller(),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { not, and } from "@ember/object/computed";
|
||||
import { and, not } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
export default Controller.extend({
|
||||
noOperationIsRunning: not("model.isOperationRunning"),
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import I18n from "I18n";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import bootbox from "bootbox";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend({
|
||||
saving: false,
|
||||
|
||||
@ -1,23 +1,31 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { reads } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { propertyNotEqual } from "discourse/lib/computed";
|
||||
import { run } from "@ember/runloop";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { propertyNotEqual } from "discourse/lib/computed";
|
||||
import { equal, reads } from "@ember/object/computed";
|
||||
import { run } from "@ember/runloop";
|
||||
import { action } from "@ember/object";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
const IMAGE = "image";
|
||||
const ICON = "icon";
|
||||
|
||||
export default Controller.extend(bufferedProperty("model"), {
|
||||
adminBadges: controller(),
|
||||
saving: false,
|
||||
savingStatus: "",
|
||||
selectedGraphicType: null,
|
||||
badgeTypes: reads("adminBadges.badgeTypes"),
|
||||
badgeGroupings: reads("adminBadges.badgeGroupings"),
|
||||
badgeTriggers: reads("adminBadges.badgeTriggers"),
|
||||
protectedSystemFields: reads("adminBadges.protectedSystemFields"),
|
||||
readOnly: reads("buffered.system"),
|
||||
showDisplayName: propertyNotEqual("name", "displayName"),
|
||||
iconSelectorSelected: equal("selectedGraphicType", ICON),
|
||||
imageUploaderSelected: equal("selectedGraphicType", IMAGE),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@ -56,12 +64,52 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
return modelQuery && modelQuery.trim().length > 0;
|
||||
},
|
||||
|
||||
@discourseComputed("model.i18n_name")
|
||||
textCustomizationPrefix(i18n_name) {
|
||||
return `badges.${i18n_name}.`;
|
||||
},
|
||||
|
||||
@observes("model.id")
|
||||
_resetSaving: function () {
|
||||
this.set("saving", false);
|
||||
this.set("savingStatus", "");
|
||||
},
|
||||
|
||||
showIconSelector() {
|
||||
this.set("selectedGraphicType", ICON);
|
||||
},
|
||||
|
||||
showImageUploader() {
|
||||
this.set("selectedGraphicType", IMAGE);
|
||||
},
|
||||
|
||||
@action
|
||||
changeGraphicType(newType) {
|
||||
if (newType === IMAGE) {
|
||||
this.showImageUploader();
|
||||
} else if (newType === ICON) {
|
||||
this.showIconSelector();
|
||||
} else {
|
||||
throw new Error(`Unknown badge graphic type "${newType}"`);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
setImage(upload) {
|
||||
this.buffered.setProperties({
|
||||
image_upload_id: upload.id,
|
||||
image_url: getURL(upload.url),
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
removeImage() {
|
||||
this.buffered.setProperties({
|
||||
image_upload_id: null,
|
||||
image_url: null,
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
if (!this.saving) {
|
||||
@ -77,7 +125,7 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
"description",
|
||||
"long_description",
|
||||
"icon",
|
||||
"image",
|
||||
"image_upload_id",
|
||||
"query",
|
||||
"badge_grouping_id",
|
||||
"trigger",
|
||||
@ -105,7 +153,7 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
const data = {};
|
||||
const buffered = this.buffered;
|
||||
fields.forEach(function (field) {
|
||||
var d = buffered.get(field);
|
||||
let d = buffered.get(field);
|
||||
if (boolFields.includes(field)) {
|
||||
d = !!d;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { inject as service } from "@ember/service";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Controller.extend({
|
||||
routing: service("-routing"),
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { later } from "@ember/runloop";
|
||||
import Controller from "@ember/controller";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed("model.colors", "onlyOverridden")
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import I18n from "I18n";
|
||||
import EmberObject from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed("model.@each.id")
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend({
|
||||
@discourseComputed("model.isSaving")
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import I18n from "I18n";
|
||||
import { action } from "@ember/object";
|
||||
import bootbox from "bootbox";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend(bufferedProperty("emailTemplate"), {
|
||||
adminCustomizeEmailTemplates: controller(),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { sort } from "@ember/object/computed";
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { sort } from "@ember/object/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
sortedTemplates: sort("emailTemplates", "titleSorting"),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { not } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { not } from "@ember/object/computed";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
|
||||
export default Controller.extend(bufferedProperty("model"), {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import I18n from "I18n";
|
||||
import Controller from "@ember/controller";
|
||||
import { url } from "discourse/lib/computed";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { url } from "discourse/lib/computed";
|
||||
|
||||
export default Controller.extend({
|
||||
section: null,
|
||||
@ -64,5 +64,9 @@ export default Controller.extend({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
this.replaceRoute(this.showRouteName, this.model.id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import I18n from "I18n";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import {
|
||||
empty,
|
||||
filterBy,
|
||||
match,
|
||||
mapBy,
|
||||
match,
|
||||
notEmpty,
|
||||
} from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import ThemeSettings from "admin/models/theme-settings";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { url } from "discourse/lib/computed";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import ThemeSettings from "admin/models/theme-settings";
|
||||
import { THEMES, COMPONENTS } from "admin/models/theme";
|
||||
import EmberObject from "@ember/object";
|
||||
import bootbox from "bootbox";
|
||||
import { url } from "discourse/lib/computed";
|
||||
|
||||
const THEME_UPLOAD_VAR = 2;
|
||||
|
||||
@ -231,6 +231,11 @@ export default Controller.extend({
|
||||
: remoteThemeUrl;
|
||||
},
|
||||
|
||||
@discourseComputed("model.user.id", "model.default")
|
||||
showConvert(userId, defaultTheme) {
|
||||
return userId > 0 && !defaultTheme;
|
||||
},
|
||||
|
||||
actions: {
|
||||
updateToLatest() {
|
||||
this.set("updatingRemote", true);
|
||||
@ -369,25 +374,29 @@ export default Controller.extend({
|
||||
|
||||
switchType() {
|
||||
const relatives = this.get("model.component")
|
||||
? this.parentThemes
|
||||
? this.get("model.parentThemes")
|
||||
: this.get("model.childThemes");
|
||||
|
||||
let message = I18n.t(`${this.convertKey}_alert_generic`);
|
||||
|
||||
if (relatives && relatives.length > 0) {
|
||||
const names = relatives.map((relative) => relative.get("name"));
|
||||
bootbox.confirm(
|
||||
I18n.t(`${this.convertKey}_alert`, {
|
||||
relatives: names.join(", "),
|
||||
}),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.commitSwitchType();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.commitSwitchType();
|
||||
message = I18n.t(`${this.convertKey}_alert`, {
|
||||
relatives: relatives
|
||||
.map((relative) => relative.get("name"))
|
||||
.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
bootbox.confirm(
|
||||
message,
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(result) => {
|
||||
if (result) {
|
||||
this.commitSwitchType();
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
enableComponent() {
|
||||
|
||||