mirror of
https://github.com/discourse/discourse.git
synced 2025-04-20 18:19:04 +08:00
Compare commits
No commits in common. "main" and "beta" have entirely different histories.
@ -76,5 +76,3 @@ cb932d6ee1b3b3571e4d4d9118635e2dbf58f0ef
|
||||
1d0d7ddbb5ce5dae9bdbdab3797628b6565fb4c4
|
||||
a017f566a84af2e74c132c4acc89028d5f779a29
|
||||
b29e0b6e1b6001890ce92f96448258550f80132b
|
||||
999ae73c7836ff20a9537e582d52b861355f1ec5
|
||||
7b2b08cf89bdab332d14b68cd17cdfb4aa8a7113
|
||||
|
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
@ -84,9 +84,6 @@ updates:
|
||||
patterns:
|
||||
- "@highlightjs/cdn-assets"
|
||||
- "highlight.js"
|
||||
prosemirror:
|
||||
patterns:
|
||||
- "prosemirror-*"
|
||||
types:
|
||||
patterns:
|
||||
- "@types/*"
|
||||
|
54
.github/workflows/migration-tests.yml
vendored
54
.github/workflows/migration-tests.yml
vendored
@ -23,16 +23,21 @@ permissions:
|
||||
jobs:
|
||||
tests:
|
||||
if: github.event_name == 'pull_request' || github.repository != 'discourse/discourse-private-mirror'
|
||||
name: Tests
|
||||
runs-on: ${{ (github.repository_owner == 'discourse' && 'debian-12') || 'ubuntu-latest' }}
|
||||
container: discourse/discourse_test:release
|
||||
name: Tests with Ruby ${{ matrix.ruby }}
|
||||
runs-on: ${{ (github.repository != 'discourse/discourse' && 'ubuntu-latest') || 'debian-12' }}
|
||||
container: discourse/discourse_test:slim
|
||||
timeout-minutes: 20
|
||||
|
||||
env:
|
||||
RAILS_ENV: test
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
LOAD_PLUGINS: 1
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
matrix:
|
||||
ruby: ["3.3"]
|
||||
|
||||
steps:
|
||||
- name: Set working directory owner
|
||||
@ -57,9 +62,23 @@ jobs:
|
||||
sudo -E -u postgres script/start_test_db.rb
|
||||
sudo -u postgres psql -c "CREATE ROLE $PGUSER LOGIN SUPERUSER PASSWORD '$PGPASSWORD';"
|
||||
|
||||
- name: Symlink vendor/bundle from image
|
||||
- name: Container envs
|
||||
id: container-envs
|
||||
run: |
|
||||
ln -s /var/www/discourse/vendor/bundle vendor/bundle
|
||||
echo "ruby_version=$RUBY_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "debian_release=$DEBIAN_RELEASE" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: >-
|
||||
${{ runner.os }}-
|
||||
${{ steps.container-envs.outputs.ruby_version }}-
|
||||
${{ steps.container-envs.outputs.debian_release }}-
|
||||
${{ hashFiles('**/Gemfile.lock') }}-
|
||||
migrations-tooling
|
||||
|
||||
- name: Setup gems
|
||||
run: |
|
||||
@ -69,14 +88,11 @@ jobs:
|
||||
bundle config --local without development
|
||||
bundle config --local with migrations
|
||||
bundle install --jobs $(($(nproc) - 1))
|
||||
bundle clean
|
||||
|
||||
- name: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Get CPU cores
|
||||
id: cpu-info
|
||||
run: echo "cpu-cores=$(nproc)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Fetch app state cache
|
||||
uses: actions/cache@v4
|
||||
id: app-cache
|
||||
@ -84,8 +100,7 @@ jobs:
|
||||
path: tmp/app-cache
|
||||
key: >-
|
||||
${{ runner.os }}-
|
||||
${{ steps.cpu-info.outputs.cpu-cores }}-
|
||||
${{ hashFiles('.github/workflows/migration-tests.yml') }}-
|
||||
${{ hashFiles('.github/workflows/tests.yml') }}-
|
||||
${{ hashFiles('db/**/*', 'plugins/**/db/**/*') }}-
|
||||
${{ hashFiles('config/environments/test.rb') }}
|
||||
|
||||
@ -111,16 +126,11 @@ jobs:
|
||||
if: steps.app-cache.outputs.cache-hit != 'true'
|
||||
run: rm -rf tmp/app-cache/uploads && cp -r public/uploads tmp/app-cache/uploads
|
||||
|
||||
- name: Validate IntermediateDB schema
|
||||
run: |
|
||||
migrations/bin/cli schema generate --db=intermediate_db
|
||||
|
||||
if [ ! -z "$(git status --porcelain migrations/db/intermediate_db_schema/)" ]; then
|
||||
echo "IntermediateDB schema is not up to date."
|
||||
echo "---------------------------------------------"
|
||||
git -c color.ui=always diff migrations/db/intermediate_db_schema/
|
||||
exit 1
|
||||
fi
|
||||
# - name: Check core database drift
|
||||
# run: |
|
||||
# mkdir /tmp/intermediate_db
|
||||
# ./migrations/scripts/schema_generator /tmp/intermediate_db/base_migration.sql
|
||||
# diff -u migrations/common/intermediate_db_schema/000_base_schema.sql /tmp/intermediate_db/base_migration.sql
|
||||
|
||||
- name: RSpec
|
||||
run: bin/rspec --default-path migrations/spec
|
||||
|
5
.github/workflows/tests.yml
vendored
5
.github/workflows/tests.yml
vendored
@ -38,14 +38,13 @@ jobs:
|
||||
PGUSER: discourse
|
||||
PGPASSWORD: discourse
|
||||
USES_PARALLEL_DATABASES: ${{ matrix.build_type == 'backend' || matrix.build_type == 'system' }}
|
||||
CAPYBARA_DEFAULT_MAX_WAIT_TIME: 20
|
||||
CAPYBARA_DEFAULT_MAX_WAIT_TIME: 10
|
||||
MINIO_RUNNER_LOG_LEVEL: DEBUG
|
||||
DISCOURSE_TURBO_RSPEC_RETRY_AND_LOG_FLAKY_TESTS: ${{ (matrix.build_type == 'system' || matrix.build_type == 'backend') && '1' }}
|
||||
CHEAP_SOURCE_MAPS: "1"
|
||||
MINIO_RUNNER_INSTALL_DIR: /home/discourse/.minio_runner
|
||||
TESTEM_BROWSER: ${{ (startsWith(matrix.browser, 'Firefox') && 'Firefox') || matrix.browser }}
|
||||
TESTEM_FIREFOX_PATH: ${{ (matrix.browser == 'Firefox Evergreen') && '/opt/firefox-evergreen/firefox' }}
|
||||
EMBER_ENV: development
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -263,7 +262,7 @@ jobs:
|
||||
|
||||
- name: Ember Build for System Tests
|
||||
if: matrix.build_type == 'system'
|
||||
run: script/assemble_ember_build.rb
|
||||
run: bin/ember-cli --build
|
||||
|
||||
- name: Core System Tests
|
||||
if: matrix.build_type == 'system' && matrix.target == 'core'
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -53,7 +53,7 @@
|
||||
|
||||
/spec/fixtures/plugins/my_plugin/auto_generated
|
||||
|
||||
/vendor/bundle
|
||||
/vendor/bundle/*
|
||||
/vendor/data/GeoLite2-City.mmdb
|
||||
/vendor/data/GeoLite2-ASN.mmdb
|
||||
|
||||
|
195
Gemfile.lock
195
Gemfile.lock
@ -88,10 +88,10 @@ GEM
|
||||
bootsnap (1.18.4)
|
||||
msgpack (~> 1.2)
|
||||
builder (3.3.0)
|
||||
bullet (8.0.3)
|
||||
bullet (8.0.1)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (12.0.0)
|
||||
byebug (11.1.3)
|
||||
capybara (3.40.0)
|
||||
addressable
|
||||
matrix
|
||||
@ -119,15 +119,15 @@ GEM
|
||||
crass (1.0.6)
|
||||
css_parser (1.21.1)
|
||||
addressable
|
||||
csv (3.3.4)
|
||||
csv (3.3.3)
|
||||
date (3.4.1)
|
||||
debug_inspector (1.2.0)
|
||||
diff-lcs (1.6.1)
|
||||
diff-lcs (1.6.0)
|
||||
diffy (3.4.3)
|
||||
digest (3.2.0)
|
||||
digest-xxhash (0.2.9)
|
||||
discourse-emojis (1.0.39)
|
||||
discourse-fonts (0.0.19)
|
||||
discourse-emojis (1.0.38)
|
||||
discourse-fonts (0.0.18)
|
||||
discourse-seed-fu (2.3.12)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
@ -143,45 +143,45 @@ GEM
|
||||
logger
|
||||
execjs (2.10.0)
|
||||
exifr (1.4.1)
|
||||
extralite-bundle (2.12)
|
||||
extralite-bundle (2.10)
|
||||
fabrication (2.31.0)
|
||||
faker (3.5.1)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
fakeweb (1.3.0)
|
||||
faraday (2.13.0)
|
||||
faraday (2.12.2)
|
||||
faraday-net_http (>= 2.0, < 3.5)
|
||||
json
|
||||
logger
|
||||
faraday-net_http (3.4.0)
|
||||
net-http (>= 0.5.0)
|
||||
faraday-retry (2.3.1)
|
||||
faraday-retry (2.2.1)
|
||||
faraday (~> 2.0)
|
||||
fast_blank (1.0.1)
|
||||
fastimage (2.3.1)
|
||||
ffi (1.17.2-aarch64-linux-gnu)
|
||||
ffi (1.17.2-aarch64-linux-musl)
|
||||
ffi (1.17.2-arm-linux-gnu)
|
||||
ffi (1.17.2-arm-linux-musl)
|
||||
ffi (1.17.2-arm64-darwin)
|
||||
ffi (1.17.2-x86_64-darwin)
|
||||
ffi (1.17.2-x86_64-linux-gnu)
|
||||
ffi (1.17.2-x86_64-linux-musl)
|
||||
ffi (1.17.1-aarch64-linux-gnu)
|
||||
ffi (1.17.1-aarch64-linux-musl)
|
||||
ffi (1.17.1-arm-linux-gnu)
|
||||
ffi (1.17.1-arm-linux-musl)
|
||||
ffi (1.17.1-arm64-darwin)
|
||||
ffi (1.17.1-x86_64-darwin)
|
||||
ffi (1.17.1-x86_64-linux-gnu)
|
||||
ffi (1.17.1-x86_64-linux-musl)
|
||||
fspath (3.1.2)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
google-protobuf (4.30.2)
|
||||
google-protobuf (4.30.1)
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
google-protobuf (4.30.2-aarch64-linux)
|
||||
google-protobuf (4.30.1-aarch64-linux)
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
google-protobuf (4.30.2-arm64-darwin)
|
||||
google-protobuf (4.30.1-arm64-darwin)
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
google-protobuf (4.30.2-x86_64-darwin)
|
||||
google-protobuf (4.30.1-x86_64-darwin)
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
google-protobuf (4.30.2-x86_64-linux)
|
||||
google-protobuf (4.30.1-x86_64-linux)
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
guess_html_encoding (0.0.11)
|
||||
@ -203,7 +203,7 @@ GEM
|
||||
image_size (3.4.0)
|
||||
in_threads (1.6.0)
|
||||
io-console (0.8.0)
|
||||
irb (1.15.2)
|
||||
irb (1.15.1)
|
||||
pp (>= 0.6.0)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
@ -233,7 +233,7 @@ GEM
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
literate_randomizer (0.4.0)
|
||||
logger (1.7.0)
|
||||
logger (1.6.6)
|
||||
lograge (0.14.0)
|
||||
actionpack (>= 4)
|
||||
activesupport (>= 4)
|
||||
@ -260,7 +260,7 @@ GEM
|
||||
mini_racer (>= 0.6.3)
|
||||
method_source (1.1.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_racer (0.18.1)
|
||||
mini_racer (0.18.0)
|
||||
libv8-node (~> 23.6.1.0)
|
||||
mini_scheduler (0.18.0)
|
||||
sidekiq (>= 6.5, < 8.0)
|
||||
@ -288,21 +288,21 @@ GEM
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.4)
|
||||
nokogiri (1.18.7-aarch64-linux-gnu)
|
||||
nokogiri (1.18.6-aarch64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-aarch64-linux-musl)
|
||||
nokogiri (1.18.6-aarch64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm-linux-gnu)
|
||||
nokogiri (1.18.6-arm-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm-linux-musl)
|
||||
nokogiri (1.18.6-arm-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-arm64-darwin)
|
||||
nokogiri (1.18.6-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-darwin)
|
||||
nokogiri (1.18.6-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-linux-gnu)
|
||||
nokogiri (1.18.6-x86_64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.7-x86_64-linux-musl)
|
||||
nokogiri (1.18.6-x86_64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
oauth (1.1.0)
|
||||
oauth-tty (~> 1.0, >= 1.0.1)
|
||||
@ -348,10 +348,10 @@ GEM
|
||||
openssl (> 2.0)
|
||||
optimist (3.2.1)
|
||||
ostruct (0.6.1)
|
||||
parallel (1.27.0)
|
||||
parallel (1.26.3)
|
||||
parallel_tests (5.1.0)
|
||||
parallel
|
||||
parser (3.3.8.0)
|
||||
parser (3.3.7.2)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
pg (1.5.9)
|
||||
@ -359,14 +359,13 @@ GEM
|
||||
prettyprint
|
||||
prettier_print (1.2.1)
|
||||
prettyprint (0.2.0)
|
||||
prism (1.4.0)
|
||||
progress (3.6.0)
|
||||
pry (0.15.2)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
pry-byebug (3.11.0)
|
||||
byebug (~> 12.0)
|
||||
pry (>= 0.13, < 0.16)
|
||||
pry-byebug (3.10.1)
|
||||
byebug (~> 11.0)
|
||||
pry (>= 0.13, < 0.15)
|
||||
pry-rails (0.3.11)
|
||||
pry (>= 0.13.0)
|
||||
pry-stack_explorer (0.6.1)
|
||||
@ -425,7 +424,7 @@ GEM
|
||||
msgpack (>= 0.4.3)
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.9.0)
|
||||
rdoc (6.13.1)
|
||||
rdoc (6.12.0)
|
||||
psych (>= 4.0.0)
|
||||
redcarpet (3.6.1)
|
||||
redis (5.4.0)
|
||||
@ -435,7 +434,7 @@ GEM
|
||||
redis-namespace (1.11.0)
|
||||
redis (>= 4)
|
||||
regexp_parser (2.10.0)
|
||||
reline (0.6.1)
|
||||
reline (0.6.0)
|
||||
io-console (~> 0.5)
|
||||
request_store (1.7.0)
|
||||
rack (>= 1.4)
|
||||
@ -484,7 +483,7 @@ GEM
|
||||
rspec-core (>= 2.14)
|
||||
rtlcss (0.2.1)
|
||||
mini_racer (>= 0.6.3)
|
||||
rubocop (1.75.2)
|
||||
rubocop (1.74.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (~> 3.17.0.2)
|
||||
lint_roller (~> 1.1.0)
|
||||
@ -492,12 +491,11 @@ GEM
|
||||
parser (>= 3.3.0.2)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 2.9.3, < 3.0)
|
||||
rubocop-ast (>= 1.44.0, < 2.0)
|
||||
rubocop-ast (>= 1.38.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 4.0)
|
||||
rubocop-ast (1.44.1)
|
||||
rubocop-ast (1.41.0)
|
||||
parser (>= 3.3.7.2)
|
||||
prism (~> 1.4)
|
||||
rubocop-capybara (2.22.1)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
@ -513,11 +511,11 @@ GEM
|
||||
rubocop-factory_bot (2.27.1)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rails (2.31.0)
|
||||
rubocop-rails (2.30.3)
|
||||
activesupport (>= 4.2.0)
|
||||
lint_roller (~> 1.1)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.75.0, < 2.0)
|
||||
rubocop (>= 1.72.1, < 2.0)
|
||||
rubocop-ast (>= 1.38.0, < 2.0)
|
||||
rubocop-rspec (3.5.0)
|
||||
lint_roller (~> 1.1)
|
||||
@ -555,9 +553,9 @@ GEM
|
||||
sassc-embedded (1.80.2)
|
||||
sass-embedded (~> 1.80)
|
||||
securerandom (0.4.1)
|
||||
selenium-devtools (0.135.0)
|
||||
selenium-devtools (0.133.0)
|
||||
selenium-webdriver (~> 4.2)
|
||||
selenium-webdriver (4.31.0)
|
||||
selenium-webdriver (4.29.1)
|
||||
base64 (~> 0.2)
|
||||
logger (~> 1.4)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
@ -599,7 +597,7 @@ GEM
|
||||
sqlite3 (2.6.0-x86_64-linux-musl)
|
||||
sshkey (3.0.0)
|
||||
stackprof (0.2.27)
|
||||
stringio (3.1.6)
|
||||
stringio (3.1.5)
|
||||
syntax_tree (6.2.0)
|
||||
prettier_print (>= 1.2.0)
|
||||
test-prof (1.4.4)
|
||||
@ -622,7 +620,7 @@ GEM
|
||||
uniform_notifier (1.16.0)
|
||||
uri (1.0.3)
|
||||
useragent (0.16.11)
|
||||
version_gem (1.1.7)
|
||||
version_gem (1.1.6)
|
||||
web-push (3.0.1)
|
||||
jwt (~> 2.0)
|
||||
openssl (~> 3.0)
|
||||
@ -827,8 +825,8 @@ CHECKSUMS
|
||||
binding_of_caller (1.0.1) sha256=2b2902abff4246ddcfbc4da9b69bc4a019e22aeb300c2ff6289a173d4b90b29a
|
||||
bootsnap (1.18.4) sha256=ac4c42af397f7ee15521820198daeff545e4c360d2772c601fbdc2c07d92af55
|
||||
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
||||
bullet (8.0.3) sha256=60e41446500a7e59272b3c2398cded214deec3662e883009de5bf30028a0642c
|
||||
byebug (12.0.0) sha256=d4a150d291cca40b66ec9ca31f754e93fed8aa266a17335f71bb0afa7fca1a1e
|
||||
bullet (8.0.1) sha256=a18f7aa3a20f063a48e7a9dbcaf868bd2ede6e9b1056818ce825f74a717cd2f0
|
||||
byebug (11.1.3) sha256=2485944d2bb21283c593d562f9ae1019bf80002143cc3a255aaffd4e9cf4a35b
|
||||
capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef
|
||||
cbor (0.5.9.8) sha256=9ee097fc58d9bc5e406d112cd2d4e112c7354ec16f8b6ff34e4732c1e44b4eb7
|
||||
certified (1.0.0) sha256=aa4cdf0e90e7ee96f6e0ce3daae39eaa8f0486124e0d92daf64d2105aeb9069c
|
||||
@ -843,15 +841,15 @@ CHECKSUMS
|
||||
crack (1.0.0) sha256=c83aefdb428cdc7b66c7f287e488c796f055c0839e6e545fec2c7047743c4a49
|
||||
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
|
||||
css_parser (1.21.1) sha256=6cfd3ffc0a97333b39d2b1b49c95397b05e0e3b684d68f77ec471ba4ec2ef7c7
|
||||
csv (3.3.4) sha256=e96ecd5a8c3494aa5b596282249daba5c6033203c199248e6146e36d2a78d8cd
|
||||
csv (3.3.3) sha256=7e2966befb7bdaf7d5e9b36e1de73e6a5e7a72f584f180a1726aec88a1b0a900
|
||||
date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
|
||||
debug_inspector (1.2.0) sha256=9bdfa02eebc3da163833e6a89b154084232f5766087e59573b70521c77ea68a2
|
||||
diff-lcs (1.6.1) sha256=12a5a83f3e37a8e2f4427268e305914d5f1879f22b4e73bb1a09f76a3dd86cd4
|
||||
diff-lcs (1.6.0) sha256=a1e7f7b272962f8fc769358ad00001b87cdcf32ba349d6c70c6b544613d2da2e
|
||||
diffy (3.4.3) sha256=4264b9e7db00d1cd426fcd32e36565779163cedc2340a95b0e6f025e71f9aaa7
|
||||
digest (3.2.0) sha256=fa2e7092ec683f65d82fadde5ff4ca3b32e23ee0b19f1fc1a5e09993ad2d3991
|
||||
digest-xxhash (0.2.9) sha256=a989d8309c03c4136a4bea9981ec0a146a2750de7f3dfb7b5624a3038aa598d7
|
||||
discourse-emojis (1.0.39) sha256=7c7ce56b7a97f7ca2b9b26ffb2c2bb6454d2bfbb45dd3b68d91dd1e90b8e9c04
|
||||
discourse-fonts (0.0.19) sha256=78d4ddd671615908303a675427039d8d787c935e6deae184c6e143c18c6e0033
|
||||
discourse-emojis (1.0.38) sha256=4f9cfcbc7ea8aef69e1210e8796233ad9923ae908ee7696424f3ad92e51d6c51
|
||||
discourse-fonts (0.0.18) sha256=a7d25c13edd3325ae40010ca277530d69fc7952a05aa7b2ff07c1d07412b72a1
|
||||
discourse-seed-fu (2.3.12) sha256=4f61d95c11ed54609046cd04eb3a51b531c5fa863fa86d1bea7d74264e5c75e4
|
||||
discourse_dev_assets (0.0.5) sha256=a09a801a210aa3f7247dd382dfd73b389d4bd02be86be675eca2d451f9898285
|
||||
docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
|
||||
@ -862,30 +860,30 @@ CHECKSUMS
|
||||
excon (1.2.5) sha256=ca040bb61bc0059968f34a17115a00d2db8562e3c0c5c5c7432072b551c85a9d
|
||||
execjs (2.10.0) sha256=6bcb8be8f0052ff9d370b65d1c080f2406656e150452a0abdb185a133048450d
|
||||
exifr (1.4.1) sha256=768374cc6b6ff3743acba57c1c35229bdd8c6b9fbc1285952047fc1215c4b894
|
||||
extralite-bundle (2.12) sha256=9c9912b7ab592e7064089ee608cf86ab9edd81d20065acb87d1f4fed06052987
|
||||
extralite-bundle (2.10) sha256=d765b84abe359f8ed8ee1735de016167ab9f7c7760e3f9b49ba7434fa81ff192
|
||||
fabrication (2.31.0) sha256=2c79f10d1b88034a2ebd47ce77acba66847fc4636581c8282b3408adc68e85aa
|
||||
faker (3.5.1) sha256=1ad1fbea279d882f486059c23fe3ddb816ccd1d7052c05a45014b4450d859bfc
|
||||
fakeweb (1.3.0) sha256=1ec996be13020a00b3464560c09180b424477c698f59f82edf2b99b16cfa09a8
|
||||
faraday (2.13.0) sha256=f2697cd61a434dc446ee035f0370de654c2ad64707c4fc2541eb2338702e9614
|
||||
faraday (2.12.2) sha256=157339c25c7b8bcb739f5cf1207cb0cefe8fa1c65027266bcbc34c90c84b9ad6
|
||||
faraday-net_http (3.4.0) sha256=a1f1e4cd6a2cf21599c8221595e27582d9936819977bbd4089a601f24c64e54a
|
||||
faraday-retry (2.3.1) sha256=4004faa21f41fc5360d359bc79889fc58fb7fae0ce93bfb737a784ac76805c03
|
||||
faraday-retry (2.2.1) sha256=4146fed14549c0580bf14591fca419a40717de0dd24f267a8ec2d9a728677608
|
||||
fast_blank (1.0.1) sha256=269fc30414fed4e6403bc4a49081e1ea539f8b9226e59276ed1efaefabaa17ea
|
||||
fastimage (2.3.1) sha256=23c629f1f3e7d61bcfcc06c25b3d2418bc6bf41d2e615dbf5132c0e3b63ecce9
|
||||
ffi (1.17.2-aarch64-linux-gnu) sha256=c910bd3cae70b76690418cce4572b7f6c208d271f323d692a067d59116211a1a
|
||||
ffi (1.17.2-aarch64-linux-musl) sha256=69e6556b091d45df83e6c3b19d3c54177c206910965155a6ec98de5e893c7b7c
|
||||
ffi (1.17.2-arm-linux-gnu) sha256=d4a438f2b40224ae42ec72f293b3ebe0ba2159f7d1bd47f8417e6af2f68dbaa5
|
||||
ffi (1.17.2-arm-linux-musl) sha256=977dfb7f3a6381206dbda9bc441d9e1f9366bf189a634559c3b7c182c497aaa3
|
||||
ffi (1.17.2-arm64-darwin) sha256=54dd9789be1d30157782b8de42d8f887a3c3c345293b57ffb6b45b4d1165f813
|
||||
ffi (1.17.2-x86_64-darwin) sha256=981f2d4e32ea03712beb26e55e972797c2c5a7b0257955d8667ba58f2da6440e
|
||||
ffi (1.17.2-x86_64-linux-gnu) sha256=05d2026fc9dbb7cfd21a5934559f16293815b7ce0314846fee2ac8efbdb823ea
|
||||
ffi (1.17.2-x86_64-linux-musl) sha256=97c0eb3981414309285a64dc4d466bd149e981c279a56371ef811395d68cb95c
|
||||
ffi (1.17.1-aarch64-linux-gnu) sha256=c5d22cb545a3a691d46060f1343c461d1a8d38c3fd71b96b4cbbe6906bf1fd38
|
||||
ffi (1.17.1-aarch64-linux-musl) sha256=88b9d6ae905d21142df27c94bb300042c1aae41b67291885f600eaad16326b1d
|
||||
ffi (1.17.1-arm-linux-gnu) sha256=fe14f5ece94082f3b0e651a09008113281f2764e7ea95f522b64e2fe32e11504
|
||||
ffi (1.17.1-arm-linux-musl) sha256=df14927ca7bd9095148a7d1938bb762bbf189d190cf25d9547395ec7acc198a0
|
||||
ffi (1.17.1-arm64-darwin) sha256=a8e04f79d375742c54ee7f9fff4b4022b87200a4ec0eb082128d3b6559e67b4d
|
||||
ffi (1.17.1-x86_64-darwin) sha256=0036199c290462dd7f03bc22933644c1685b7834a21788062bd5df48c72aa7a6
|
||||
ffi (1.17.1-x86_64-linux-gnu) sha256=8c0ade2a5d19f3672bccfe3b58e016ae5f159e3e2e741c856db87fcf07c903d0
|
||||
ffi (1.17.1-x86_64-linux-musl) sha256=3a343086820c96d6fbea4a5ef807fb69105b2b8174678f103b3db210c3f78401
|
||||
fspath (3.1.2) sha256=b5ac9bafb97e2c8f8f9e303cd98ebd484be76fe9aa588bc4d01c6d99e78c9d75
|
||||
globalid (1.2.1) sha256=70bf76711871f843dbba72beb8613229a49429d1866828476f9c9d6ccc327ce9
|
||||
google-protobuf (4.30.2) sha256=0f35168dbeeccf13d928acf6c128cfec17b9a826ae4505246a02c115f4ae16ed
|
||||
google-protobuf (4.30.2-aarch64-linux) sha256=a99d2f31bc2bebf4994b7cd2dd4c1d3ef28a0acc8f1b37be236982f7dc21bd8d
|
||||
google-protobuf (4.30.2-arm64-darwin) sha256=c66a93ceef100fb2390615e76310491cc6e1944f7b9cda2cf1e3279887f817d1
|
||||
google-protobuf (4.30.2-x86_64-darwin) sha256=17f4567dff431f8dd5be5ff6395824ec044413f67d2803a9941ebc8c70dec604
|
||||
google-protobuf (4.30.2-x86_64-linux) sha256=c96993d98732ea185d98279f6c76e130eb9595437dda39610b3398c9e348518e
|
||||
google-protobuf (4.30.1) sha256=0c88b433866eac8a07d13ea19182e23334b14ac99d2a186cd88b72e2413d0778
|
||||
google-protobuf (4.30.1-aarch64-linux) sha256=5e155eae7b686bd4f826f947f311d1c00b4c3b467ca21b27c47610b400a215c5
|
||||
google-protobuf (4.30.1-arm64-darwin) sha256=f69682f65a0c2f689040714e2c6407c838b9113dce87d76e7e568f1213b7fdeb
|
||||
google-protobuf (4.30.1-x86_64-darwin) sha256=626836baf2470c5590fedda795598cea1c3385f690a97f2ed6d7d43a31110d9a
|
||||
google-protobuf (4.30.1-x86_64-linux) sha256=84c87b239dec7a200dddbcbd9bdb03a59c109f4b32667a50bec84286faa9784e
|
||||
guess_html_encoding (0.0.11) sha256=cab6468b945f38673fc41ad147fbbc89693b3c6c34b03b071e2ed669a603e098
|
||||
hana (1.3.7) sha256=5425db42d651fea08859811c29d20446f16af196308162894db208cac5ce9b0d
|
||||
hashdiff (1.1.2) sha256=2c30eeded6ed3dce8401d2b5b99e6963fe5f14ed85e60dd9e33c545a44b71a77
|
||||
@ -898,7 +896,7 @@ CHECKSUMS
|
||||
image_size (3.4.0) sha256=c6a580513fe74947e25e5d3f0aea1e33add6c20f7d0007efa65504317b7f029a
|
||||
in_threads (1.6.0) sha256=91a7e6138d279dc632f59b8a9a409e47148948e297c0f69c92f9a2479a182149
|
||||
io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
|
||||
irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba
|
||||
irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890
|
||||
iso8601 (0.13.0) sha256=298c2b15b7be5fa95a1372813d36a2257656cd8e906dfbc1f5cb409851425aa2
|
||||
jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1
|
||||
json (2.10.2) sha256=34e0eada93022b2a0a3345bb0b5efddb6e9ff5be7c48e409cfb54ff8a36a8b06
|
||||
@ -916,7 +914,7 @@ CHECKSUMS
|
||||
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
||||
listen (3.9.0) sha256=db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67
|
||||
literate_randomizer (0.4.0) sha256=05073c9b383983b1ed7e26c40b963468e91bc86e663b3eeff3a4af91b84217b1
|
||||
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||
logger (1.6.6) sha256=dd618d24e637715472732e7eed02e33cfbdf56deaad225edd0f1f89d38024017
|
||||
lograge (0.14.0) sha256=42371a75823775f166f727639f5ddce73dd149452a55fc94b90c303213dc9ae1
|
||||
logstash-event (1.2.02) sha256=89a7dc60fac67070a5f60ba07409e541b09cb58906c391e90cb74b9f217467ae
|
||||
logster (2.20.1) sha256=a84bbe58e7f99c4eb0246ea3a952ed87950f63aeea3cdbe7147018d10cc9a2a8
|
||||
@ -931,7 +929,7 @@ CHECKSUMS
|
||||
messageformat-wrapper (1.1.0) sha256=ecea879626e412d1bc841c457dacfcbb1a62cf88ca83573e4ea34bb371f160bc
|
||||
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
|
||||
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
||||
mini_racer (0.18.1) sha256=c6694c37672da05027fe0894215a94c18a2117bdbb4ba90d80d275e4b23b3413
|
||||
mini_racer (0.18.0) sha256=742ea6f25e45ad33efaa3e0b7c5c5a0ab4f2c1f5b116de1324c04cc89fd5607e
|
||||
mini_scheduler (0.18.0) sha256=d2f084f38da8d76c5844a92f0d6bd01fc9982a8b5e6c7679b6cf44c82da33503
|
||||
mini_sql (1.6.0) sha256=5296637f6a4af5bb43e06788037e9a2968ff9c8eb65928befcba8cb41f42d6ee
|
||||
mini_suffix (0.3.3) sha256=8d1d33f92f69a2247c9b7d27173235da90479d955cdb863b63a7f53843b722e7
|
||||
@ -948,14 +946,14 @@ CHECKSUMS
|
||||
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
|
||||
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
|
||||
nio4r (2.7.4) sha256=d95dee68e0bb251b8ff90ac3423a511e3b784124e5db7ff5f4813a220ae73ca9
|
||||
nokogiri (1.18.7-aarch64-linux-gnu) sha256=57a064ab5440814a69a0e040817bd8154adea68a30d2ff2b3aa515a6a06dbb5f
|
||||
nokogiri (1.18.7-aarch64-linux-musl) sha256=3e442dc5b69376e84288295fe37cbb890a21ad816a7e571e5e9967b3c1e30cd3
|
||||
nokogiri (1.18.7-arm-linux-gnu) sha256=337d9149deb5ae01022dff7c90f97bed81715fd586aacab0c5809ef933994c5e
|
||||
nokogiri (1.18.7-arm-linux-musl) sha256=97a26edcc975f780a0822aaf7f7d7427c561067c1c9ee56bd3542960f0c28a6e
|
||||
nokogiri (1.18.7-arm64-darwin) sha256=083abb2e9ed2646860f6b481a981485a658c6064caafaa81bf1cda1bada2e9d5
|
||||
nokogiri (1.18.7-x86_64-darwin) sha256=081d1aa517454ba3415304e2ea51fe411d6a3a809490d0c4aa42799cada417b7
|
||||
nokogiri (1.18.7-x86_64-linux-gnu) sha256=3a0bf946eb2defde13d760f869b61bc8b0c18875afdd3cffa96543cfa3a18005
|
||||
nokogiri (1.18.7-x86_64-linux-musl) sha256=9d83f8ec1fc37a305fa835d7ee61a4f37899e6ccc6dcb05be6645fa9797605af
|
||||
nokogiri (1.18.6-aarch64-linux-gnu) sha256=1b11f9a814068282cc2b47ebe61395b2a69d1918092d2ca3bd664074f72540e9
|
||||
nokogiri (1.18.6-aarch64-linux-musl) sha256=797662f201c37a8feac3bd5b0c0e3447053bc71e6633d273fefd4c68b03e6a54
|
||||
nokogiri (1.18.6-arm-linux-gnu) sha256=2da07a07ef4c9d9e9da809b3dc0937ed90b031e32c2c658d9918941b85d68b95
|
||||
nokogiri (1.18.6-arm-linux-musl) sha256=e8ae1c9a4d8cfa7a92d632a6f596a88235ebe66d4b70418543378ba16c601f70
|
||||
nokogiri (1.18.6-arm64-darwin) sha256=727a441d179d934b4b7c73e0e28e6723ee46463d96bb0cc6e2e33a13540962c4
|
||||
nokogiri (1.18.6-x86_64-darwin) sha256=fb72568c97ccd90a8d68cb765b0ff0720b109bd62e3babbf372e854ef8fef995
|
||||
nokogiri (1.18.6-x86_64-linux-gnu) sha256=df065db6ba6e1e80f76ef04f860fcf260cc24685125fe33cdc3d1572a1c66b71
|
||||
nokogiri (1.18.6-x86_64-linux-musl) sha256=75ec7a93cec54687aa63b2eaf830dc4ac5b4f3d8c969f20c035e67c9e6a30cef
|
||||
oauth (1.1.0) sha256=38902b7f0f5ed91e858d6353f5e1e06b2c16a8aa0fd91984671eab1a1d1cddeb
|
||||
oauth-tty (1.0.5) sha256=34e25c307da4509d4deec266ff3690bbf42e391355f496201c029268862d8b17
|
||||
oauth2 (1.4.11) sha256=6739fcc8872bc94f476b0cae3e8bd78a56d8364b1b79b0757794c25e152d5c10
|
||||
@ -971,17 +969,16 @@ CHECKSUMS
|
||||
openssl-signature_algorithm (1.3.0) sha256=a3b40b5e8276162d4a6e50c7c97cdaf1446f9b2c3946a6fa2c14628e0c957e80
|
||||
optimist (3.2.1) sha256=8cf8a0fd69f3aa24ab48885d3a666717c27bc3d9edd6e976e18b9d771e72e34e
|
||||
ostruct (0.6.1) sha256=09a3fb7ecc1fa4039f25418cc05ae9c82bd520472c5c6a6f515f03e4988cb817
|
||||
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
||||
parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
|
||||
parallel_tests (5.1.0) sha256=c8cc0eef06577543dc3e09220ac5271809d9a1c65fa52ef86dd759bb4cb5aba5
|
||||
parser (3.3.8.0) sha256=2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45
|
||||
parser (3.3.7.2) sha256=c71de9076be0b84459a268581b5aa75e5eeaac892b564430371d1f8eb55fb65f
|
||||
pg (1.5.9) sha256=761efbdf73b66516f0c26fcbe6515dc7500c3f0aa1a1b853feae245433c64fdc
|
||||
pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
|
||||
prettier_print (1.2.1) sha256=a72838b5f23facff21f90a5423cdcdda19e4271092b41f4ea7f50b83929e6ff9
|
||||
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
||||
prism (1.4.0) sha256=dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e
|
||||
progress (3.6.0) sha256=360ed306dfa43d6174e847d563c70736dca249e2333cfec4b0387306c86cd573
|
||||
pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
|
||||
pry-byebug (3.11.0) sha256=0b0abb7d309bc7f00044d512a3c8567274f7012b944b38becc8440439a1cea72
|
||||
pry (0.14.2) sha256=c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d
|
||||
pry-byebug (3.10.1) sha256=c8f975c32255bfdb29e151f5532130be64ff3d0042dc858d0907e849125581f8
|
||||
pry-rails (0.3.11) sha256=a69e28e24a34d75d1f60bcf241192a54253f8f7ef8a62cba1e75750a9653593d
|
||||
pry-stack_explorer (0.6.1) sha256=a2dbea9b47c4ad00cf5c1ce21499f8128b915089e90015f7bafb6e9453baf340
|
||||
psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee
|
||||
@ -1006,13 +1003,13 @@ CHECKSUMS
|
||||
rb-inotify (0.11.1) sha256=a0a700441239b0ff18eb65e3866236cd78613d6b9f78fea1f9ac47a85e47be6e
|
||||
rbtrace (0.5.1) sha256=e8cba64d462bfb8ba102d7be2ecaacc789247d52ac587d8003549d909cb9c5dc
|
||||
rchardet (1.9.0) sha256=26889486cdd83b378652baf7603f71d93e431bb11bc237b4cd8c65151af4a590
|
||||
rdoc (6.13.1) sha256=62a0dac99493c94e8eb7a3fb44e55aefcb4cecb119f7991f25bddc5ed8d472f7
|
||||
rdoc (6.12.0) sha256=7d6f706e070bffa5d18a448f24076cbfb34923a99c1eab842aa18e6ca69f56e0
|
||||
redcarpet (3.6.1) sha256=d444910e6aa55480c6bcdc0cdb057626e8a32c054c29e793fa642ba2f155f445
|
||||
redis (5.4.0) sha256=798900d869418a9fc3977f916578375b45c38247a556b61d58cba6bb02f7d06b
|
||||
redis-client (0.24.0) sha256=ee65ee39cb2c38608b734566167fd912384f3c1241f59075e22858f23a085dbb
|
||||
redis-namespace (1.11.0) sha256=e91a1aa2b2d888b6dea1d4ab8d39e1ae6fac3426161feb9d91dd5cca598a2239
|
||||
regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
|
||||
reline (0.6.1) sha256=1afcc9d7cb1029cdbe780d72f2f09251ce46d3780050f3ec39c3ccc6b60675fb
|
||||
reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
|
||||
request_store (1.7.0) sha256=e1b75d5346a315f452242a68c937ef8e48b215b9453a77a6c0acdca2934c88cb
|
||||
rexml (3.4.1) sha256=c74527a9a0a04b4ec31dbe0dc4ed6004b960af943d8db42e539edde3a871abca
|
||||
rinku (2.0.6) sha256=8b60670e3143f3db2b37efa262971ce3619ec23092045498ef9f077d82828d7d
|
||||
@ -1032,12 +1029,12 @@ CHECKSUMS
|
||||
rss (0.3.1) sha256=b46234c04551b925180f8bedfc6f6045bf2d9998417feda72f300e7980226737
|
||||
rswag-specs (2.16.0) sha256=8ba26085c408b0bd2ed21dc8015c80f417c7d34c63720ab7133c2549b5bd2a91
|
||||
rtlcss (0.2.1) sha256=213d5a00bf61267f93a7a516d699d77e1cc5f396743abb33c01e3f3243a7bf60
|
||||
rubocop (1.75.2) sha256=8efde647e278417e8074421b007e0d7d7c591482ef99d980528b18fea015a7c8
|
||||
rubocop-ast (1.44.1) sha256=e3cc04203b2ef04f6d6cf5f85fe6d643f442b18cc3b23e3ada0ce5b6521b8e92
|
||||
rubocop (1.74.0) sha256=06138a35d7d11c963d5abc0148b355e3999007cb0225a619940db0e75521379b
|
||||
rubocop-ast (1.41.0) sha256=0eeff9ad3743f42823e3c687cbc15f8c552ff63c9f8e3d35fbafe746977c7c0d
|
||||
rubocop-capybara (2.22.1) sha256=ced88caef23efea53f46e098ff352f8fc1068c649606ca75cb74650970f51c0c
|
||||
rubocop-discourse (3.12.1) sha256=ebf7e2224f053047372071419052828c3e3a01bccb14ea1f282ac143547df9bc
|
||||
rubocop-factory_bot (2.27.1) sha256=9d744b5916778c1848e5fe6777cc69855bd96548853554ec239ba9961b8573fe
|
||||
rubocop-rails (2.31.0) sha256=79476e1075299c3e60fc50549c7c32614f9ebaae719b899ed75785c6786c52bd
|
||||
rubocop-rails (2.30.3) sha256=fc5a6506daa916d15e282cc806943afa64a020bf592b93a94025d89a2a78a715
|
||||
rubocop-rspec (3.5.0) sha256=710c942fe1af884ba8eea75cbb8bdbb051929a2208880a6fc2e2dce1eed5304c
|
||||
rubocop-rspec_rails (2.31.0) sha256=775375e18a26a1184a812ef3054b79d218e85601b9ae897f38f8be24dddf1f45
|
||||
ruby-prof (1.7.1) sha256=026393448cf92fd24a91739bf71ccd2bfe88fe8a1401ee8afc4948a16d62ea24
|
||||
@ -1056,8 +1053,8 @@ CHECKSUMS
|
||||
sass-embedded (1.85.0-x86_64-linux-musl) sha256=ca01931c54b59db1130a779386bcfc798f8dcfee1f98f60fbcf8c5dbdc0f9c23
|
||||
sassc-embedded (1.80.2) sha256=625ac3923fe9af1a8072210cf22b01b66f3dc23748a4997a9b28bfdff7c7967d
|
||||
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
|
||||
selenium-devtools (0.135.0) sha256=3862ec1f3e940a030f492b3691d11af35544789f961fcd0633cb89e4ea4251ec
|
||||
selenium-webdriver (4.31.0) sha256=ddb2d88eee23cddb5d6a9dadd909427a9e5163718338e11a91eef2fbead100e9
|
||||
selenium-devtools (0.133.0) sha256=aba5a5225ac38d235bbc6ebb4e0b8209e973ac7af4226e4304a1417573f73f64
|
||||
selenium-webdriver (4.29.1) sha256=0a7fe53cc4d2c515adbb89e115c6e786c64e9b98f85939d21071c6e32883a146
|
||||
shoulda-matchers (6.4.0) sha256=9055bb7f4bb342125fb860809798855c630e05ef5e75837b3168b8e6ee1608b0
|
||||
sidekiq (7.3.9) sha256=1108712e1def89002b28e3545d5ae15d4a57ffd4d2c25d97bb1360988826b5a7
|
||||
simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
|
||||
@ -1077,7 +1074,7 @@ CHECKSUMS
|
||||
sqlite3 (2.6.0-x86_64-linux-musl) sha256=6f7c9346430c4aacc9280dee6bd4d23a6f1f31013d4f9c0a720fb14ef6a801c2
|
||||
sshkey (3.0.0) sha256=655ba351d6e01a48dfe59d65530af8975c777b8cc57a061770de3228ff2d11cd
|
||||
stackprof (0.2.27) sha256=aff6d28656c852e74cf632cc2046f849033dc1dedffe7cb8c030d61b5745e80c
|
||||
stringio (3.1.6) sha256=292c495d1657adfcdf0a32eecf12a60e6691317a500c3112ad3b2e31068274f5
|
||||
stringio (3.1.5) sha256=bca92461515a131535743bc81d5559fa1de7d80cff9a654d6c0af6f9f27e35c8
|
||||
syntax_tree (6.2.0) sha256=a50a01c246601af3c258edbb6b12e44373d17966ab3bebd1f7224b3b994a343d
|
||||
test-prof (1.4.4) sha256=1a59513ed9d33a1f5ca17c0b89da4e70f60a91c83ec62e9a873dbb99141353ef
|
||||
thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda
|
||||
@ -1093,7 +1090,7 @@ CHECKSUMS
|
||||
uniform_notifier (1.16.0) sha256=99b39ee4a0864e3b49f375b5e5803eb26d35ed6eb1719c96407573a87bc4dbb5
|
||||
uri (1.0.3) sha256=e9f2244608eea2f7bc357d954c65c910ce0399ca5e18a7a29207ac22d8767011
|
||||
useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844
|
||||
version_gem (1.1.7) sha256=df3bacb16c09d9069d51625f6e009da28e69ed8f9cbd2dd14753cec944e0cacc
|
||||
version_gem (1.1.6) sha256=b989cf19880ee18907083ba9bb6fdbe40826bd698fbd7cdfab7345a2550bf203
|
||||
web-push (3.0.1) sha256=5b4dd2f2bba3bd8951da6416492fe920a6f203d14d3080f943c5d01c0cc4b18d
|
||||
webmock (3.25.1) sha256=ab9d5d9353bcbe6322c83e1c60a7103988efc7b67cd72ffb9012629c3d396323
|
||||
webrick (1.9.1) sha256=b42d3c94f166f3fb73d87e9b359def9b5836c426fc8beacf38f2184a21b2a989
|
||||
|
@ -10,7 +10,6 @@ import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
|
||||
import AdminFilteredSiteSettings from "admin/components/admin-filtered-site-settings";
|
||||
import AdminSiteSettingsChangesBanner from "admin/components/admin-site-settings-changes-banner";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
|
||||
export default class AdminAreaSettings extends Component {
|
||||
@ -95,7 +94,5 @@ export default class AdminAreaSettings extends Component {
|
||||
</ConditionalLoadingSpinner>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<AdminSiteSettingsChangesBanner />
|
||||
</template>
|
||||
}
|
||||
|
@ -12,9 +12,8 @@ import { i18n } from "discourse-i18n";
|
||||
import AdminConfigAreaCardSection from "admin/components/admin-config-area-card-section";
|
||||
import SimpleList from "admin/components/simple-list";
|
||||
|
||||
export default class AdminLogoForm extends Component {
|
||||
export default class AdminBrandingLogoForm extends Component {
|
||||
@service siteSettings;
|
||||
@service siteSettingChangeTracker;
|
||||
@service toasts;
|
||||
|
||||
@tracked placeholders = {};
|
||||
@ -57,7 +56,7 @@ export default class AdminLogoForm extends Component {
|
||||
@action
|
||||
async save(data) {
|
||||
try {
|
||||
await ajax("/admin/config/logo.json", {
|
||||
await ajax("/admin/config/branding/logo.json", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
logo: data.logo,
|
||||
@ -79,10 +78,9 @@ export default class AdminLogoForm extends Component {
|
||||
this.toasts.success({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: i18n("admin.config.logo_and_fonts.logo.form.saved"),
|
||||
message: i18n("admin.config.branding.logo.form.saved"),
|
||||
},
|
||||
});
|
||||
this.siteSettingChangeTracker.refreshPage(data);
|
||||
} catch (err) {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
@ -131,13 +129,11 @@ export default class AdminLogoForm extends Component {
|
||||
>
|
||||
<form.Field
|
||||
@name="logo"
|
||||
@title={{i18n "admin.config.logo_and_fonts.logo.form.logo.title"}}
|
||||
@title={{i18n "admin.config.branding.logo.form.logo.title"}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo.help_text"
|
||||
"admin.config.branding.logo.form.logo.description"
|
||||
}}
|
||||
@helpText={{i18n "admin.config.branding.logo.form.logo.help_text"}}
|
||||
@onSet={{fn this.handleUpload "logo"}}
|
||||
as |field|
|
||||
>
|
||||
@ -145,9 +141,7 @@ export default class AdminLogoForm extends Component {
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="logo_dark_required"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_dark.required"
|
||||
}}
|
||||
@title={{i18n "admin.config.branding.logo.form.logo_dark.required"}}
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
@ -157,11 +151,9 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Section>
|
||||
<form.Field
|
||||
@name="logo_dark"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_dark.title"
|
||||
}}
|
||||
@title={{i18n "admin.config.branding.logo.form.logo_dark.title"}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_dark.help_text"
|
||||
"admin.config.branding.logo.form.logo_dark.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "logo_dark"}}
|
||||
as |field|
|
||||
@ -172,14 +164,12 @@ export default class AdminLogoForm extends Component {
|
||||
{{/if}}
|
||||
<form.Field
|
||||
@name="large_icon"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.large_icon.title"
|
||||
}}
|
||||
@title={{i18n "admin.config.branding.logo.form.large_icon.title"}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.large_icon.description"
|
||||
"admin.config.branding.logo.form.large_icon.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.large_icon.help_text"
|
||||
"admin.config.branding.logo.form.large_icon.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "large_icon"}}
|
||||
@placeholderUrl={{this.placeholders.large_icon}}
|
||||
@ -189,9 +179,9 @@ export default class AdminLogoForm extends Component {
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="favicon"
|
||||
@title={{i18n "admin.config.logo_and_fonts.logo.form.favicon.title"}}
|
||||
@title={{i18n "admin.config.branding.logo.form.favicon.title"}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.favicon.description"
|
||||
"admin.config.branding.logo.form.favicon.description"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "favicon"}}
|
||||
@placeholderUrl={{this.placeholders.favicon}}
|
||||
@ -201,14 +191,12 @@ export default class AdminLogoForm extends Component {
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="logo_small"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small.title"
|
||||
}}
|
||||
@title={{i18n "admin.config.branding.logo.form.logo_small.title"}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small.description"
|
||||
"admin.config.branding.logo.form.logo_small.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small.help_text"
|
||||
"admin.config.branding.logo.form.logo_small.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "logo_small"}}
|
||||
as |field|
|
||||
@ -218,7 +206,7 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="logo_small_dark_required"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small_dark.required"
|
||||
"admin.config.branding.logo.form.logo_small_dark.required"
|
||||
}}
|
||||
@format="full"
|
||||
as |field|
|
||||
@ -230,10 +218,10 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="logo_small_dark"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small_dark.title"
|
||||
"admin.config.branding.logo.form.logo_small_dark.title"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.logo_small_dark.help_text"
|
||||
"admin.config.branding.logo.form.logo_small_dark.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "logo_small_dark"}}
|
||||
as |field|
|
||||
@ -244,7 +232,7 @@ export default class AdminLogoForm extends Component {
|
||||
{{/if}}
|
||||
|
||||
<AdminConfigAreaCardSection
|
||||
@heading={{i18n "admin.config.logo_and_fonts.logo.form.mobile"}}
|
||||
@heading={{i18n "admin.config.branding.logo.form.mobile"}}
|
||||
class="admin-logo-form__mobile-section"
|
||||
@collapsable={{true}}
|
||||
@collapsed={{true}}
|
||||
@ -253,13 +241,13 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="mobile_logo"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo.title"
|
||||
"admin.config.branding.logo.form.mobile_logo.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo.description"
|
||||
"admin.config.branding.logo.form.mobile_logo.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo.help_text"
|
||||
"admin.config.branding.logo.form.mobile_logo.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "mobile_logo"}}
|
||||
@placeholderUrl={{this.placeholders.mobile_logo}}
|
||||
@ -270,7 +258,7 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="mobile_logo_dark_required"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo_dark.required"
|
||||
"admin.config.branding.logo.form.mobile_logo_dark.required"
|
||||
}}
|
||||
@format="full"
|
||||
as |field|
|
||||
@ -282,10 +270,10 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="mobile_logo_dark"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo_dark.title"
|
||||
"admin.config.branding.logo.form.mobile_logo_dark.title"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.mobile_logo_dark.help_text"
|
||||
"admin.config.branding.logo.form.mobile_logo_dark.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "mobile_logo_dark"}}
|
||||
as |field|
|
||||
@ -297,13 +285,13 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="manifest_icon"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.manifest_icon.title"
|
||||
"admin.config.branding.logo.form.manifest_icon.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.manifest_icon.description"
|
||||
"admin.config.branding.logo.form.manifest_icon.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.manifest_icon.help_text"
|
||||
"admin.config.branding.logo.form.manifest_icon.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "manifest_icon"}}
|
||||
as |field|
|
||||
@ -313,10 +301,10 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="manifest_screenshots"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.manifest_screenshots.title"
|
||||
"admin.config.branding.logo.form.manifest_screenshots.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.manifest_screenshots.description"
|
||||
"admin.config.branding.logo.form.manifest_screenshots.description"
|
||||
}}
|
||||
@format="full"
|
||||
as |field|
|
||||
@ -334,13 +322,13 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="apple_touch_icon"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.apple_touch_icon.title"
|
||||
"admin.config.branding.logo.form.apple_touch_icon.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.apple_touch_icon.description"
|
||||
"admin.config.branding.logo.form.apple_touch_icon.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.apple_touch_icon.help_text"
|
||||
"admin.config.branding.logo.form.apple_touch_icon.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "apple_touch_icon"}}
|
||||
@placeholderUrl={{this.placeholders.apple_touch_icon}}
|
||||
@ -351,7 +339,7 @@ export default class AdminLogoForm extends Component {
|
||||
</:content>
|
||||
</AdminConfigAreaCardSection>
|
||||
<AdminConfigAreaCardSection
|
||||
@heading={{i18n "admin.config.logo_and_fonts.logo.form.email"}}
|
||||
@heading={{i18n "admin.config.branding.logo.form.email"}}
|
||||
class="admin-logo-form__email-section"
|
||||
@collapsable={{true}}
|
||||
@collapsed={{true}}
|
||||
@ -360,13 +348,13 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="digest_logo"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.digest_logo.title"
|
||||
"admin.config.branding.logo.form.digest_logo.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.digest_logo.description"
|
||||
"admin.config.branding.logo.form.digest_logo.description"
|
||||
}}
|
||||
@helpText={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.digest_logo.help_text"
|
||||
"admin.config.branding.logo.form.digest_logo.help_text"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "digest_logo"}}
|
||||
@placeholderUrl={{this.placeholders.digest_logo}}
|
||||
@ -380,7 +368,7 @@ export default class AdminLogoForm extends Component {
|
||||
</:content>
|
||||
</AdminConfigAreaCardSection>
|
||||
<AdminConfigAreaCardSection
|
||||
@heading={{i18n "admin.config.logo_and_fonts.logo.form.social_media"}}
|
||||
@heading={{i18n "admin.config.branding.logo.form.social_media"}}
|
||||
class="admin-logo-form__social-media-section"
|
||||
@collapsable={{true}}
|
||||
@collapsed={{true}}
|
||||
@ -389,10 +377,10 @@ export default class AdminLogoForm extends Component {
|
||||
<form.Field
|
||||
@name="opengraph_image"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.opengraph_image.title"
|
||||
"admin.config.branding.logo.form.opengraph_image.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.logo.form.opengraph_image.description"
|
||||
"admin.config.branding.logo.form.opengraph_image.description"
|
||||
}}
|
||||
@onSet={{fn this.handleUpload "opengraph_image"}}
|
||||
@placeholderUrl={{this.placeholders.opengraph_image}}
|
@ -10,10 +10,10 @@ import DButton from "discourse/components/d-button";
|
||||
import Form from "discourse/components/form";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { API_KEY_SCOPE_MODES } from "discourse/lib/constants";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ApiKeyUrlsModal from "admin/components/modal/api-key-urls";
|
||||
import { API_KEY_SCOPE_MODES } from "admin/lib/constants";
|
||||
import EmailGroupUserChooser from "select-kit/components/email-group-user-chooser";
|
||||
|
||||
export default class AdminConfigAreasApiKeysNew extends Component {
|
||||
|
@ -207,12 +207,12 @@ export default class AdminConfigAreasColorPalette extends Component {
|
||||
/>
|
||||
</div>
|
||||
<form.Alert class="fonts-and-logos-hint">
|
||||
<div class="admin-config-color-palettes__logo-and-fonts-hint">
|
||||
<div class="admin-config-color-palettes__fonts-and-logos-hint">
|
||||
<span>{{i18n
|
||||
"admin.config_areas.color_palettes.logo_and_fonts_hint"
|
||||
"admin.config_areas.color_palettes.fonts_and_logos_hint"
|
||||
}}</span>
|
||||
<LinkTo @route="adminConfig.logo-and-fonts">{{i18n
|
||||
"admin.config_areas.color_palettes.go_to_logo_and_fonts"
|
||||
<LinkTo @route="adminConfig.branding">{{i18n
|
||||
"admin.config_areas.color_palettes.go_to_branding"
|
||||
}}</LinkTo>
|
||||
</div>
|
||||
</form.Alert>
|
||||
|
@ -1,71 +1,17 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { array, concat, hash } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DPageSubheader from "discourse/components/d-page-subheader";
|
||||
import DSelect from "discourse/components/d-select";
|
||||
import DToggleSwitch from "discourse/components/d-toggle-switch";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import FilterInput from "discourse/components/filter-input";
|
||||
import LoadMore from "discourse/components/load-more";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { extractErrorInfo } from "discourse/lib/ajax-error";
|
||||
import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import getURL from "discourse/lib/get-url";
|
||||
import { descriptionForRemoteUrl } from "discourse/lib/popular-themes";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigAreaEmptyList from "admin/components/admin-config-area-empty-list";
|
||||
import InstallThemeCard from "admin/components/admin-config-area-cards/install-theme-card";
|
||||
import InstallComponentModal from "admin/components/modal/install-theme";
|
||||
import ThemesGrid from "admin/components/themes-grid";
|
||||
import { COMPONENTS } from "admin/models/theme";
|
||||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
const STATUS_FILTER_OPTIONS = [
|
||||
{
|
||||
value: "all",
|
||||
label: "admin.config_areas.themes_and_components.components.filter_by_all",
|
||||
},
|
||||
{
|
||||
value: "used",
|
||||
label: "admin.config_areas.themes_and_components.components.filter_by_used",
|
||||
},
|
||||
{
|
||||
value: "unused",
|
||||
label:
|
||||
"admin.config_areas.themes_and_components.components.filter_by_unused",
|
||||
},
|
||||
{
|
||||
value: "updates_available",
|
||||
label:
|
||||
"admin.config_areas.themes_and_components.components.filter_by_updates_available",
|
||||
},
|
||||
];
|
||||
|
||||
export default class AdminConfigAreasComponents extends Component {
|
||||
@service modal;
|
||||
@service router;
|
||||
@service toasts;
|
||||
|
||||
@tracked loading = true;
|
||||
@tracked components = [];
|
||||
@tracked nameFilter;
|
||||
@tracked statusFilter;
|
||||
@tracked hasComponents = false;
|
||||
@tracked loadingMore = false;
|
||||
|
||||
page = 0;
|
||||
hasMore = false;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.load();
|
||||
}
|
||||
|
||||
@action
|
||||
installModal() {
|
||||
this.modal.show(InstallComponentModal, {
|
||||
@ -82,7 +28,7 @@ export default class AdminConfigAreasComponents extends Component {
|
||||
selectedType: COMPONENTS,
|
||||
userId: null,
|
||||
content: [],
|
||||
installedThemes: this.components,
|
||||
installedThemes: this.args.components,
|
||||
addTheme: this.addComponent,
|
||||
updateSelectedType: () => {},
|
||||
showComponentsOnly: true,
|
||||
@ -99,482 +45,19 @@ export default class AdminConfigAreasComponents extends Component {
|
||||
},
|
||||
duration: 2000,
|
||||
});
|
||||
this.load();
|
||||
}
|
||||
|
||||
@action
|
||||
onNameFilterChange(event) {
|
||||
this.loading = true;
|
||||
this.nameFilter = event.target.value;
|
||||
this.page = 0;
|
||||
discourseDebounce(this, this.load, INPUT_DELAY);
|
||||
}
|
||||
|
||||
@action
|
||||
onStatusFilterChange(value) {
|
||||
this.loading = true;
|
||||
this.statusFilter = value;
|
||||
this.page = 0;
|
||||
this.load();
|
||||
}
|
||||
|
||||
@action
|
||||
async load({ append = false } = {}) {
|
||||
try {
|
||||
const data = await ajax("/admin/config/customize/components", {
|
||||
data: {
|
||||
name: this.nameFilter,
|
||||
status: this.statusFilter,
|
||||
page: this.page,
|
||||
},
|
||||
});
|
||||
|
||||
if (append) {
|
||||
this.components = [...this.components, ...data.components];
|
||||
} else {
|
||||
this.components = data.components;
|
||||
}
|
||||
this.hasMore = data.has_more;
|
||||
|
||||
if (!this.hasComponents && !this.nameFilter && !this.statusFilter) {
|
||||
this.hasComponents = !!data.components.length;
|
||||
}
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async loadMore() {
|
||||
if (this.loadingMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hasMore) {
|
||||
this.page += 1;
|
||||
this.loadingMore = true;
|
||||
try {
|
||||
await this.load({ append: true });
|
||||
} finally {
|
||||
this.loadingMore = false;
|
||||
}
|
||||
}
|
||||
this.router.refresh();
|
||||
}
|
||||
|
||||
<template>
|
||||
<DPageSubheader
|
||||
@titleLabel={{i18n
|
||||
"admin.config_areas.themes_and_components.components.title"
|
||||
}}
|
||||
@descriptionLabel={{i18n
|
||||
"admin.config_areas.themes_and_components.components.description"
|
||||
}}
|
||||
>
|
||||
<:actions as |actions|>
|
||||
<actions.Primary
|
||||
disabled={{this.loading}}
|
||||
@label="admin.config_areas.themes_and_components.components.install"
|
||||
@action={{this.installModal}}
|
||||
/>
|
||||
</:actions>
|
||||
</DPageSubheader>
|
||||
<div class="container">
|
||||
{{#if this.hasComponents}}
|
||||
<div class="d-admin-filter">
|
||||
<div
|
||||
class="admin-filter__input-container admin-config-components__name-filter"
|
||||
>
|
||||
<FilterInput
|
||||
placeholder={{i18n
|
||||
"admin.config_areas.themes_and_components.components.search_components"
|
||||
}}
|
||||
@filterAction={{this.onNameFilterChange}}
|
||||
class="admin-filter__input"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label class="admin-config-components__status-filter">
|
||||
{{i18n
|
||||
"admin.config_areas.themes_and_components.components.filter_by"
|
||||
}}
|
||||
<DSelect
|
||||
@value="all"
|
||||
@includeNone={{false}}
|
||||
@onChange={{this.onStatusFilterChange}}
|
||||
as |select|
|
||||
>
|
||||
{{#each STATUS_FILTER_OPTIONS as |option|}}
|
||||
<select.Option @value={{option.value}}>
|
||||
{{i18n option.label}}
|
||||
</select.Option>
|
||||
{{/each}}
|
||||
</DSelect>
|
||||
</label>
|
||||
</div>
|
||||
{{/if}}
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#if this.components.length}}
|
||||
<LoadMore @selector=".component-list tr" @action={{this.loadMore}}>
|
||||
<table class="d-admin-table component-list">
|
||||
<thead>
|
||||
<th>{{i18n
|
||||
"admin.config_areas.themes_and_components.components.name"
|
||||
}}</th>
|
||||
<th>{{i18n
|
||||
"admin.config_areas.themes_and_components.components.used_on"
|
||||
}}</th>
|
||||
<th>{{i18n
|
||||
"admin.config_areas.themes_and_components.components.enabled"
|
||||
}}</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.components as |comp|}}
|
||||
<ComponentRow @component={{comp}} @refresh={{this.load}} />
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
<ConditionalLoadingSpinner @condition={{this.loadingMore}} />
|
||||
</LoadMore>
|
||||
{{else}}
|
||||
{{#if this.hasComponents}}
|
||||
{{i18n
|
||||
"admin.config_areas.themes_and_components.components.no_components_found"
|
||||
}}
|
||||
{{else}}
|
||||
<AdminConfigAreaEmptyList
|
||||
@emptyLabel="admin.config_areas.themes_and_components.components.no_components"
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
||||
<div class="admin-detail">
|
||||
<ThemesGrid @themes={{@components}}>
|
||||
<:specialCard>
|
||||
<InstallThemeCard
|
||||
@component={{true}}
|
||||
@openModal={{this.installModal}}
|
||||
/>
|
||||
</:specialCard>
|
||||
</ThemesGrid>
|
||||
</div>
|
||||
</template>
|
||||
}
|
||||
|
||||
class ComponentRow extends Component {
|
||||
@service toasts;
|
||||
@service dialog;
|
||||
|
||||
@tracked enabled = this.args.component.enabled;
|
||||
@tracked hasUpdates = this.args.component.remote_theme?.commits_behind > 0;
|
||||
@tracked disableToggle = false;
|
||||
@tracked checkingForUpdates = false;
|
||||
@tracked updating = false;
|
||||
|
||||
get parentThemesCell() {
|
||||
const names = this.args.component.parent_themes.map((theme) => theme.name);
|
||||
names.sort();
|
||||
|
||||
if (!names.length) {
|
||||
return;
|
||||
} else if (names.length === 1) {
|
||||
return names[0];
|
||||
} else if (names.length === 2) {
|
||||
return i18n(
|
||||
"admin.config_areas.themes_and_components.components.parent_themes_two",
|
||||
{
|
||||
name1: names[0],
|
||||
name2: names[1],
|
||||
}
|
||||
);
|
||||
} else if (names.length === 3) {
|
||||
return i18n(
|
||||
"admin.config_areas.themes_and_components.components.parent_themes_three",
|
||||
{
|
||||
name1: names[0],
|
||||
name2: names[1],
|
||||
name3: names[2],
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return i18n(
|
||||
"admin.config_areas.themes_and_components.components.parent_themes_more_than_three",
|
||||
{
|
||||
name1: names[0],
|
||||
name2: names[1],
|
||||
name3: names[2],
|
||||
count: names.length - 3,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
get description() {
|
||||
const remoteUrl = this.args.component.remote_theme?.remote_url;
|
||||
return (
|
||||
this.args.component.description ??
|
||||
(remoteUrl && descriptionForRemoteUrl(remoteUrl))
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
async toggleEnabled() {
|
||||
this.disableToggle = true;
|
||||
try {
|
||||
const data = await this.save({ enabled: !this.enabled });
|
||||
this.enabled = data.theme.enabled;
|
||||
} finally {
|
||||
this.disableToggle = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async checkForUpdates() {
|
||||
this.checkingForUpdates = true;
|
||||
|
||||
try {
|
||||
const data = await this.save({ remote_check: true });
|
||||
if (data.theme.remote_theme.commits_behind > 0) {
|
||||
this.hasUpdates = true;
|
||||
this.toasts.default({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: i18n(
|
||||
"admin.config_areas.themes_and_components.components.new_update_for_component",
|
||||
{ name: this.args.component.name }
|
||||
),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.hasUpdates = false;
|
||||
this.toasts.default({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: i18n(
|
||||
"admin.config_areas.themes_and_components.components.component_up_to_date",
|
||||
{ name: this.args.component.name }
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
this.checkingForUpdates = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async updateToLatest() {
|
||||
this.updating = true;
|
||||
|
||||
try {
|
||||
await this.save({ remote_update: true });
|
||||
this.hasUpdates = false;
|
||||
this.toasts.success({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: i18n(
|
||||
"admin.config_areas.themes_and_components.components.updated_successfully",
|
||||
{ name: this.args.component.name }
|
||||
),
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
this.updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
delete() {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: i18n(
|
||||
"admin.config_areas.themes_and_components.components.delete_confirm",
|
||||
{ name: this.args.component.name }
|
||||
),
|
||||
didConfirm: async () => {
|
||||
try {
|
||||
await ajax(`/admin/themes/${this.args.component.id}`, {
|
||||
type: "DELETE",
|
||||
});
|
||||
this.toasts.success({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: i18n(
|
||||
"admin.config_areas.themes_and_components.components.deleted_successfully",
|
||||
{ name: this.args.component.name }
|
||||
),
|
||||
},
|
||||
});
|
||||
this.args.refresh();
|
||||
} catch (error) {
|
||||
this.toasts.error({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: extractErrorInfo(error),
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async save(attrs) {
|
||||
try {
|
||||
return await ajax(`/admin/themes/${this.args.component.id}.json`, {
|
||||
type: "PUT",
|
||||
data: {
|
||||
theme: attrs,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
this.toasts.error({
|
||||
duration: 5000,
|
||||
data: {
|
||||
message: extractErrorInfo(error),
|
||||
},
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
<tr
|
||||
data-component-id={{@component.id}}
|
||||
class="d-admin-row__content admin-config-components__component-row
|
||||
{{if this.hasUpdates 'has-update'}}"
|
||||
>
|
||||
<td class="d-admin-row__overview">
|
||||
<div class="d-admin-row__overview-name">
|
||||
{{@component.name}}
|
||||
</div>
|
||||
{{#if @component.remote_theme.authors}}
|
||||
<div
|
||||
class="d-admin-row__overview-author admin-config-components__author-name"
|
||||
>{{i18n
|
||||
"admin.config_areas.themes_and_components.components.by_author"
|
||||
(hash name=@component.remote_theme.authors)
|
||||
}}</div>
|
||||
{{/if}}
|
||||
{{#if this.description}}
|
||||
<div
|
||||
class="d-admin-row__overview-about admin-config-components__description"
|
||||
>
|
||||
{{this.description}}
|
||||
{{#if @component.remote_theme.about_url}}
|
||||
<a href={{@component.remote_theme.about_url}}>{{i18n
|
||||
"admin.config_areas.themes_and_components.components.learn_more"
|
||||
}}
|
||||
{{icon "up-right-from-square"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.hasUpdates}}
|
||||
<div
|
||||
class="d-admin-row__overview-about admin-config-components__update-available"
|
||||
>
|
||||
{{i18n
|
||||
"admin.config_areas.themes_and_components.components.update_available"
|
||||
}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td class="d-admin-row__detail admin-config-components__parent-themes">
|
||||
<div class="d-admin-row__mobile-label">
|
||||
{{i18n "admin.config_areas.themes_and_components.components.used_on"}}
|
||||
</div>
|
||||
<div class="admin-config-components__parent-themes-list">
|
||||
{{#if @component.parent_themes.length}}
|
||||
{{this.parentThemesCell}}
|
||||
{{else}}
|
||||
<div class="status-label --inactive">
|
||||
<div class="status-label-indicator"></div>
|
||||
<div class="status-label-text">
|
||||
{{i18n
|
||||
"admin.config_areas.themes_and_components.components.badge_unused"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
<td class="d-admin-row__detail">
|
||||
<div class="d-admin-row__mobile-label">
|
||||
{{i18n "admin.config_areas.themes_and_components.components.enabled"}}
|
||||
</div>
|
||||
<DToggleSwitch
|
||||
@state={{this.enabled}}
|
||||
class="admin-config-components__toggle"
|
||||
disabled={{this.disableToggle}}
|
||||
{{on "click" this.toggleEnabled}}
|
||||
/>
|
||||
</td>
|
||||
<td class="d-admin-row__controls">
|
||||
<div class="d-admin-row__controls-options">
|
||||
<DButton
|
||||
class="admin-config-components__edit"
|
||||
@label="admin.config_areas.themes_and_components.components.edit"
|
||||
@route="adminCustomizeThemes.show"
|
||||
@routeModels={{array "themes" @component.id}}
|
||||
/>
|
||||
<DMenu
|
||||
@identifier="component-menu"
|
||||
@title={{i18n "admin.config_areas.flags.more_options.title"}}
|
||||
@icon="ellipsis"
|
||||
@class="btn-default admin-config-components__more-actions"
|
||||
>
|
||||
<:content>
|
||||
<DropdownMenu as |dropdown|>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
class="btn-transparent admin-config-components__preview"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@label="admin.config_areas.themes_and_components.components.preview"
|
||||
@icon="desktop"
|
||||
@href={{getURL
|
||||
(concat "/admin/themes/" @component.id "/preview")
|
||||
}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{#if @component.remote_theme.is_git}}
|
||||
<dropdown.item>
|
||||
{{#if this.hasUpdates}}
|
||||
<DButton
|
||||
class="btn-transparent admin-config-components__update"
|
||||
@label="admin.config_areas.themes_and_components.components.update"
|
||||
@icon="cloud-arrow-down"
|
||||
@action={{this.updateToLatest}}
|
||||
@isLoading={{this.updating}}
|
||||
/>
|
||||
{{else}}
|
||||
<DButton
|
||||
class="btn-transparent admin-config-components__check-updates"
|
||||
@label="admin.config_areas.themes_and_components.components.check_update"
|
||||
@icon="arrows-rotate"
|
||||
@action={{this.checkForUpdates}}
|
||||
@isLoading={{this.checkingForUpdates}}
|
||||
/>
|
||||
{{/if}}
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
class="btn-transparent admin-config-components__export"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@label="admin.config_areas.themes_and_components.components.export"
|
||||
@icon="download"
|
||||
@href={{getURL
|
||||
(concat
|
||||
"/admin/customize/themes/" @component.id "/export"
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
class="btn-danger admin-config-components__delete"
|
||||
@label="admin.config_areas.themes_and_components.components.delete"
|
||||
@icon="trash-can"
|
||||
@action={{this.delete}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
</DropdownMenu>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { SYSTEM_FLAG_IDS } from "discourse/lib/constants";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminFlagItem from "admin/components/admin-flag-item";
|
||||
import { SYSTEM_FLAG_IDS } from "admin/lib/constants";
|
||||
|
||||
export default class AdminConfigAreasFlags extends Component {
|
||||
@service site;
|
||||
|
@ -12,8 +12,8 @@ import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { SYSTEM_FLAG_IDS } from "discourse/lib/constants";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { SYSTEM_FLAG_IDS } from "admin/lib/constants";
|
||||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
export default class AdminFlagItem extends Component {
|
||||
@ -28,11 +28,10 @@ export default class AdminFlagItem extends Component {
|
||||
}
|
||||
|
||||
get canEdit() {
|
||||
return !Object.values(SYSTEM_FLAG_IDS).includes(this.args.flag.id);
|
||||
}
|
||||
|
||||
get canDelete() {
|
||||
return this.canEdit && !this.args.flag.is_used;
|
||||
return (
|
||||
!Object.values(SYSTEM_FLAG_IDS).includes(this.args.flag.id) &&
|
||||
!this.args.flag.is_used
|
||||
);
|
||||
}
|
||||
|
||||
get editTitle() {
|
||||
@ -42,9 +41,9 @@ export default class AdminFlagItem extends Component {
|
||||
}
|
||||
|
||||
get deleteTitle() {
|
||||
return this.canDelete
|
||||
? "admin.config_areas.flags.form.delete_flag"
|
||||
: "admin.config_areas.flags.form.non_deletable";
|
||||
return this.canEdit
|
||||
? "admin.config_areas.flags.form.edit_flag"
|
||||
: "admin.config_areas.flags.form.non_editable";
|
||||
}
|
||||
|
||||
@action
|
||||
@ -192,7 +191,7 @@ export default class AdminFlagItem extends Component {
|
||||
@icon="trash-can"
|
||||
class="btn-transparent btn-danger admin-flag-item__delete"
|
||||
@action={{this.delete}}
|
||||
@disabled={{not this.canDelete}}
|
||||
@disabled={{not this.canEdit}}
|
||||
@title={{this.deleteTitle}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
|
@ -133,14 +133,6 @@ export default class AdminFlagsForm extends Component {
|
||||
<AdminConfigAreaCard @heading={{this.header}}>
|
||||
<:content>
|
||||
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>
|
||||
<form.Alert @type="warning" @icon="circle-info">
|
||||
{{#if this.isUpdate}}
|
||||
{{i18n "admin.config_areas.flags.form.edit_warning"}}
|
||||
{{else}}
|
||||
{{i18n "admin.config_areas.flags.form.create_warning"}}
|
||||
{{/if}}
|
||||
</form.Alert>
|
||||
|
||||
<form.Field
|
||||
@name="name"
|
||||
@title={{i18n "admin.config_areas.flags.form.name"}}
|
||||
@ -218,6 +210,10 @@ export default class AdminFlagsForm extends Component {
|
||||
</checkboxGroup.Field>
|
||||
</form.CheckboxGroup>
|
||||
|
||||
<form.Alert @icon="circle-info">
|
||||
{{i18n "admin.config_areas.flags.form.alert"}}
|
||||
</form.Alert>
|
||||
|
||||
<form.Submit @label="admin.config_areas.flags.form.save" />
|
||||
</Form>
|
||||
</:content>
|
||||
|
@ -1,63 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { concat, fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { dasherize } from "@ember/string";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { MAIN_FONTS, MORE_FONTS } from "admin/lib/constants";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
export default class AdminFontChooser extends Component {
|
||||
@tracked showMoreFonts = MORE_FONTS.map((font) => font.key).includes(
|
||||
this.args.selectedFont
|
||||
);
|
||||
|
||||
@action
|
||||
setButtonValue(fieldSet, value) {
|
||||
fieldSet(value);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleMoreFonts() {
|
||||
this.showMoreFonts = !this.showMoreFonts;
|
||||
}
|
||||
|
||||
<template>
|
||||
<@field.Custom>
|
||||
{{#each MAIN_FONTS as |font|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue @field.set font.key}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option font btn-flat"
|
||||
(concat "body-font-" (dasherize font.key))
|
||||
(if (eq @selectedFont font.key) "active")
|
||||
}}
|
||||
>{{font.name}}</DButton>
|
||||
{{/each}}
|
||||
{{#if this.showMoreFonts}}
|
||||
{{#each MORE_FONTS as |font|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue @field.set font.key}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option font btn-flat"
|
||||
(concat "body-font-" (dasherize font.key))
|
||||
(if (eq @selectedFont font.key) "active")
|
||||
}}
|
||||
>{{font.name}}</DButton>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
<DButton
|
||||
@action={{this.toggleMoreFonts}}
|
||||
class="admin-fonts-form__more font"
|
||||
>
|
||||
{{#if this.showMoreFonts}}
|
||||
{{i18n "admin.config.logo_and_fonts.fonts.form.less_fonts"}}
|
||||
{{else}}
|
||||
{{i18n "admin.config.logo_and_fonts.fonts.form.more_fonts"}}
|
||||
{{/if}}
|
||||
</DButton>
|
||||
</@field.Custom>
|
||||
</template>
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { decamelize, underscore } from "@ember/string";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import Form from "discourse/components/form";
|
||||
import UpdateDefaultTextSize from "discourse/components/modal/update-default-text-size";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminFontChooser from "admin/components/admin-font-chooser";
|
||||
import {
|
||||
DEFAULT_TEXT_SIZES,
|
||||
MAIN_FONTS,
|
||||
MORE_FONTS,
|
||||
} from "admin/lib/constants";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
const ALL_FONTS = [...MAIN_FONTS, ...MORE_FONTS];
|
||||
export default class AdminFontsForm extends Component {
|
||||
@service siteSettings;
|
||||
@service siteSettingChangeTracker;
|
||||
@service toasts;
|
||||
@service modal;
|
||||
@service router;
|
||||
|
||||
updateExistingUsers = null;
|
||||
|
||||
@bind
|
||||
setUpdateExistingUsers(value) {
|
||||
this.updateExistingUsers = value;
|
||||
}
|
||||
|
||||
@action
|
||||
setButtonValue(fieldSet, value) {
|
||||
fieldSet(decamelize(underscore(value)));
|
||||
}
|
||||
|
||||
@action
|
||||
async update(data) {
|
||||
if (this.siteSettings.default_text_size === data.default_text_size) {
|
||||
await this.#save(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ajax(
|
||||
`/admin/site_settings/default_text_size/user_count.json`,
|
||||
{
|
||||
type: "PUT",
|
||||
data: {
|
||||
default_text_size: data.default_text_size,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const count = result.user_count;
|
||||
if (count > 0) {
|
||||
await this.modal.show(UpdateDefaultTextSize, {
|
||||
model: {
|
||||
setUpdateExistingUsers: this.setUpdateExistingUsers,
|
||||
count,
|
||||
},
|
||||
});
|
||||
await this.#save(data);
|
||||
} else {
|
||||
await this.#save(data);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async #save(data) {
|
||||
try {
|
||||
await ajax("/admin/config/fonts.json", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
base_font: data.base_font,
|
||||
heading_font: data.heading_font,
|
||||
default_text_size: data.default_text_size,
|
||||
update_existing_users: this.updateExistingUsers,
|
||||
},
|
||||
});
|
||||
this.toasts.success({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: i18n("admin.config.logo_and_fonts.fonts.form.saved"),
|
||||
},
|
||||
});
|
||||
this.siteSettingChangeTracker.refreshPage({
|
||||
base_font: ALL_FONTS.find((font) => font.key === data.base_font).name,
|
||||
heading_font: ALL_FONTS.find((font) => font.key === data.heading_font)
|
||||
.name,
|
||||
default_text_size: data.default_text_size,
|
||||
});
|
||||
} catch (err) {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: err.jqXHR.responseJSON.errors[0],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get formData() {
|
||||
return {
|
||||
base_font: this.siteSettings.base_font,
|
||||
heading_font: this.siteSettings.heading_font,
|
||||
default_text_size: this.siteSettings.default_text_size,
|
||||
};
|
||||
}
|
||||
|
||||
<template>
|
||||
<Form
|
||||
@onSubmit={{this.update}}
|
||||
@data={{this.formData}}
|
||||
class="admin-fonts-form"
|
||||
as |form transientData|
|
||||
>
|
||||
<form.Field
|
||||
@name="base_font"
|
||||
@title={{i18n "admin.config.logo_and_fonts.fonts.form.base_font.title"}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<AdminFontChooser
|
||||
@field={{field}}
|
||||
@selectedFont={{transientData.base_font}}
|
||||
/>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="heading_font"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.fonts.form.heading_font.title"
|
||||
}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<AdminFontChooser
|
||||
@field={{field}}
|
||||
@selectedFont={{transientData.heading_font}}
|
||||
/>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="default_text_size"
|
||||
@title={{i18n
|
||||
"admin.config.logo_and_fonts.fonts.form.default_text_size.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.logo_and_fonts.fonts.form.default_text_size.description"
|
||||
}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<field.Custom>
|
||||
{{#each DEFAULT_TEXT_SIZES as |textSize|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue field.set textSize}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option text-size btn-flat"
|
||||
textSize
|
||||
(if (eq transientData.default_text_size textSize) "active")
|
||||
}}
|
||||
>{{textSize}}</DButton>
|
||||
{{/each}}
|
||||
</field.Custom>
|
||||
</form.Field>
|
||||
<form.Submit />
|
||||
</Form>
|
||||
</template>
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import Component from "@ember/component";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { eq } from "truth-helpers";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
@classNames("row")
|
||||
export default class AdminFormRow extends Component {
|
||||
|
@ -0,0 +1,25 @@
|
||||
// TODO (martin) Delete this once we have removed references from plugins.
|
||||
|
||||
import {
|
||||
DangerActionListItem,
|
||||
DangerButton,
|
||||
DefaultActionListItem,
|
||||
DefaultButton,
|
||||
DPageActionButton,
|
||||
DPageActionListItem,
|
||||
PrimaryActionListItem,
|
||||
PrimaryButton,
|
||||
WrappedActionListItem,
|
||||
WrappedButton,
|
||||
} from "discourse/components/d-page-action-button";
|
||||
|
||||
export { DangerActionListItem as DangerActionListItem };
|
||||
export { DangerButton as DangerButton };
|
||||
export { DefaultActionListItem as DefaultActionListItem };
|
||||
export { DefaultButton as DefaultButton };
|
||||
export { DPageActionButton as DPageActionButton };
|
||||
export { DPageActionListItem as DPageActionListItem };
|
||||
export { PrimaryActionListItem as PrimaryActionListItem };
|
||||
export { PrimaryButton as PrimaryButton };
|
||||
export { WrappedActionListItem as WrappedActionListItem };
|
||||
export { WrappedButton as WrappedButton };
|
@ -2,12 +2,12 @@ import Component, { Textarea } from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import { eq } from "truth-helpers";
|
||||
import TextField from "discourse/components/text-field";
|
||||
import htmlSafe from "discourse/helpers/html-safe";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
const CUSTOM_REASON_KEY = "custom";
|
||||
|
||||
|
@ -4,7 +4,6 @@ import { Input } from "@ember/component";
|
||||
import { fn, get, hash } from "@ember/helper";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { not } from "truth-helpers";
|
||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||
import avatar from "discourse/helpers/avatar";
|
||||
import formatDuration from "discourse/helpers/format-duration";
|
||||
@ -12,6 +11,7 @@ import htmlSafe from "discourse/helpers/html-safe";
|
||||
import number from "discourse/helpers/number";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import not from "truth-helpers/helpers/not";
|
||||
|
||||
export default class AdminPenaltySimilarUsers extends Component {
|
||||
@tracked isLoading;
|
||||
|
@ -15,6 +15,7 @@ import concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import number from "discourse/helpers/number";
|
||||
import { reportModeComponent } from "discourse/lib/admin-report-additional-modes";
|
||||
import { REPORT_MODES } from "discourse/lib/constants";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { isTesting } from "discourse/lib/environment";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
@ -34,7 +35,6 @@ import ReportFilterBoolComponent from "admin/components/report-filters/bool";
|
||||
import ReportFilterCategoryComponent from "admin/components/report-filters/category";
|
||||
import ReportFilterGroupComponent from "admin/components/report-filters/group";
|
||||
import ReportFilterListComponent from "admin/components/report-filters/list";
|
||||
import { REPORT_MODES } from "admin/lib/constants";
|
||||
import Report, { DAILY_LIMIT_DAYS, SCHEMA_VERSION } from "admin/models/report";
|
||||
import DTooltip from "float-kit/components/d-tooltip";
|
||||
|
||||
|
@ -9,12 +9,12 @@ import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { ADMIN_SEARCH_RESULT_TYPES } from "discourse/lib/constants";
|
||||
import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import autoFocus from "discourse/modifiers/auto-focus";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminSearchFilters from "admin/components/admin-search-filters";
|
||||
import { ADMIN_SEARCH_RESULT_TYPES } from "admin/lib/constants";
|
||||
|
||||
const ADMIN_SEARCH_FILTERS = "admin_search_filters";
|
||||
|
||||
|
@ -1,109 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
|
||||
import { service } from "@ember/service";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import htmlSafe from "discourse/helpers/html-safe";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminSiteSettingsChangesBanner extends Component {
|
||||
@service siteSettingChangeTracker;
|
||||
|
||||
@tracked isSaving = false;
|
||||
_resizer = null;
|
||||
|
||||
@action
|
||||
async save() {
|
||||
this.isSaving = true;
|
||||
|
||||
try {
|
||||
await this.siteSettingChangeTracker.save();
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
discard() {
|
||||
this.siteSettingChangeTracker.discard();
|
||||
}
|
||||
|
||||
@action
|
||||
setupResizeObserver(element) {
|
||||
const container = document.getElementById("main-container");
|
||||
this._resizer = () => this.positionBanner(container, element);
|
||||
|
||||
this._resizer();
|
||||
|
||||
this._resizeObserver = window.addEventListener("resize", this._resizer);
|
||||
}
|
||||
|
||||
@action
|
||||
teardownResizeObserver() {
|
||||
window.removeEventListener("resize", this._resizer);
|
||||
}
|
||||
|
||||
positionBanner(container, element) {
|
||||
if (container) {
|
||||
const { width } = container.getBoundingClientRect();
|
||||
|
||||
element.style.width = `${width}px`;
|
||||
}
|
||||
}
|
||||
|
||||
get dirtyCount() {
|
||||
return this.siteSettingChangeTracker.count;
|
||||
}
|
||||
|
||||
get showBanner() {
|
||||
return this.dirtyCount > 0;
|
||||
}
|
||||
|
||||
get bannerLabel() {
|
||||
return i18n("admin.site_settings.dirty_banner", {
|
||||
count: this.dirtyCount,
|
||||
});
|
||||
}
|
||||
|
||||
get saveLabel() {
|
||||
return i18n("admin.site_settings.save", {
|
||||
count: this.dirtyCount,
|
||||
});
|
||||
}
|
||||
|
||||
get discardLabel() {
|
||||
return i18n("admin.site_settings.discard", {
|
||||
count: this.dirtyCount,
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if this.showBanner}}
|
||||
<div
|
||||
class="admin-site-settings__changes-banner"
|
||||
{{didInsert this.setupResizeObserver}}
|
||||
{{willDestroy this.teardownResizeObserver}}
|
||||
>
|
||||
<span>{{htmlSafe this.bannerLabel}}</span>
|
||||
<div class="controls">
|
||||
<DButton
|
||||
@action={{this.discard}}
|
||||
@disabled={{this.isSaving}}
|
||||
class="btn-secondary btn-small"
|
||||
>
|
||||
{{this.discardLabel}}
|
||||
</DButton>
|
||||
<DButton
|
||||
@action={{this.save}}
|
||||
@isLoading={{this.isSaving}}
|
||||
class="btn-primary btn-small"
|
||||
>
|
||||
{{this.saveLabel}}
|
||||
</DButton>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
@ -6,7 +6,6 @@ import { action, computed } from "@ember/object";
|
||||
import { LinkTo } from "@ember/routing";
|
||||
import { next } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { gt, lte } from "truth-helpers";
|
||||
import AceEditor from "discourse/components/ace-editor";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import htmlSafe from "discourse/helpers/html-safe";
|
||||
@ -14,6 +13,8 @@ import { fmt } from "discourse/lib/computed";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import gt from "truth-helpers/helpers/gt";
|
||||
import lte from "truth-helpers/helpers/lte";
|
||||
|
||||
const JS_DEFAULT_VALUE = `import { apiInitializer } from "discourse/lib/api";
|
||||
|
||||
|
@ -4,8 +4,8 @@ import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import { USER_FIELD_FLAGS } from "discourse/lib/constants";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { USER_FIELD_FLAGS } from "admin/lib/constants";
|
||||
import UserField from "admin/models/user-field";
|
||||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
|
@ -5,13 +5,13 @@ import { action, set, setProperties } from "@ember/object";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import { service } from "@ember/service";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { not } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import EmojiPicker from "discourse/components/emoji-picker";
|
||||
import EmojiPickerDetached from "discourse/components/emoji-picker/detached";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import { emojiUrlFor } from "discourse/lib/text";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import not from "truth-helpers/helpers/not";
|
||||
|
||||
@classNameBindings(":value-list", ":emoji-list")
|
||||
export default class EmojiValueList extends Component {
|
||||
|
@ -0,0 +1,57 @@
|
||||
import Component from "@ember/component";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import UserFlagPercentage from "discourse/components/user-flag-percentage";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import FlagUser from "admin/components/flag-user";
|
||||
import dispositionIcon from "admin/helpers/disposition-icon";
|
||||
import postActionTitle from "admin/helpers/post-action-title";
|
||||
|
||||
@classNames("flag-user-lists")
|
||||
export default class FlagUserLists extends Component {
|
||||
<template>
|
||||
<div class="flagged-by">
|
||||
<div class="user-list-title">
|
||||
{{i18n "admin.flags.flagged_by"}}
|
||||
</div>
|
||||
<div class="flag-users">
|
||||
{{#each this.flaggedPost.post_actions as |postAction|}}
|
||||
<FlagUser @user={{postAction.user}} @date={{postAction.created_at}}>
|
||||
<div class="flagger-flag-type">
|
||||
{{postActionTitle
|
||||
postAction.post_action_type_id
|
||||
postAction.name_key
|
||||
}}
|
||||
</div>
|
||||
<UserFlagPercentage
|
||||
@agreed={{postAction.user.flags_agreed}}
|
||||
@disagreed={{postAction.user.flags_disagreed}}
|
||||
@ignored={{postAction.user.flags_ignored}}
|
||||
/>
|
||||
</FlagUser>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.showResolvedBy}}
|
||||
<div class="flagged-post-resolved-by">
|
||||
<div class="user-list-title">
|
||||
{{i18n "admin.flags.resolved_by"}}
|
||||
</div>
|
||||
<div class="flag-users">
|
||||
{{#each this.flaggedPost.post_actions as |postAction|}}
|
||||
<FlagUser
|
||||
@user={{postAction.disposed_by}}
|
||||
@date={{postAction.disposed_at}}
|
||||
>
|
||||
{{dispositionIcon postAction.disposition}}
|
||||
{{#if postAction.staff_took_action}}
|
||||
{{icon "gavel" title="admin.flags.took_action"}}
|
||||
{{/if}}
|
||||
</FlagUser>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
@ -49,10 +49,6 @@ export default class FormTemplateForm extends Component {
|
||||
type: "multiselect",
|
||||
icon: "bullseye",
|
||||
},
|
||||
{
|
||||
type: "tagchooser",
|
||||
icon: "bullseye",
|
||||
},
|
||||
];
|
||||
|
||||
get disablePreviewButton() {
|
||||
|
@ -4,7 +4,6 @@ import { fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { eq } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import FutureDateInput from "discourse/components/future-date-input";
|
||||
@ -14,6 +13,7 @@ import I18n, { i18n } from "discourse-i18n";
|
||||
import AdminPenaltyPostAction from "admin/components/admin-penalty-post-action";
|
||||
import AdminPenaltyReason from "admin/components/admin-penalty-reason";
|
||||
import AdminPenaltySimilarUsers from "admin/components/admin-penalty-similar-users";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
export default class PenalizeUser extends Component {
|
||||
@service dialog;
|
||||
|
@ -1,63 +0,0 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import TextField from "discourse/components/text-field";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class ScrubRejectedUserModal extends Component {
|
||||
@tracked isScrubbing = false;
|
||||
@tracked scrubReason = "";
|
||||
|
||||
@action
|
||||
async confirmScrub() {
|
||||
this.isScrubbing = true;
|
||||
await this.args.model.confirmScrub(this.scrubReason);
|
||||
this.args.closeModal();
|
||||
}
|
||||
|
||||
get scrubButtonDisabled() {
|
||||
return isEmpty(this.scrubReason);
|
||||
}
|
||||
|
||||
<template>
|
||||
<DModal
|
||||
@bodyClass="scrub-rejected-user"
|
||||
class="admin-scrub-rejected-user-modal"
|
||||
@title={{i18n "review.user.scrub_record.confirm_title"}}
|
||||
@closeModal={{if this.isScrubbing null @closeModal}}
|
||||
>
|
||||
<:body>
|
||||
<p>{{i18n "review.user.scrub_record.confirm_body"}}</p>
|
||||
<label class="scrub-reason-title" for="scrub-reason">{{i18n
|
||||
"review.user.scrub_record.reason_title"
|
||||
}}</label>
|
||||
|
||||
<TextField
|
||||
class="scrub-reason"
|
||||
id="scrub-reason"
|
||||
@placeholderKey="review.user.scrub_record.reason_placeholder"
|
||||
{{on "input" (action (mut this.scrubReason) value="target.value")}}
|
||||
/>
|
||||
</:body>
|
||||
<:footer>
|
||||
<DButton
|
||||
class="btn btn-danger"
|
||||
@action={{this.confirmScrub}}
|
||||
@isLoading={{this.isScrubbing}}
|
||||
@disabled={{this.scrubButtonDisabled}}
|
||||
@label="review.user.scrub_record.confirm_button"
|
||||
/>
|
||||
<DButton
|
||||
class="btn btn-default"
|
||||
@action={{@closeModal}}
|
||||
@disabled={{this.isScrubbing}}
|
||||
@label="review.user.scrub_record.cancel_button"
|
||||
/>
|
||||
</:footer>
|
||||
</DModal>
|
||||
</template>
|
||||
}
|
@ -6,11 +6,11 @@ import { action } from "@ember/object";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { gt } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
import gt from "truth-helpers/helpers/gt";
|
||||
|
||||
@classNameBindings(":simple-list", ":value-list")
|
||||
export default class SimpleList extends Component {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { cached, tracked } from "@glimmer/tracking";
|
||||
import Component from "@ember/component";
|
||||
import { hash } from "@ember/helper";
|
||||
import { dependentKeyCompat } from "@ember/object/compat";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import { getOwner } from "@ember/owner";
|
||||
import { LinkTo } from "@ember/routing";
|
||||
import BufferedProxy from "ember-buffered-proxy/proxy";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import icon from "discourse/helpers/d-icon";
|
||||
import { i18n } from "discourse-i18n";
|
||||
@ -27,15 +28,18 @@ export default class SiteSettingComponent extends Component.extend(
|
||||
);
|
||||
}
|
||||
|
||||
@cached
|
||||
@dependentKeyCompat
|
||||
get buffered() {
|
||||
return this.setting.buffered;
|
||||
return BufferedProxy.create({
|
||||
content: this.setting,
|
||||
});
|
||||
}
|
||||
|
||||
_save() {
|
||||
const setting = this.buffered;
|
||||
return SiteSetting.update(setting.get("setting"), setting.get("value"), {
|
||||
updateExistingUsers: this.setting.updateExistingUsers,
|
||||
updateExistingUsers: this.updateExistingUsers,
|
||||
});
|
||||
}
|
||||
|
||||
@ -86,7 +90,7 @@ export default class SiteSettingComponent extends Component.extend(
|
||||
@changeValueCallback={{this.changeValueCallback}}
|
||||
@setValidationMessage={{this.setValidationMessage}}
|
||||
/>
|
||||
<SettingValidationMessage @message={{this.setting.validationMessage}} />
|
||||
<SettingValidationMessage @message={{this.validationMessage}} />
|
||||
{{#if this.displayDescription}}
|
||||
<Description @description={{this.setting.description}} />
|
||||
{{/if}}
|
||||
@ -98,14 +102,13 @@ export default class SiteSettingComponent extends Component.extend(
|
||||
<DButton
|
||||
@action={{this.update}}
|
||||
@icon="check"
|
||||
@isLoading={{this.disableControls}}
|
||||
@disabled={{this.disableSaveButton}}
|
||||
@ariaLabel="admin.settings.save"
|
||||
class="ok setting-controls__ok"
|
||||
/>
|
||||
<DButton
|
||||
@action={{this.cancel}}
|
||||
@icon="xmark"
|
||||
@isLoading={{this.disableControls}}
|
||||
@ariaLabel="admin.settings.cancel"
|
||||
class="cancel setting-controls__cancel"
|
||||
/>
|
||||
|
@ -1,10 +1,7 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { eq } from "truth-helpers";
|
||||
|
||||
export default class ThemesGridPlaceholder extends Component {
|
||||
randomVariant = Math.floor(Math.random() * 4);
|
||||
|
||||
get themeColors() {
|
||||
if (this.args.theme.color_scheme) {
|
||||
return {
|
||||
@ -31,305 +28,59 @@ export default class ThemesGridPlaceholder extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
get safeThemeColors() {
|
||||
let colors = this.themeColors;
|
||||
|
||||
return {
|
||||
primary: htmlSafe(colors.primary),
|
||||
secondary: htmlSafe(colors.secondary),
|
||||
tertiary: htmlSafe(colors.tertiary),
|
||||
quaternary: htmlSafe(colors.quaternary),
|
||||
highlight: htmlSafe(colors.highlight),
|
||||
danger: htmlSafe(colors.danger),
|
||||
success: htmlSafe(colors.success),
|
||||
love: htmlSafe(colors.love),
|
||||
};
|
||||
}
|
||||
|
||||
get gradientId() {
|
||||
return `bgGradient-${this.args.theme.id}-${this.randomVariant}`;
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if (eq this.randomVariant 0)}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 800 200"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
>
|
||||
<rect fill={{this.safeThemeColors.tertiary}} width="800" height="200" />
|
||||
<g transform="translate(280, -100) scale(0.4)">
|
||||
<g
|
||||
fill="none"
|
||||
stroke={{this.safeThemeColors.secondary}}
|
||||
stroke-width="1"
|
||||
>
|
||||
<path
|
||||
d="M769 229L1037 260.9M927 880L731 737 520 660 309 538 40 599 295 764 126.5 879.5 40 599-197 493 102 382-31 229 126.5 79.5-69-63"
|
||||
/>
|
||||
<path
|
||||
d="M-31 229L237 261 390 382 603 493 308.5 537.5 101.5 381.5M370 905L295 764"
|
||||
/>
|
||||
<path
|
||||
d="M520 660L578 842 731 737 840 599 603 493 520 660 295 764 309 538 390 382 539 269 769 229 577.5 41.5 370 105 295 -36 126.5 79.5 237 261 102 382 40 599 -69 737 127 880"
|
||||
/>
|
||||
<path
|
||||
d="M520-140L578.5 42.5 731-63M603 493L539 269 237 261 370 105M902 382L539 269M390 382L102 382"
|
||||
/>
|
||||
<path
|
||||
d="M-222 42L126.5 79.5 370 105 539 269 577.5 41.5 927 80 769 229 902 382 603 493 731 737M295-36L577.5 41.5M578 842L295 764M40-201L127 80M102 382L-261 269"
|
||||
/>
|
||||
</g>
|
||||
<g fill={{this.safeThemeColors.tertiary}}>
|
||||
<circle cx="769" cy="229" r="5" />
|
||||
<circle cx="539" cy="269" r="5" />
|
||||
<circle cx="603" cy="493" r="5" />
|
||||
<circle cx="731" cy="737" r="5" />
|
||||
<circle cx="520" cy="660" r="5" />
|
||||
<circle cx="309" cy="538" r="5" />
|
||||
<circle cx="295" cy="764" r="5" />
|
||||
<circle cx="40" cy="599" r="5" />
|
||||
<circle cx="102" cy="382" r="5" />
|
||||
<circle cx="127" cy="80" r="5" />
|
||||
<circle cx="370" cy="105" r="5" />
|
||||
<circle cx="578" cy="42" r="5" />
|
||||
<circle cx="237" cy="261" r="5" />
|
||||
<circle cx="390" cy="382" r="5" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
{{else if (eq this.randomVariant 1)}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 800 200"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
>
|
||||
<rect fill={{this.safeThemeColors.tertiary}} width="800" height="200" />
|
||||
<defs>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-a"
|
||||
cx="0"
|
||||
cy="347"
|
||||
r="347"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.quaternary}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.quaternary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-b"
|
||||
cx="636"
|
||||
cy="347"
|
||||
r="347"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.tertiary}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.tertiary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-c"
|
||||
cx="600"
|
||||
cy="0"
|
||||
r="600"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.highlight}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.highlight}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-d"
|
||||
cx="600"
|
||||
cy="347"
|
||||
r="600"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.quaternary}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.quaternary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-e"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="347"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.tertiary}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.tertiary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="{{this.gradientId}}-f"
|
||||
cx="636"
|
||||
cy="0"
|
||||
r="347"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.tertiary}} />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.tertiary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect fill="url(#{{this.gradientId}}-a)" width="800" height="200" />
|
||||
<rect fill="url(#{{this.gradientId}}-b)" width="800" height="200" />
|
||||
<rect fill="url(#{{this.gradientId}}-c)" width="800" height="200" />
|
||||
<rect fill="url(#{{this.gradientId}}-d)" width="800" height="200" />
|
||||
<rect fill="url(#{{this.gradientId}}-e)" width="800" height="200" />
|
||||
<rect fill="url(#{{this.gradientId}}-f)" width="800" height="200" />
|
||||
</svg>
|
||||
{{else if (eq this.randomVariant 2)}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 1600 800"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
>
|
||||
<rect
|
||||
fill={{this.safeThemeColors.tertiary}}
|
||||
width="1600"
|
||||
height="800"
|
||||
/>
|
||||
<g fill-opacity=".4" transform="scale(1.2)">
|
||||
<path
|
||||
fill={{this.safeThemeColors.tertiary}}
|
||||
d="M486 705.8c-109.3-21.8-223.4-32.2-335.3-19.4C99.5 692.1 49 703 0 719.8V800h843.8c-115.9-33.2-230.8-68.1-347.6-92.2C492.8 707.1 489.4 706.5 486 705.8z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.tertiary}}
|
||||
d="M1600 0H0v719.8c49-16.8 99.5-27.8 150.7-33.5c111.9-12.7 226-2.4 335.3 19.4c3.4 0.7 6.8 1.4 10.2 2c116.8 24 231.7 59 347.6 92.2H1600V0z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.quaternary}}
|
||||
d="M478.4 581c3.2 0.8 6.4 1.7 9.5 2.5c196.2 52.5 388.7 133.5 593.5 176.6c174.2 36.6 349.5 29.2 518.6-10.2V0H0v574.9c52.3-17.6 106.5-27.7 161.1-30.9C268.4 537.4 375.7 554.2 478.4 581z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.quaternary}}
|
||||
d="M0 0v429.4c55.6-18.4 113.5-27.3 171.4-27.7c102.8-0.8 203.2 22.7 299.3 54.5c3 1 5.9 2 8.9 3c183.6 62 365.7 146.1 562.4 192.1c186.7 43.7 376.3 34.4 557.9-12.6V0H0z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.highlight}}
|
||||
d="M181.8 259.4c98.2 6 191.9 35.2 281.3 72.1c2.8 1.1 5.5 2.3 8.3 3.4c171 71.6 342.7 158.5 531.3 207.7c198.8 51.8 403.4 40.8 597.3-14.8V0H0v283.2C59 263.6 120.6 255.7 181.8 259.4z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.highlight}}
|
||||
d="M1600 0H0v136.3c62.3-20.9 127.7-27.5 192.2-19.2c93.6 12.1 180.5 47.7 263.3 89.6c2.6 1.3 5.1 2.6 7.7 3.9c158.4 81.1 319.7 170.9 500.3 223.2c210.5 61 430.8 49 636.6-16.6V0z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.danger}}
|
||||
d="M454.9 86.3C600.7 177 751.6 269.3 924.1 325c208.6 67.4 431.3 60.8 637.9-5.3c12.8-4.1 25.4-8.4 38.1-12.9V0H288.1c56 21.3 108.7 50.6 159.7 82C450.2 83.4 452.5 84.9 454.9 86.3z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.danger}}
|
||||
d="M1600 0H498c118.1 85.8 243.5 164.5 386.8 216.2c191.8 69.2 400 74.7 595 21.1c40.8-11.2 81.1-25.2 120.3-41.7V0z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.success}}
|
||||
d="M1397.5 154.8c47.2-10.6 93.6-25.3 138.6-43.8c21.7-8.9 43-18.8 63.9-29.5V0H643.4c62.9 41.7 129.7 78.2 202.1 107.4C1020.4 178.1 1214.2 196.1 1397.5 154.8z"
|
||||
/>
|
||||
<path
|
||||
fill={{this.safeThemeColors.success}}
|
||||
d="M1315.3 72.4c75.3-12.6 148.9-37.1 216.8-72.4h-723C966.8 71 1144.7 101 1315.3 72.4z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
{{else if (eq this.randomVariant 3)}}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 2 1"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<rect fill={{this.safeThemeColors.tertiary}} width="2" height="1" />
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="{{this.gradientId}}-a"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="0"
|
||||
y1="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop offset="0" stop-color={{this.safeThemeColors.tertiary}} />
|
||||
<stop offset="1" stop-color={{this.safeThemeColors.quaternary}} />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="{{this.gradientId}}-b"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color={{this.safeThemeColors.quaternary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.highlight}}
|
||||
stop-opacity="1"
|
||||
/>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="{{this.gradientId}}-c"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="2"
|
||||
y2="2"
|
||||
>
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color={{this.safeThemeColors.quaternary}}
|
||||
stop-opacity="0"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color={{this.safeThemeColors.highlight}}
|
||||
stop-opacity="1"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
fill="url(#{{this.gradientId}}-a)"
|
||||
width="2"
|
||||
height="1"
|
||||
/>
|
||||
<g fill-opacity="0.5">
|
||||
<polygon fill="url(#{{this.gradientId}}-b)" points="0 1 0 0 2 0" />
|
||||
<polygon fill="url(#{{this.gradientId}}-c)" points="2 1 2 0 0 0" />
|
||||
</g>
|
||||
</svg>
|
||||
{{/if}}
|
||||
<svg viewBox="0 0 636 347" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
width="635.115"
|
||||
height="347"
|
||||
fill={{htmlSafe this.themeColors.secondary}}
|
||||
/>
|
||||
<path
|
||||
d="M54.9766 79.1039C55.9198 76.0065 59.8623 75.0916 62.0732 77.4571L121.448 140.986C123.659 143.351 122.48 147.223 119.326 147.955L34.621 167.611C31.467 168.343 28.7034 165.386 29.6466 162.288L54.9766 79.1039Z"
|
||||
fill={{htmlSafe this.themeColors.primary}}
|
||||
/>
|
||||
<path
|
||||
d="M398.487 211.02C400.651 208.611 404.611 209.448 405.615 212.527L432.579 295.196C433.584 298.274 430.879 301.285 427.711 300.615L342.635 282.633C339.467 281.963 338.212 278.115 340.376 275.707L398.487 211.02Z"
|
||||
fill={{htmlSafe this.themeColors.tertiary}}
|
||||
/>
|
||||
<circle cx="109.357" cy="262.879" r="44.1636" fill="#D1F0FF" />
|
||||
<circle cx="365.927" cy="103.048" r="44.1636" fill="#E45735" />
|
||||
<rect
|
||||
x="166.139"
|
||||
y="68.751"
|
||||
width="81.9226"
|
||||
height="81.9226"
|
||||
rx="4.20606"
|
||||
transform="rotate(-15.9297 166.139 68.751)"
|
||||
fill={{htmlSafe this.themeColors.danger}}
|
||||
/>
|
||||
<rect
|
||||
x="500.521"
|
||||
y="100.296"
|
||||
width="81.9226"
|
||||
height="81.9226"
|
||||
rx="4.20606"
|
||||
transform="rotate(-15.9297 500.521 100.296)"
|
||||
fill={{htmlSafe this.themeColors.success}}
|
||||
/>
|
||||
<rect
|
||||
x="481.857"
|
||||
y="222.921"
|
||||
width="121.976"
|
||||
height="54.6788"
|
||||
rx="4.20606"
|
||||
transform="rotate(9.12857 481.857 222.921)"
|
||||
fill={{htmlSafe this.themeColors.love}}
|
||||
/>
|
||||
<rect
|
||||
x="176.654"
|
||||
y="240.608"
|
||||
width="121.976"
|
||||
height="54.6788"
|
||||
rx="4.20606"
|
||||
transform="rotate(-22.7296 176.654 240.608)"
|
||||
fill={{htmlSafe this.themeColors.primary}}
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import { action } from "@ember/object";
|
||||
import { equal, gt, gte } from "@ember/object/computed";
|
||||
import { service } from "@ember/service";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { and, eq, not, or } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DeleteThemesConfirm from "discourse/components/modal/delete-themes-confirm";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
@ -15,6 +14,10 @@ import { i18n } from "discourse-i18n";
|
||||
import ThemesListItem from "admin/components/themes-list-item";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
import and from "truth-helpers/helpers/and";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
import not from "truth-helpers/helpers/not";
|
||||
import or from "truth-helpers/helpers/or";
|
||||
|
||||
const ALL_FILTER = "all";
|
||||
const ACTIVE_FILTER = "active";
|
||||
|
@ -8,7 +8,6 @@ import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
|
||||
import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
|
||||
import { service } from "@ember/service";
|
||||
import { not } from "truth-helpers";
|
||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||
import CountI18n from "discourse/components/count-i18n";
|
||||
import DButton from "discourse/components/d-button";
|
||||
@ -19,6 +18,7 @@ import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import WebhookEvent from "admin/components/webhook-event";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
import not from "truth-helpers/helpers/not";
|
||||
|
||||
export default class WebhookEvents extends Component {
|
||||
@service messageBus;
|
||||
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigAnalyticsSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminApiKeysSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,10 +1,3 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { service } from "@ember/service";
|
||||
|
||||
export default class AdminApiKeysController extends Controller {
|
||||
@service router;
|
||||
|
||||
get hideTabs() {
|
||||
return ["adminApiKeys.show"].includes(this.router.currentRouteName);
|
||||
}
|
||||
}
|
||||
export default class AdminApiKeysController extends Controller {}
|
||||
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigContentCategoriesAndTagsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigContentPostsAndTopicsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigContentSharingController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigContentPostsAndTopicsController extends AdminAreaSettingsBaseController {}
|
@ -0,0 +1,3 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigFontsSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigInterfaceSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigSiteAdminSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigUserDefaultsSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,5 +1,5 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import {
|
||||
empty,
|
||||
filterBy,
|
||||
@ -16,7 +16,6 @@ import discourseComputed from "discourse/lib/decorators";
|
||||
import { makeArray } from "discourse/lib/helpers";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ThemeSettingsEditor from "admin/components/theme-settings-editor";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import ThemeSettings from "admin/models/theme-settings";
|
||||
import ThemeUploadAddModal from "../components/theme-upload-add";
|
||||
@ -92,11 +91,11 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
|
||||
@discourseComputed("model.parentThemes.[]")
|
||||
relativesSelectorSettingsForComponent() {
|
||||
return SiteSetting.create({
|
||||
return EmberObject.create({
|
||||
list_type: "compact",
|
||||
type: "list",
|
||||
preview: null,
|
||||
allow_any: false,
|
||||
anyValue: false,
|
||||
setting: "parent_theme_ids",
|
||||
label: i18n("admin.customize.theme.component_on_themes"),
|
||||
choices: this.availableThemesNames,
|
||||
@ -110,11 +109,11 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
|
||||
@discourseComputed("model.parentThemes.[]")
|
||||
relativesSelectorSettingsForTheme() {
|
||||
return SiteSetting.create({
|
||||
return EmberObject.create({
|
||||
list_type: "compact",
|
||||
type: "list",
|
||||
preview: null,
|
||||
allow_any: false,
|
||||
anyValue: false,
|
||||
setting: "child_theme_ids",
|
||||
label: i18n("admin.customize.theme.included_components"),
|
||||
choices: this.availableComponentsNames,
|
||||
@ -312,12 +311,10 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
|
||||
@action
|
||||
updateLocale(value) {
|
||||
this.set("model.loadingTranslations", true);
|
||||
this.set("model.locale", value);
|
||||
ajax(this.getTranslationsUrl).then(({ translations }) => {
|
||||
this.set("model.translations", translations);
|
||||
this.set("model.loadingTranslations", false);
|
||||
});
|
||||
ajax(this.getTranslationsUrl).then(({ translations }) =>
|
||||
this.set("model.translations", translations)
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -2,11 +2,11 @@ import { inject as controller } from "@ember/controller";
|
||||
import { computed } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import { REPORT_MODES } from "discourse/lib/constants";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import getURL from "discourse/lib/get-url";
|
||||
import { makeArray } from "discourse/lib/helpers";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { REPORT_MODES } from "admin/lib/constants";
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import Report from "admin/models/report";
|
||||
import AdminDashboardTabController from "./admin-dashboard-tab";
|
||||
|
@ -4,7 +4,7 @@ import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
|
||||
export default class AdminEmailLogsBouncedController extends AdminEmailLogsController {
|
||||
export default class AdminEmailBouncedController extends AdminEmailLogsController {
|
||||
@action
|
||||
handleShowIncomingEmail(id, event) {
|
||||
event?.preventDefault();
|
@ -5,7 +5,7 @@ import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
|
||||
export default class AdminEmailLogsReceivedController extends AdminEmailLogsController {
|
||||
export default class AdminEmailReceivedController extends AdminEmailLogsController {
|
||||
@observes("filter.{status,from,to,subject}")
|
||||
filterIncomingEmails() {
|
||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
@ -5,7 +5,7 @@ import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
|
||||
export default class AdminEmailLogsRejectedController extends AdminEmailLogsController {
|
||||
export default class AdminEmailRejectedController extends AdminEmailLogsController {
|
||||
@observes("filter.{status,from,to,subject,error}")
|
||||
filterIncomingEmails() {
|
||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
@ -3,7 +3,7 @@ import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
|
||||
export default class AdminEmailLogsSentController extends AdminEmailLogsController {
|
||||
export default class AdminEmailSentController extends AdminEmailLogsController {
|
||||
ccAddressDisplayThreshold = 2;
|
||||
sortWithAddressFilter = (addresses) => {
|
||||
if (!Array.isArray(addresses) || addresses.length === 0) {
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminEmailSettingsController extends AdminAreaSettingsBaseController {}
|
@ -3,7 +3,7 @@ import discourseDebounce from "discourse/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse/lib/environment";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
|
||||
export default class AdminEmailLogsSkippedController extends AdminEmailLogsController {
|
||||
export default class AdminEmailSkippedController extends AdminEmailLogsController {
|
||||
@observes("filter.{status,user,address,type}")
|
||||
filterEmailLogs() {
|
||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminReportsDashboardSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,10 +0,0 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { service } from "@ember/service";
|
||||
|
||||
export default class AdminReportsController extends Controller {
|
||||
@service router;
|
||||
|
||||
get hideTabs() {
|
||||
return ["adminReports.show"].includes(this.router.currentRouteName);
|
||||
}
|
||||
}
|
@ -1,11 +1,5 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
|
||||
import { translateModKey } from "discourse/lib/utilities";
|
||||
|
||||
export default class AdminSearchIndexController extends Controller {
|
||||
queryParams = ["filter"];
|
||||
|
||||
get shortcutHTML() {
|
||||
return `<kbd>${translateModKey(PLATFORM_KEY_MODIFIER)}</kbd> + <kbd>/</kbd>`;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export default class AdminSiteTextEdit extends Controller {
|
||||
});
|
||||
}
|
||||
|
||||
@discourseComputed("buffered.value", "siteText.value")
|
||||
@discourseComputed("buffered.value")
|
||||
saveDisabled(value) {
|
||||
return this.siteText.value === value;
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ export default class AdminUserIndexController extends Controller {
|
||||
@computed("model.id", "currentUser.id")
|
||||
get canCheckEmails() {
|
||||
return new CanCheckEmailsHelper(
|
||||
this.model.id,
|
||||
this.model,
|
||||
this.canModeratorsViewEmails,
|
||||
this.currentUser
|
||||
).canCheckEmails;
|
||||
@ -142,7 +142,7 @@ export default class AdminUserIndexController extends Controller {
|
||||
@computed("model.id", "currentUser.id")
|
||||
get canAdminCheckEmails() {
|
||||
return new CanCheckEmailsHelper(
|
||||
this.model.id,
|
||||
this.model,
|
||||
this.canModeratorsViewEmails,
|
||||
this.currentUser
|
||||
).canAdminCheckEmails;
|
||||
|
@ -66,7 +66,7 @@ export default class AdminUsersListShowController extends Controller {
|
||||
@computed("model.id", "currentUser.id")
|
||||
get canCheckEmails() {
|
||||
return new CanCheckEmailsHelper(
|
||||
this.model?.id,
|
||||
this.model,
|
||||
this.canModeratorsViewEmails,
|
||||
this.currentUser
|
||||
).canCheckEmails;
|
||||
@ -75,7 +75,7 @@ export default class AdminUsersListShowController extends Controller {
|
||||
@computed("model.id", "currentUser.id")
|
||||
get canAdminCheckEmails() {
|
||||
return new CanCheckEmailsHelper(
|
||||
this.model?.id,
|
||||
this.model,
|
||||
this.canModeratorsViewEmails,
|
||||
this.currentUser
|
||||
).canAdminCheckEmails;
|
||||
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminUsersSettingsController extends AdminAreaSettingsBaseController {}
|
@ -1,6 +1,9 @@
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { registerRawHelper } from "discourse/lib/helpers";
|
||||
import { renderIcon } from "discourse/lib/icon-library";
|
||||
|
||||
registerRawHelper("check-icon", checkIcon);
|
||||
|
||||
export default function checkIcon(value) {
|
||||
let icon = value ? "check" : "xmark";
|
||||
return htmlSafe(renderIcon("string", icon));
|
||||
|
@ -0,0 +1,28 @@
|
||||
import Helper from "@ember/component/helper";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { iconHTML } from "discourse/lib/icon-library";
|
||||
|
||||
export default class DispositionIcon extends Helper {
|
||||
compute([disposition]) {
|
||||
if (!disposition) {
|
||||
return null;
|
||||
}
|
||||
let icon;
|
||||
let title = "admin.flags.dispositions." + disposition;
|
||||
switch (disposition) {
|
||||
case "deferred": {
|
||||
icon = "up-right-from-square";
|
||||
break;
|
||||
}
|
||||
case "agreed": {
|
||||
icon = "thumbs-o-up";
|
||||
break;
|
||||
}
|
||||
case "disagreed": {
|
||||
icon = "thumbs-o-down";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return htmlSafe(iconHTML(icon, { title }));
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import Helper from "@ember/component/helper";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
function postActionTitle([id, nameKey]) {
|
||||
let title = i18n(`admin.flags.short_names.${nameKey}`, {
|
||||
defaultValue: null,
|
||||
});
|
||||
|
||||
// TODO: We can remove this once other translations have been updated
|
||||
if (!title) {
|
||||
return i18n(`admin.flags.summary.action_type_${id}`, { count: 1 });
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
export default Helper.helper(postActionTitle);
|
@ -0,0 +1,6 @@
|
||||
import { htmlHelper } from "discourse/lib/helpers";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default htmlHelper((str) =>
|
||||
escapeExpression(str).replace(/\n/g, "<br>")
|
||||
);
|
17
app/assets/javascripts/admin/addon/helpers/value-at-tl.js
Normal file
17
app/assets/javascripts/admin/addon/helpers/value-at-tl.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { registerRawHelper } from "discourse/lib/helpers";
|
||||
|
||||
registerRawHelper("value-at-tl", valueAtTl);
|
||||
|
||||
export default function valueAtTl(data, params = {}) {
|
||||
let tl = parseInt(params.level, 10);
|
||||
if (data) {
|
||||
let item = data.find(function (d) {
|
||||
return parseInt(d.x, 10) === tl;
|
||||
});
|
||||
if (item) {
|
||||
return item.y;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
// DO NOT EDIT THIS FILE!!!
|
||||
// Update it by running `rake javascript:update_constants`
|
||||
|
||||
export const ADMIN_SEARCH_RESULT_TYPES = [
|
||||
"page",
|
||||
"setting",
|
||||
"theme",
|
||||
"component",
|
||||
"report",
|
||||
];
|
||||
|
||||
export const SITE_SETTING_REQUIRES_CONFIRMATION_TYPES = {
|
||||
simple: "simple",
|
||||
user_option: "user_option",
|
||||
};
|
||||
|
||||
export const API_KEY_SCOPE_MODES = ["global", "read_only", "granular"];
|
||||
|
||||
export const SYSTEM_FLAG_IDS = {
|
||||
like: 2,
|
||||
notify_user: 6,
|
||||
off_topic: 3,
|
||||
inappropriate: 4,
|
||||
spam: 8,
|
||||
illegal: 10,
|
||||
notify_moderators: 7,
|
||||
};
|
||||
|
||||
export const REPORT_MODES = {
|
||||
table: "table",
|
||||
chart: "chart",
|
||||
stacked_chart: "stacked_chart",
|
||||
stacked_line_chart: "stacked_line_chart",
|
||||
radar: "radar",
|
||||
counters: "counters",
|
||||
inline_table: "inline_table",
|
||||
storage_stats: "storage_stats",
|
||||
};
|
||||
|
||||
export const USER_FIELD_FLAGS = [
|
||||
"editable",
|
||||
"show_on_profile",
|
||||
"show_on_user_card",
|
||||
"searchable",
|
||||
];
|
||||
|
||||
export const DEFAULT_USER_PREFERENCES = [
|
||||
"default_email_digest_frequency",
|
||||
"default_include_tl0_in_digests",
|
||||
"default_email_level",
|
||||
"default_email_messages_level",
|
||||
"default_email_mailing_list_mode",
|
||||
"default_email_mailing_list_mode_frequency",
|
||||
"default_email_previous_replies",
|
||||
"default_email_in_reply_to",
|
||||
"default_hide_profile",
|
||||
"default_hide_presence",
|
||||
"default_other_new_topic_duration_minutes",
|
||||
"default_other_auto_track_topics_after_msecs",
|
||||
"default_other_notification_level_when_replying",
|
||||
"default_other_external_links_in_new_tab",
|
||||
"default_other_enable_quoting",
|
||||
"default_other_enable_smart_lists",
|
||||
"default_other_enable_defer",
|
||||
"default_other_dynamic_favicon",
|
||||
"default_other_like_notification_frequency",
|
||||
"default_other_skip_new_user_tips",
|
||||
"default_topics_automatic_unpin",
|
||||
"default_categories_watching",
|
||||
"default_categories_tracking",
|
||||
"default_categories_muted",
|
||||
"default_categories_watching_first_post",
|
||||
"default_categories_normal",
|
||||
"default_tags_watching",
|
||||
"default_tags_tracking",
|
||||
"default_tags_muted",
|
||||
"default_tags_watching_first_post",
|
||||
"default_text_size",
|
||||
"default_title_count_mode",
|
||||
"default_navigation_menu_categories",
|
||||
"default_navigation_menu_tags",
|
||||
"default_sidebar_link_to_filtered_list",
|
||||
"default_sidebar_show_count_of_new_items",
|
||||
];
|
||||
|
||||
export const MAIN_FONTS = [
|
||||
{ key: "open_sans", name: "Open Sans" },
|
||||
{ key: "roboto", name: "Roboto" },
|
||||
{ key: "lato", name: "Lato" },
|
||||
{ key: "inter", name: "Inter" },
|
||||
{ key: "montserrat", name: "Montserrat" },
|
||||
{ key: "poppins", name: "Poppins" },
|
||||
{ key: "merriweather", name: "Merriweather" },
|
||||
{ key: "mukta", name: "Mukta" },
|
||||
{ key: "helvetica", name: "Helvetica" },
|
||||
];
|
||||
|
||||
export const MORE_FONTS = [
|
||||
{ key: "arial", name: "Arial" },
|
||||
{ key: "system", name: "System" },
|
||||
{ key: "oxanium", name: "Oxanium" },
|
||||
{ key: "noto_sans_jp", name: "NotoSansJP" },
|
||||
{ key: "roboto_condensed", name: "RobotoCondensed" },
|
||||
{ key: "source_sans_pro", name: "SourceSansPro" },
|
||||
{ key: "oswald", name: "Oswald" },
|
||||
{ key: "raleway", name: "Raleway" },
|
||||
{ key: "roboto_mono", name: "RobotoMono" },
|
||||
{ key: "noto_sans", name: "NotoSans" },
|
||||
{ key: "roboto_slab", name: "RobotoSlab" },
|
||||
{ key: "ubuntu", name: "Ubuntu" },
|
||||
{ key: "pt_sans", name: "PTSans" },
|
||||
{ key: "playfair_display", name: "PlayfairDisplay" },
|
||||
{ key: "nunito", name: "Nunito" },
|
||||
{ key: "lora", name: "Lora" },
|
||||
{ key: "jet_brains_mono", name: "JetBrains Mono" },
|
||||
];
|
||||
|
||||
export const DEFAULT_TEXT_SIZES = [
|
||||
"smallest",
|
||||
"smaller",
|
||||
"normal",
|
||||
"larger",
|
||||
"largest",
|
||||
];
|
@ -73,16 +73,4 @@ export const templateFormFields = [
|
||||
validations:
|
||||
# ${i18n("admin.form_templates.field_placeholders.validations")}`,
|
||||
},
|
||||
{
|
||||
type: "tagchooser",
|
||||
structure: `- type: tag-chooser
|
||||
id: ${i18n("admin.form_templates.field_placeholders.id")}
|
||||
tag_group: ""
|
||||
attributes:
|
||||
none_label: "${i18n("admin.form_templates.field_placeholders.none_label")}"
|
||||
label: "${i18n("admin.form_templates.field_placeholders.label")}"
|
||||
multiple: true
|
||||
validations:
|
||||
# ${i18n("admin.form_templates.field_placeholders.validations")}`,
|
||||
},
|
||||
];
|
||||
|
@ -5,12 +5,16 @@ import Mixin from "@ember/object/mixin";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { isNone } from "@ember/utils";
|
||||
import { Promise } from "rsvp";
|
||||
import JsonSchemaEditorModal from "discourse/components/modal/json-schema-editor";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { fmt, propertyNotEqual } from "discourse/lib/computed";
|
||||
import { SITE_SETTING_REQUIRES_CONFIRMATION_TYPES } from "discourse/lib/constants";
|
||||
import { deepEqual } from "discourse/lib/object";
|
||||
import { humanizedSettingName } from "discourse/lib/site-settings-utils";
|
||||
import { splitString } from "discourse/lib/utilities";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import SiteSettingDefaultCategoriesModal from "../components/modal/site-setting-default-categories";
|
||||
|
||||
const CUSTOM_TYPES = [
|
||||
"bool",
|
||||
@ -38,14 +42,55 @@ const CUSTOM_TYPES = [
|
||||
"font_list",
|
||||
];
|
||||
|
||||
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];
|
||||
|
||||
const DEFAULT_USER_PREFERENCES = [
|
||||
"default_email_digest_frequency",
|
||||
"default_include_tl0_in_digests",
|
||||
"default_email_level",
|
||||
"default_email_messages_level",
|
||||
"default_email_mailing_list_mode",
|
||||
"default_email_mailing_list_mode_frequency",
|
||||
"default_email_previous_replies",
|
||||
"default_email_in_reply_to",
|
||||
"default_hide_profile",
|
||||
"default_hide_presence",
|
||||
"default_other_new_topic_duration_minutes",
|
||||
"default_other_auto_track_topics_after_msecs",
|
||||
"default_other_notification_level_when_replying",
|
||||
"default_other_external_links_in_new_tab",
|
||||
"default_other_enable_quoting",
|
||||
"default_other_enable_smart_lists",
|
||||
"default_other_enable_defer",
|
||||
"default_other_dynamic_favicon",
|
||||
"default_other_like_notification_frequency",
|
||||
"default_other_skip_new_user_tips",
|
||||
"default_topics_automatic_unpin",
|
||||
"default_categories_watching",
|
||||
"default_categories_tracking",
|
||||
"default_categories_muted",
|
||||
"default_categories_watching_first_post",
|
||||
"default_categories_normal",
|
||||
"default_tags_watching",
|
||||
"default_tags_tracking",
|
||||
"default_tags_muted",
|
||||
"default_tags_watching_first_post",
|
||||
"default_text_size",
|
||||
"default_title_count_mode",
|
||||
"default_navigation_menu_categories",
|
||||
"default_navigation_menu_tags",
|
||||
"default_sidebar_link_to_filtered_list",
|
||||
"default_sidebar_show_count_of_new_items",
|
||||
];
|
||||
|
||||
export default Mixin.create({
|
||||
modal: service(),
|
||||
router: service(),
|
||||
site: service(),
|
||||
dialog: service(),
|
||||
siteSettingChangeTracker: service(),
|
||||
attributeBindings: ["setting.setting:data-setting"],
|
||||
classNameBindings: [":row", ":setting", "overridden", "typeClass"],
|
||||
validationMessage: null,
|
||||
|
||||
content: alias("setting"),
|
||||
isSecret: oneWay("setting.secret"),
|
||||
@ -67,7 +112,7 @@ export default Mixin.create({
|
||||
}),
|
||||
|
||||
dirty: computed("buffered.value", "setting.value", function () {
|
||||
let bufferVal = this.buffered.get("value");
|
||||
let bufferVal = this.get("buffered.value");
|
||||
let settingVal = this.setting?.value;
|
||||
|
||||
if (isNone(bufferVal)) {
|
||||
@ -78,20 +123,12 @@ export default Mixin.create({
|
||||
settingVal = "";
|
||||
}
|
||||
|
||||
const dirty = !deepEqual(bufferVal, settingVal);
|
||||
|
||||
if (dirty) {
|
||||
this.siteSettingChangeTracker.add(this.setting);
|
||||
} else {
|
||||
this.siteSettingChangeTracker.remove(this.setting);
|
||||
}
|
||||
|
||||
return dirty;
|
||||
return !deepEqual(bufferVal, settingVal);
|
||||
}),
|
||||
|
||||
preview: computed("setting", "buffered.value", function () {
|
||||
const setting = this.setting;
|
||||
const value = this.buffered.get("value");
|
||||
const value = this.get("buffered.value");
|
||||
const preview = setting.preview;
|
||||
if (preview) {
|
||||
const escapedValue = preview.replace(/\{\{value\}\}/g, value);
|
||||
@ -128,7 +165,7 @@ export default Mixin.create({
|
||||
}),
|
||||
|
||||
bufferedValues: computed("buffered.value", function () {
|
||||
const value = this.buffered.get("value");
|
||||
const value = this.get("buffered.value");
|
||||
return splitString(value, "|");
|
||||
}),
|
||||
|
||||
@ -179,41 +216,102 @@ export default Mixin.create({
|
||||
}
|
||||
}),
|
||||
|
||||
disableControls: computed("setting.isSaving", function () {
|
||||
return !!this.setting.isSaving;
|
||||
disableSaveButton: computed("validationMessage", function () {
|
||||
return !!this.validationMessage;
|
||||
}),
|
||||
|
||||
confirmChanges(settingKey) {
|
||||
return new Promise((resolve) => {
|
||||
// Fallback is needed in case the setting does not have a custom confirmation
|
||||
// prompt/confirm defined.
|
||||
this.dialog.alert({
|
||||
message: i18n(
|
||||
`admin.site_settings.requires_confirmation_messages.${settingKey}.prompt`,
|
||||
{
|
||||
translatedFallback: i18n(
|
||||
"admin.site_settings.requires_confirmation_messages.default.prompt"
|
||||
),
|
||||
}
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
label: i18n(
|
||||
`admin.site_settings.requires_confirmation_messages.${settingKey}.confirm`,
|
||||
{
|
||||
translatedFallback: i18n(
|
||||
"admin.site_settings.requires_confirmation_messages.default.confirm"
|
||||
),
|
||||
}
|
||||
),
|
||||
class: "btn-primary",
|
||||
action: () => resolve(true),
|
||||
},
|
||||
{
|
||||
label: i18n("no_value"),
|
||||
class: "btn-default",
|
||||
action: () => resolve(false),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
update: action(async function () {
|
||||
if (this.setting.requiresConfirmation) {
|
||||
const confirm = await this.siteSettingChangeTracker.confirmChanges(
|
||||
this.setting
|
||||
);
|
||||
const key = this.buffered.get("setting");
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
let confirm = true;
|
||||
if (
|
||||
this.buffered.get("requires_confirmation") ===
|
||||
SITE_SETTING_REQUIRES_CONFIRMATION_TYPES.simple
|
||||
) {
|
||||
confirm = await this.confirmChanges(key);
|
||||
}
|
||||
|
||||
if (this.setting.affectsExistingUsers) {
|
||||
await this.siteSettingChangeTracker.configureBackfill(this.setting);
|
||||
if (!confirm) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
await this.save();
|
||||
if (!DEFAULT_USER_PREFERENCES.includes(key)) {
|
||||
await this.save();
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
[key]: this.buffered.get("value"),
|
||||
};
|
||||
|
||||
const result = await ajax(`/admin/site_settings/${key}/user_count.json`, {
|
||||
type: "PUT",
|
||||
data,
|
||||
});
|
||||
|
||||
const count = result.user_count;
|
||||
if (count > 0) {
|
||||
await this.modal.show(SiteSettingDefaultCategoriesModal, {
|
||||
model: {
|
||||
siteSetting: { count, key: key.replaceAll("_", " ") },
|
||||
setUpdateExistingUsers: this.setUpdateExistingUsers,
|
||||
},
|
||||
});
|
||||
this.save();
|
||||
} else {
|
||||
await this.save();
|
||||
}
|
||||
}),
|
||||
|
||||
setUpdateExistingUsers: action(function (value) {
|
||||
this.updateExistingUsers = value;
|
||||
}),
|
||||
|
||||
save: action(async function () {
|
||||
try {
|
||||
this.setting.isSaving = true;
|
||||
|
||||
await this._save();
|
||||
|
||||
this.setting.validationMessage = null;
|
||||
this.set("validationMessage", null);
|
||||
this.buffered.applyChanges();
|
||||
|
||||
if (this.setting.requiresReload) {
|
||||
this.siteSettingChangeTracker.refreshPage({
|
||||
[this.setting.setting]: this.setting.value,
|
||||
});
|
||||
if (AUTO_REFRESH_ON_SAVE.includes(this.setting.setting)) {
|
||||
this.afterSave();
|
||||
}
|
||||
} catch (e) {
|
||||
const json = e.jqXHR?.responseJSON;
|
||||
@ -224,31 +322,29 @@ export default Mixin.create({
|
||||
errorString = htmlSafe(errorString);
|
||||
}
|
||||
|
||||
this.setting.validationMessage = errorString;
|
||||
this.set("validationMessage", errorString);
|
||||
} else {
|
||||
this.setting.validationMessage = i18n("generic_error");
|
||||
this.set("validationMessage", i18n("generic_error"));
|
||||
}
|
||||
} finally {
|
||||
this.setting.isSaving = false;
|
||||
}
|
||||
}),
|
||||
|
||||
changeValueCallback: action(function (value) {
|
||||
this.buffered.set("value", value);
|
||||
this.set("buffered.value", value);
|
||||
}),
|
||||
|
||||
setValidationMessage: action(function (message) {
|
||||
this.setting.validationMessage = message;
|
||||
this.set("validationMessage", message);
|
||||
}),
|
||||
|
||||
cancel: action(function () {
|
||||
this.buffered.discardChanges();
|
||||
this.setting.validationMessage = null;
|
||||
this.set("validationMessage", null);
|
||||
}),
|
||||
|
||||
resetDefault: action(function () {
|
||||
this.buffered.set("value", this.setting.default);
|
||||
this.setting.validationMessage = null;
|
||||
this.set("buffered.value", this.setting.default);
|
||||
this.set("validationMessage", null);
|
||||
}),
|
||||
|
||||
toggleSecret: action(function () {
|
||||
@ -256,11 +352,11 @@ export default Mixin.create({
|
||||
}),
|
||||
|
||||
setDefaultValues: action(function () {
|
||||
this.buffered.set(
|
||||
"value",
|
||||
this.set(
|
||||
"buffered.value",
|
||||
this.bufferedValues.concat(this.defaultValues).uniq().join("|")
|
||||
);
|
||||
this.setting.validationMessage = null;
|
||||
this.set("validationMessage", null);
|
||||
return false;
|
||||
}),
|
||||
|
||||
|
@ -25,7 +25,7 @@ export default class EmailLog extends EmberObject {
|
||||
const status = filter.status || "sent";
|
||||
delete filter.status;
|
||||
|
||||
return ajax(`/admin/email-logs/${status}.json?offset=${offset}`, {
|
||||
return ajax(`/admin/email/${status}.json?offset=${offset}`, {
|
||||
data: filter,
|
||||
}).then((logs) => logs.map((log) => EmailLog.create(log)));
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default class EmailSettings extends EmberObject {
|
||||
static find() {
|
||||
return ajax("/admin/email/server-settings.json").then(function (settings) {
|
||||
return ajax("/admin/email.json").then(function (settings) {
|
||||
return EmailSettings.create(settings);
|
||||
});
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ export default class IncomingEmail extends EmberObject {
|
||||
}
|
||||
|
||||
static find(id) {
|
||||
return ajax(`/admin/email-logs/incoming/${id}.json`);
|
||||
return ajax(`/admin/email/incoming/${id}.json`);
|
||||
}
|
||||
|
||||
static findByBounced(id) {
|
||||
return ajax(`/admin/email-logs/incoming_from_bounced/${id}.json`);
|
||||
return ajax(`/admin/email/incoming_from_bounced/${id}.json`);
|
||||
}
|
||||
|
||||
static findAll(filter, offset) {
|
||||
@ -28,7 +28,7 @@ export default class IncomingEmail extends EmberObject {
|
||||
const status = filter.status || "received";
|
||||
delete filter.status;
|
||||
|
||||
return ajax(`/admin/email-logs/${status}.json?offset=${offset}`, {
|
||||
return ajax(`/admin/email/${status}.json?offset=${offset}`, {
|
||||
data: filter,
|
||||
}).then((incomings) =>
|
||||
incomings.map((incoming) => IncomingEmail.create(incoming))
|
||||
|
@ -1,24 +1,10 @@
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import EmberObject from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import BufferedProxy from "ember-buffered-proxy/proxy";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import discourseComputed, { bind } from "discourse/lib/decorators";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import {
|
||||
DEFAULT_USER_PREFERENCES,
|
||||
SITE_SETTING_REQUIRES_CONFIRMATION_TYPES,
|
||||
} from "admin/lib/constants";
|
||||
import SettingObjectHelper from "admin/lib/setting-object-helper";
|
||||
|
||||
const AUTO_REFRESH_ON_SAVE = [
|
||||
"logo",
|
||||
"mobile_logo",
|
||||
"base_font",
|
||||
"heading_font",
|
||||
"default_text_size",
|
||||
];
|
||||
|
||||
export default class SiteSetting extends EmberObject {
|
||||
static findAll(params = {}) {
|
||||
return ajax("/admin/site_settings", { data: params }).then(
|
||||
@ -54,17 +40,6 @@ export default class SiteSetting extends EmberObject {
|
||||
return ajax(`/admin/site_settings/${key}`, { type: "PUT", data });
|
||||
}
|
||||
|
||||
static bulkUpdate(settings) {
|
||||
return ajax(`/admin/site_settings/bulk_update.json`, {
|
||||
type: "PUT",
|
||||
data: { settings },
|
||||
});
|
||||
}
|
||||
|
||||
@tracked isSaving = false;
|
||||
@tracked validationMessage = null;
|
||||
updateExistingUsers = false;
|
||||
|
||||
settingObjectHelper = new SettingObjectHelper(this);
|
||||
|
||||
@alias("settingObjectHelper.overridden") overridden;
|
||||
@ -74,11 +49,6 @@ export default class SiteSetting extends EmberObject {
|
||||
@alias("settingObjectHelper.allowsNone") allowsNone;
|
||||
@alias("settingObjectHelper.anyValue") anyValue;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.buffered = BufferedProxy.create({ content: this });
|
||||
}
|
||||
|
||||
@discourseComputed("setting")
|
||||
staffLogFilter(setting) {
|
||||
if (!setting) {
|
||||
@ -90,24 +60,4 @@ export default class SiteSetting extends EmberObject {
|
||||
action_name: "change_site_setting",
|
||||
};
|
||||
}
|
||||
|
||||
get requiresConfirmation() {
|
||||
return (
|
||||
this.requires_confirmation ===
|
||||
SITE_SETTING_REQUIRES_CONFIRMATION_TYPES.simple
|
||||
);
|
||||
}
|
||||
|
||||
get requiresReload() {
|
||||
return AUTO_REFRESH_ON_SAVE.includes(this.setting);
|
||||
}
|
||||
|
||||
get affectsExistingUsers() {
|
||||
return DEFAULT_USER_PREFERENCES.includes(this.setting);
|
||||
}
|
||||
|
||||
@bind
|
||||
setUpdateExistingUsers(value) {
|
||||
this.updateExistingUsers = value;
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ export default class StaffActionLog extends RestModel {
|
||||
|
||||
@discourseComputed("details")
|
||||
useModalForDetails(details) {
|
||||
return details && (details.length > 100 || details.includes("\n"));
|
||||
return details && details.length > 100;
|
||||
}
|
||||
|
||||
@discourseComputed("action_name")
|
||||
|
@ -1,8 +1,19 @@
|
||||
import EmberObject from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
import SettingObjectHelper from "admin/lib/setting-object-helper";
|
||||
|
||||
export default class ThemeSettings extends EmberObject {
|
||||
settingObjectHelper = new SettingObjectHelper(this);
|
||||
|
||||
@alias("settingObjectHelper.overridden") overridden;
|
||||
@alias("settingObjectHelper.computedValueProperty") computedValueProperty;
|
||||
@alias("settingObjectHelper.computedNameProperty") computedNameProperty;
|
||||
@alias("settingObjectHelper.validValues") validValues;
|
||||
@alias("settingObjectHelper.allowsNone") allowsNone;
|
||||
@alias("settingObjectHelper.anyValue") anyValue;
|
||||
|
||||
export default class ThemeSettings extends SiteSetting {
|
||||
updateSetting(themeId, newValue) {
|
||||
if (this.objects_schema) {
|
||||
newValue = JSON.stringify(newValue);
|
||||
|
@ -1,11 +1,6 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminApiKeysIndexRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.api_keys.title");
|
||||
}
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
export default class AdminApiKeysIndexRoute extends Route {
|
||||
model() {
|
||||
return this.store.findAll("api-key");
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminApiKeysSettingsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("settings");
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import Route from "@ember/routing/route";
|
||||
|
||||
export default class AdminApiKeysRoute extends Route {}
|
@ -12,10 +12,6 @@ export default class AdminBadgesRoute extends DiscourseRoute {
|
||||
|
||||
_json = null;
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config.badges.title");
|
||||
}
|
||||
|
||||
async model() {
|
||||
let json = await ajax("/admin/badges.json");
|
||||
this._json = json;
|
||||
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigContentCategoriesAndTagsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.content.sub_pages.categories_and_tags.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigContentPostsAndTopicsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.content.sub_pages.posts_and_topics.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigContentSharingRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.content.sub_pages.sharing.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigContentStatsAndThresholdsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.content.sub_pages.stats_and_thresholds.title");
|
||||
}
|
||||
}
|
@ -2,6 +2,11 @@ import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigThemesAndComponentsComponentsRoute extends DiscourseRoute {
|
||||
async model() {
|
||||
const components = await this.store.findAll("theme");
|
||||
return components.reject((t) => !t.component);
|
||||
}
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config_areas.themes_and_components.components.title");
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigWithSettingsRoute from "./admin-config-with-settings-route";
|
||||
|
||||
export default class AdminConfigFontsRoute extends AdminConfigWithSettingsRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.font_style.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigInterfaceSettingsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.interface.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigLogoAndFontsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.logo_and_fonts.title");
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigWithSettingsRoute from "./admin-config-with-settings-route";
|
||||
|
||||
export default class AdminAnalyticsRoute extends AdminConfigWithSettingsRoute {
|
||||
export default class AdminConfigLogoRoute extends AdminConfigWithSettingsRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.analytics.title");
|
||||
return i18n("admin.config.logo.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigSiteAdminSettingsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.site_admin.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigUserDefaultsSettingsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.user_defaults.title");
|
||||
}
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminConfigWithSettingsRoute extends DiscourseRoute {
|
||||
@service siteSettingChangeTracker;
|
||||
|
||||
resetController(controller, isExiting) {
|
||||
// Have to do this because this is the parent route. We don't want to have
|
||||
// to make a controller for every single settings route when we can reset
|
||||
@ -16,15 +12,4 @@ export default class AdminConfigWithSettingsRoute extends DiscourseRoute {
|
||||
settingsController.set("filter", "");
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async willTransition(transition) {
|
||||
if (this.siteSettingChangeTracker.hasUnsavedChanges) {
|
||||
transition.abort();
|
||||
|
||||
await this.siteSettingChangeTracker.confirmTransition();
|
||||
|
||||
transition.retry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,7 @@
|
||||
import { scrollTop } from "discourse/mixins/scroll-top";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminDashboardRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.dashboard.title");
|
||||
}
|
||||
|
||||
activate() {
|
||||
this.controllerFor("admin-dashboard").fetchProblems();
|
||||
this.controllerFor("admin-dashboard").fetchDashboard();
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
import AdminEmailLogs from "admin/routes/admin-email-logs";
|
||||
import IncomingEmailModal from "../components/modal/incoming-email";
|
||||
|
||||
export default class AdminEmailLogsBouncedRoute extends AdminEmailLogs {
|
||||
export default class AdminEmailBouncedRoute extends AdminEmailLogs {
|
||||
@service modal;
|
||||
|
||||
status = "bounced";
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config.email_logs.sub_pages.bounced.title");
|
||||
}
|
||||
|
||||
@action
|
||||
async showIncomingEmail(id) {
|
||||
const model = await this.loadFromBounced(id);
|
@ -1,10 +0,0 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminEmailIncomings from "admin/routes/admin-email-incomings";
|
||||
|
||||
export default class AdminEmailLogsReceivedRoute extends AdminEmailIncomings {
|
||||
status = "received";
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config.email_logs.sub_pages.received.title");
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminEmailLogs from "admin/routes/admin-email-logs";
|
||||
|
||||
export default class AdminEmailLogsSentRoute extends AdminEmailLogs {
|
||||
status = "sent";
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config.email_logs.sub_pages.sent.title");
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminEmailLogs from "admin/routes/admin-email-logs";
|
||||
|
||||
export default class AdminEmailLogsSkippedRoute extends AdminEmailLogs {
|
||||
status = "skipped";
|
||||
|
||||
titleToken() {
|
||||
return i18n("admin.config.email_logs.sub_pages.skipped.title");
|
||||
}
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminEmailLogsRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.email_logs.title");
|
||||
}
|
||||
|
||||
setupController(controller) {
|
||||
controller.setProperties({
|
||||
loading: true,
|
||||
|
@ -0,0 +1,5 @@
|
||||
import AdminEmailIncomings from "admin/routes/admin-email-incomings";
|
||||
|
||||
export default class AdminEmailReceivedRoute extends AdminEmailIncomings {
|
||||
status = "received";
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user