Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38fdd842f5 | ||
|
|
aeab38aff1 | ||
|
|
aa8eff5e16 | ||
|
|
293cb7bde2 | ||
|
|
cfee0cfee9 | ||
|
|
c5e5b6d5ab | ||
|
|
184ce647ea | ||
|
|
f57ba758ce | ||
|
|
12a18d4d55 | ||
|
|
74349e17c9 | ||
|
|
1161c980f2 | ||
|
|
5e5024d3e7 | ||
|
|
64557c4076 | ||
|
|
303f97ce89 | ||
|
|
6b5743ba3c | ||
|
|
32ad46c551 | ||
|
|
5103d249aa | ||
|
|
39c2f63b35 | ||
|
|
6dcb099547 | ||
|
|
a373bf2a01 | ||
|
|
fd16eade7f | ||
|
|
52ef44f43b | ||
|
|
d89b537d8f | ||
|
|
7dd317b875 | ||
|
|
c213cc7211 | ||
|
|
0bd64788d2 | ||
|
|
272c31023d | ||
|
|
150a6601c0 | ||
|
|
9d1423b5aa | ||
|
|
5d46a16ca5 | ||
|
|
164b60cd07 | ||
|
|
5324216740 | ||
|
|
94fd884297 | ||
|
|
c190994046 | ||
|
|
62bbdd25ab | ||
|
|
2ea6675671 | ||
|
|
e50f51fa85 | ||
|
|
e700f0af93 | ||
|
|
7288bc277b | ||
|
|
be354e7950 | ||
|
|
84f590ab83 | ||
|
|
e6c04e2dc2 | ||
|
|
d0c6b33cc2 | ||
|
|
dfd6d6b999 | ||
|
|
22a7818399 | ||
|
|
a208ed0925 | ||
|
|
4cf065c480 | ||
|
|
d12f1878c9 | ||
|
|
b5721b7b4f | ||
|
|
bb317bd554 | ||
|
|
f75afc0979 | ||
|
|
8a8f2758d5 | ||
|
|
964f37476d | ||
|
|
0a5b078ac7 | ||
|
|
ab442058c0 | ||
|
|
72726830b5 | ||
|
|
f91af69ec4 | ||
|
|
59e5485408 | ||
|
|
05e713d098 | ||
|
|
b5bb41493a | ||
|
|
8c653cbc91 | ||
|
|
ad6edfc08a | ||
|
|
06848eaf49 | ||
|
|
e9a04dd6f1 | ||
|
|
8793297792 | ||
|
|
173a3b4d02 | ||
|
|
e4b11e7643 | ||
|
|
44bc284e0f | ||
|
|
03e3fd742e | ||
|
|
943068a634 | ||
|
|
5172749638 | ||
|
|
727100d1e2 | ||
|
|
6bb89ffea8 | ||
|
|
ada89d6124 | ||
|
|
60ce3d24fa | ||
|
|
7df40fc905 | ||
|
|
3e8d349465 | ||
|
|
8f1a5c9392 | ||
|
|
270e98e45f | ||
|
|
cd3c35418c | ||
|
|
29727408d6 | ||
|
|
0d9efa938b | ||
|
|
87ec058b8b | ||
|
|
168de52538 | ||
|
|
5893ad46ba | ||
|
|
118ce348f4 | ||
|
|
0df7743d78 | ||
|
|
5624dbaa9b | ||
|
|
0603bd57df | ||
|
|
2d0ad48dd1 | ||
|
|
4350a903ec | ||
|
|
f6063c684b | ||
|
|
e292c45924 | ||
|
|
73be7b3dd8 | ||
|
|
4f9afabf87 | ||
|
|
f144c64e13 | ||
|
|
dd07e0dbd0 | ||
|
|
673cd4196f | ||
|
|
3cab9d5f80 | ||
|
|
b1727d9748 | ||
|
|
059ac3d31a | ||
|
|
3c4bfb6a9f | ||
|
|
a99218677f | ||
|
|
ec40693f89 | ||
|
|
ba1b95c9f4 | ||
|
|
f38779adf4 | ||
|
|
5ea89d1fcb | ||
|
|
931eedeb66 | ||
|
|
22bccef8f4 | ||
|
|
008f71b961 | ||
|
|
2b5698a6ca | ||
|
|
5930744e1d | ||
|
|
d5ebcc3309 | ||
|
|
f76ea32246 | ||
|
|
c25d79168b | ||
|
|
a805013b86 | ||
|
|
7b1eb080ba | ||
|
|
d78fed7dc6 | ||
|
|
4f2dfd3857 | ||
|
|
54351e1b8a | ||
|
|
910bf74c2e | ||
|
|
27f7cf18b1 | ||
|
|
7f486cbc9b | ||
|
|
c659540475 | ||
|
|
9ec657f1fd | ||
|
|
12436d054d | ||
|
|
5fb2c1dde5 | ||
|
|
8eb2fa5fa9 | ||
|
|
6feb436303 | ||
|
|
b62d44b40a | ||
|
|
cf0a0945e4 | ||
|
|
500d0f6daf | ||
|
|
a252022117 | ||
|
|
b5cd22edb6 | ||
|
|
3f5fa4eb09 | ||
|
|
f2476d4b80 | ||
|
|
360d0dde65 | ||
|
|
1c881c1037 | ||
|
|
5e0c95ed83 | ||
|
|
2781264711 | ||
|
|
fa543cda06 | ||
|
|
1f88354c5e | ||
|
|
fdcb429145 | ||
|
|
a16ea24461 | ||
|
|
b4528b9e27 | ||
|
|
15cf62411a | ||
|
|
c52570ddc4 | ||
|
|
5f57b4b5aa | ||
|
|
6fc2cded55 | ||
|
|
e27c045f75 | ||
|
|
420214fc82 | ||
|
|
b5e736504a | ||
|
|
d28390054e | ||
|
|
62dc37ac35 | ||
|
|
41f933ce89 | ||
|
|
9e49abc0b9 | ||
|
|
28f8bdf91d | ||
|
|
3f908c047d | ||
|
|
c961dcc757 | ||
|
|
bfd4bfb824 | ||
|
|
36c8148377 | ||
|
|
a4e27da9e6 | ||
|
|
a89ed6b14a | ||
|
|
d694cc8109 | ||
|
|
9a58a97c45 | ||
|
|
08b2da4c1f | ||
|
|
e3977f84a3 | ||
|
|
2fcfaccb5c | ||
|
|
1c9f300896 | ||
|
|
26f77f03d5 | ||
|
|
cdcd20fe1e | ||
|
|
0dc9c6c96d | ||
|
|
5d6e8fdff0 | ||
|
|
aad0d5fcfb | ||
|
|
6b0aeced7e | ||
|
|
e08a0b509d | ||
|
|
36ad653fa9 | ||
|
|
66c50547b4 | ||
|
|
e022a7adec | ||
|
|
990b710ade | ||
|
|
fac78413c8 | ||
|
|
435761ef58 | ||
|
|
10e1831139 | ||
|
|
654ba44723 | ||
|
|
e204c61bd8 | ||
|
|
31480bde92 | ||
|
|
e52bbc1230 | ||
|
|
67c0498f64 | ||
|
|
e206bd8907 | ||
|
|
cb4a22b34f | ||
|
|
96d03ea9c0 |
20
.github/workflows/tests.yml
vendored
20
.github/workflows/tests.yml
vendored
@ -159,6 +159,22 @@ jobs:
|
|||||||
path: tmp/turbo_rspec_runtime.log
|
path: tmp/turbo_rspec_runtime.log
|
||||||
key: rspec-runtime-backend-core
|
key: rspec-runtime-backend-core
|
||||||
|
|
||||||
|
- name: Run Zeitwerk check
|
||||||
|
if: matrix.build_type == 'backend'
|
||||||
|
env:
|
||||||
|
LOAD_PLUGINS: ${{ (matrix.target == 'plugins') && '1' || '0' }}
|
||||||
|
run: |
|
||||||
|
if ! bin/rails zeitwerk:check --trace; then
|
||||||
|
echo
|
||||||
|
echo "---------------------------------------------"
|
||||||
|
echo
|
||||||
|
echo "::error::'bin/rails zeitwerk:check' failed - the app will fail to boot with 'eager_load=true' (e.g. in production)."
|
||||||
|
echo "To reproduce locally, run 'bin/rails zeitwerk:check'."
|
||||||
|
echo "Alternatively, you can run your local server/tests with the 'DISCOURSE_ZEITWERK_EAGER_LOAD=1' environment variable."
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Core RSpec
|
- name: Core RSpec
|
||||||
if: matrix.build_type == 'backend' && matrix.target == 'core'
|
if: matrix.build_type == 'backend' && matrix.target == 'core'
|
||||||
run: bin/turbo_rspec --verbose
|
run: bin/turbo_rspec --verbose
|
||||||
@ -182,11 +198,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Core System Tests
|
- name: Core System Tests
|
||||||
if: matrix.build_type == 'system' && matrix.target == 'core'
|
if: matrix.build_type == 'system' && matrix.target == 'core'
|
||||||
run: PARALLEL_TEST_PROCESSORS=1 bin/turbo_rspec --verbose spec/system
|
run: bin/rspec spec/system
|
||||||
|
|
||||||
- name: Plugin System Tests
|
- name: Plugin System Tests
|
||||||
if: matrix.build_type == 'system' && matrix.target == 'plugins'
|
if: matrix.build_type == 'system' && matrix.target == 'plugins'
|
||||||
run: LOAD_PLUGINS=1 PARALLEL_TEST_PROCESSORS=1 bin/turbo_rspec --verbose plugins/*/spec/system
|
run: LOAD_PLUGINS=1 bin/rspec plugins/*/spec/system
|
||||||
|
|
||||||
- name: Upload failed system test screenshots
|
- name: Upload failed system test screenshots
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
|||||||
@ -15,7 +15,7 @@ module.exports = {
|
|||||||
"directory-item-value",
|
"directory-item-value",
|
||||||
"directory-table-header-title",
|
"directory-table-header-title",
|
||||||
"loading-spinner",
|
"loading-spinner",
|
||||||
"mobile-directory-item-label",
|
"directory-item-label",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"no-implicit-this": {
|
"no-implicit-this": {
|
||||||
|
|||||||
2
Gemfile
2
Gemfile
@ -18,7 +18,7 @@ else
|
|||||||
# this allows us to include the bits of rails we use without pieces we do not.
|
# this allows us to include the bits of rails we use without pieces we do not.
|
||||||
#
|
#
|
||||||
# To issue a rails update bump the version number here
|
# To issue a rails update bump the version number here
|
||||||
rails_version = "7.0.4.1"
|
rails_version = "7.0.4.3"
|
||||||
gem "actionmailer", rails_version
|
gem "actionmailer", rails_version
|
||||||
gem "actionpack", rails_version
|
gem "actionpack", rails_version
|
||||||
gem "actionview", rails_version
|
gem "actionview", rails_version
|
||||||
|
|||||||
103
Gemfile.lock
103
Gemfile.lock
@ -17,25 +17,25 @@ GIT
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actionmailer (7.0.4.1)
|
actionmailer (7.0.4.3)
|
||||||
actionpack (= 7.0.4.1)
|
actionpack (= 7.0.4.3)
|
||||||
actionview (= 7.0.4.1)
|
actionview (= 7.0.4.3)
|
||||||
activejob (= 7.0.4.1)
|
activejob (= 7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (7.0.4.1)
|
actionpack (7.0.4.3)
|
||||||
actionview (= 7.0.4.1)
|
actionview (= 7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
rack (~> 2.0, >= 2.2.0)
|
rack (~> 2.0, >= 2.2.0)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actionview (7.0.4.1)
|
actionview (7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
@ -44,15 +44,15 @@ GEM
|
|||||||
actionview (>= 6.0.a)
|
actionview (>= 6.0.a)
|
||||||
active_model_serializers (0.8.4)
|
active_model_serializers (0.8.4)
|
||||||
activemodel (>= 3.0)
|
activemodel (>= 3.0)
|
||||||
activejob (7.0.4.1)
|
activejob (7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.0.4.1)
|
activemodel (7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
activerecord (7.0.4.1)
|
activerecord (7.0.4.3)
|
||||||
activemodel (= 7.0.4.1)
|
activemodel (= 7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
activesupport (7.0.4.1)
|
activesupport (7.0.4.3)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
@ -157,7 +157,7 @@ GEM
|
|||||||
faraday-net_http (>= 2.0, < 3.1)
|
faraday-net_http (>= 2.0, < 3.1)
|
||||||
ruby2_keywords (>= 0.0.4)
|
ruby2_keywords (>= 0.0.4)
|
||||||
faraday-net_http (3.0.2)
|
faraday-net_http (3.0.2)
|
||||||
faraday-retry (2.0.0)
|
faraday-retry (2.1.0)
|
||||||
faraday (~> 2.0)
|
faraday (~> 2.0)
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fast_xs (0.8.0)
|
fast_xs (0.8.0)
|
||||||
@ -167,10 +167,11 @@ GEM
|
|||||||
gc_tracer (1.5.1)
|
gc_tracer (1.5.1)
|
||||||
globalid (1.1.0)
|
globalid (1.1.0)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
google-protobuf (3.22.0)
|
google-protobuf (3.22.2)
|
||||||
google-protobuf (3.22.0-arm64-darwin)
|
google-protobuf (3.22.2-aarch64-linux)
|
||||||
google-protobuf (3.22.0-x86_64-darwin)
|
google-protobuf (3.22.2-arm64-darwin)
|
||||||
google-protobuf (3.22.0-x86_64-linux)
|
google-protobuf (3.22.2-x86_64-darwin)
|
||||||
|
google-protobuf (3.22.2-x86_64-linux)
|
||||||
guess_html_encoding (0.0.11)
|
guess_html_encoding (0.0.11)
|
||||||
hana (1.3.7)
|
hana (1.3.7)
|
||||||
hashdiff (1.0.1)
|
hashdiff (1.0.1)
|
||||||
@ -218,7 +219,7 @@ GEM
|
|||||||
logstash-event (1.2.02)
|
logstash-event (1.2.02)
|
||||||
logstash-logger (0.26.1)
|
logstash-logger (0.26.1)
|
||||||
logstash-event (~> 1.2)
|
logstash-event (~> 1.2)
|
||||||
logster (2.11.4)
|
logster (2.12.2)
|
||||||
loofah (2.19.1)
|
loofah (2.19.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
@ -239,10 +240,10 @@ GEM
|
|||||||
mini_sql (1.4.0)
|
mini_sql (1.4.0)
|
||||||
mini_suffix (0.3.3)
|
mini_suffix (0.3.3)
|
||||||
ffi (~> 1.9)
|
ffi (~> 1.9)
|
||||||
minitest (5.17.0)
|
minitest (5.18.0)
|
||||||
mocha (2.0.2)
|
mocha (2.0.2)
|
||||||
ruby2_keywords (>= 0.0.5)
|
ruby2_keywords (>= 0.0.5)
|
||||||
msgpack (1.6.0)
|
msgpack (1.6.1)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multi_xml (0.6.0)
|
multi_xml (0.6.0)
|
||||||
mustache (1.1.1)
|
mustache (1.1.1)
|
||||||
@ -311,10 +312,10 @@ GEM
|
|||||||
parallel (1.22.1)
|
parallel (1.22.1)
|
||||||
parallel_tests (4.2.0)
|
parallel_tests (4.2.0)
|
||||||
parallel
|
parallel
|
||||||
parser (3.2.1.0)
|
parser (3.2.1.1)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
pg (1.4.6)
|
pg (1.4.6)
|
||||||
prettier_print (1.2.0)
|
prettier_print (1.2.1)
|
||||||
progress (3.6.0)
|
progress (3.6.0)
|
||||||
pry (0.14.2)
|
pry (0.14.2)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
@ -328,12 +329,12 @@ GEM
|
|||||||
puma (6.1.1)
|
puma (6.1.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.6.2)
|
racc (1.6.2)
|
||||||
rack (2.2.6.2)
|
rack (2.2.6.4)
|
||||||
rack-mini-profiler (3.0.0)
|
rack-mini-profiler (3.0.0)
|
||||||
rack (>= 1.2.0)
|
rack (>= 1.2.0)
|
||||||
rack-protection (3.0.5)
|
rack-protection (3.0.5)
|
||||||
rack
|
rack
|
||||||
rack-test (2.0.2)
|
rack-test (2.1.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
@ -347,9 +348,9 @@ GEM
|
|||||||
rails_multisite (4.0.1)
|
rails_multisite (4.0.1)
|
||||||
activerecord (> 5.0, < 7.1)
|
activerecord (> 5.0, < 7.1)
|
||||||
railties (> 5.0, < 7.1)
|
railties (> 5.0, < 7.1)
|
||||||
railties (7.0.4.1)
|
railties (7.0.4.3)
|
||||||
actionpack (= 7.0.4.1)
|
actionpack (= 7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
@ -390,7 +391,7 @@ GEM
|
|||||||
rspec-html-matchers (0.10.0)
|
rspec-html-matchers (0.10.0)
|
||||||
nokogiri (~> 1)
|
nokogiri (~> 1)
|
||||||
rspec (>= 3.0.0.a)
|
rspec (>= 3.0.0.a)
|
||||||
rspec-mocks (3.12.3)
|
rspec-mocks (3.12.4)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.12.0)
|
rspec-support (~> 3.12.0)
|
||||||
rspec-rails (6.0.1)
|
rspec-rails (6.0.1)
|
||||||
@ -411,7 +412,7 @@ GEM
|
|||||||
rspec-core (>= 2.14)
|
rspec-core (>= 2.14)
|
||||||
rtlcss (0.2.0)
|
rtlcss (0.2.0)
|
||||||
mini_racer (~> 0.6.3)
|
mini_racer (~> 0.6.3)
|
||||||
rubocop (1.47.0)
|
rubocop (1.48.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.2.0.0)
|
parser (>= 3.2.0.0)
|
||||||
@ -425,14 +426,14 @@ GEM
|
|||||||
parser (>= 3.2.1.0)
|
parser (>= 3.2.1.0)
|
||||||
rubocop-capybara (2.17.1)
|
rubocop-capybara (2.17.1)
|
||||||
rubocop (~> 1.41)
|
rubocop (~> 1.41)
|
||||||
rubocop-discourse (3.1.0)
|
rubocop-discourse (3.2.0)
|
||||||
rubocop (>= 1.1.0)
|
rubocop (>= 1.1.0)
|
||||||
rubocop-rspec (>= 2.0.0)
|
rubocop-rspec (>= 2.0.0)
|
||||||
rubocop-rspec (2.18.1)
|
rubocop-rspec (2.19.0)
|
||||||
rubocop (~> 1.33)
|
rubocop (~> 1.33)
|
||||||
rubocop-capybara (~> 2.17)
|
rubocop-capybara (~> 2.17)
|
||||||
ruby-prof (1.6.1)
|
ruby-prof (1.6.1)
|
||||||
ruby-progressbar (1.12.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-readability (0.7.0)
|
ruby-readability (0.7.0)
|
||||||
guess_html_encoding (>= 0.0.4)
|
guess_html_encoding (>= 0.0.4)
|
||||||
nokogiri (>= 1.6.0)
|
nokogiri (>= 1.6.0)
|
||||||
@ -441,16 +442,16 @@ GEM
|
|||||||
sanitize (6.0.1)
|
sanitize (6.0.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
sass-embedded (1.58.3)
|
sass-embedded (1.59.2)
|
||||||
google-protobuf (~> 3.21)
|
google-protobuf (~> 3.21)
|
||||||
rake (>= 10.0.0)
|
rake (>= 10.0.0)
|
||||||
sass-embedded (1.58.3-aarch64-linux-gnu)
|
sass-embedded (1.59.2-aarch64-linux-gnu)
|
||||||
google-protobuf (~> 3.21)
|
google-protobuf (~> 3.21)
|
||||||
sass-embedded (1.58.3-arm64-darwin)
|
sass-embedded (1.59.2-arm64-darwin)
|
||||||
google-protobuf (~> 3.21)
|
google-protobuf (~> 3.21)
|
||||||
sass-embedded (1.58.3-x86_64-darwin)
|
sass-embedded (1.59.2-x86_64-darwin)
|
||||||
google-protobuf (~> 3.21)
|
google-protobuf (~> 3.21)
|
||||||
sass-embedded (1.58.3-x86_64-linux-gnu)
|
sass-embedded (1.59.2-x86_64-linux-gnu)
|
||||||
google-protobuf (~> 3.21)
|
google-protobuf (~> 3.21)
|
||||||
selenium-webdriver (4.8.1)
|
selenium-webdriver (4.8.1)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
@ -477,7 +478,7 @@ GEM
|
|||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sshkey (2.0.0)
|
sshkey (2.0.0)
|
||||||
stackprof (0.2.23)
|
stackprof (0.2.23)
|
||||||
syntax_tree (6.0.1)
|
syntax_tree (6.0.2)
|
||||||
prettier_print (>= 1.2.0)
|
prettier_print (>= 1.2.0)
|
||||||
syntax_tree-disable_ternary (1.0.0)
|
syntax_tree-disable_ternary (1.0.0)
|
||||||
test-prof (1.2.0)
|
test-prof (1.2.0)
|
||||||
@ -533,14 +534,14 @@ PLATFORMS
|
|||||||
x86_64-linux
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
actionmailer (= 7.0.4.1)
|
actionmailer (= 7.0.4.3)
|
||||||
actionpack (= 7.0.4.1)
|
actionpack (= 7.0.4.3)
|
||||||
actionview (= 7.0.4.1)
|
actionview (= 7.0.4.3)
|
||||||
actionview_precompiler
|
actionview_precompiler
|
||||||
active_model_serializers (~> 0.8.3)
|
active_model_serializers (~> 0.8.3)
|
||||||
activemodel (= 7.0.4.1)
|
activemodel (= 7.0.4.3)
|
||||||
activerecord (= 7.0.4.1)
|
activerecord (= 7.0.4.3)
|
||||||
activesupport (= 7.0.4.1)
|
activesupport (= 7.0.4.3)
|
||||||
addressable
|
addressable
|
||||||
annotate
|
annotate
|
||||||
aws-sdk-s3
|
aws-sdk-s3
|
||||||
@ -626,7 +627,7 @@ DEPENDENCIES
|
|||||||
rack-protection
|
rack-protection
|
||||||
rails_failover
|
rails_failover
|
||||||
rails_multisite
|
rails_multisite
|
||||||
railties (= 7.0.4.1)
|
railties (= 7.0.4.3)
|
||||||
rake
|
rake
|
||||||
rb-fsevent
|
rb-fsevent
|
||||||
rbtrace
|
rbtrace
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import RESTAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RESTAdapter.extend({
|
export default class ApiKey extends RestAdapter {
|
||||||
jsonMode: true,
|
jsonMode = true;
|
||||||
|
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/api/";
|
return "/admin/api/";
|
||||||
},
|
}
|
||||||
|
|
||||||
apiNameFor() {
|
apiNameFor() {
|
||||||
return "key";
|
return "key";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default function buildPluginAdapter(pluginName) {
|
export default function buildPluginAdapter(pluginName) {
|
||||||
return RestAdapter.extend({
|
return class extends RestAdapter {
|
||||||
pathFor(store, type, findArgs) {
|
pathFor(store, type, findArgs) {
|
||||||
return (
|
return (
|
||||||
"/admin/plugins/" + pluginName + this._super(store, type, findArgs)
|
"/admin/plugins/" + pluginName + super.pathFor(store, type, findArgs)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class CustomizationBase extends RestAdapter {
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/customize/";
|
return "/admin/customize/";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class EmailStyle extends RestAdapter {
|
||||||
pathFor() {
|
pathFor() {
|
||||||
return "/admin/customize/email_style";
|
return "/admin/customize/email_style";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class Embedding extends RestAdapter {
|
||||||
pathFor() {
|
pathFor() {
|
||||||
return "/admin/customize/embedding";
|
return "/admin/customize/embedding";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class StaffActionLog extends RestAdapter {
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/logs/";
|
return "/admin/logs/";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class TagGroup extends RestAdapter {
|
||||||
jsonMode: true,
|
jsonMode = true;
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import RestAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RestAdapter.extend({
|
export default class Theme extends RestAdapter {
|
||||||
|
jsonMode = true;
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/";
|
return "/admin/";
|
||||||
},
|
}
|
||||||
|
|
||||||
afterFindAll(results) {
|
afterFindAll(results) {
|
||||||
let map = {};
|
let map = {};
|
||||||
@ -20,7 +21,5 @@ export default RestAdapter.extend({
|
|||||||
theme.set("parentThemes", mappedParents);
|
theme.set("parentThemes", mappedParents);
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
},
|
}
|
||||||
|
}
|
||||||
jsonMode: true,
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RESTAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RESTAdapter.extend({
|
export default class WebHookEvent extends RestAdapter {
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/api/";
|
return "/admin/api/";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import RESTAdapter from "discourse/adapters/rest";
|
import RestAdapter from "discourse/adapters/rest";
|
||||||
|
|
||||||
export default RESTAdapter.extend({
|
export default class WebHook extends RestAdapter {
|
||||||
basePath() {
|
basePath() {
|
||||||
return "/admin/api/";
|
return "/admin/api/";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
{{#if this.hasInactiveThemes}}
|
{{#if this.hasInactiveThemes}}
|
||||||
{{#each this.inactiveThemes as |theme|}}
|
{{#each this.inactiveThemes as |theme|}}
|
||||||
<ThemesListItem
|
<ThemesListItem
|
||||||
|
@classNames="inactive-theme"
|
||||||
@theme={{theme}}
|
@theme={{theme}}
|
||||||
@navigateToTheme={{action "navigateToTheme" theme}}
|
@navigateToTheme={{action "navigateToTheme" theme}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -2,18 +2,18 @@ import Controller from "@ember/controller";
|
|||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminApiKeysIndexController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
revokeKey(key) {
|
revokeKey(key) {
|
||||||
key.revoke().catch(popupAjaxError);
|
key.revoke().catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
undoRevokeKey(key) {
|
undoRevokeKey(key) {
|
||||||
key.undoRevoke().catch(popupAjaxError);
|
key.undoRevoke().catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
@ -35,5 +35,5 @@ export default Controller.extend({
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,37 +1,32 @@
|
|||||||
|
import { equal } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { isBlank } from "@ember/utils";
|
import { isBlank } from "@ember/utils";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { action, get } from "@ember/object";
|
import { action, get } from "@ember/object";
|
||||||
import { equal } from "@ember/object/computed";
|
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminApiKeysNewController extends Controller {
|
||||||
userModes: null,
|
userModes = [
|
||||||
scopeModes: null,
|
{ id: "all", name: I18n.t("admin.api.all_users") },
|
||||||
globalScopes: null,
|
{ id: "single", name: I18n.t("admin.api.single_user") },
|
||||||
scopes: null,
|
];
|
||||||
|
scopeModes = [
|
||||||
|
{ id: "granular", name: I18n.t("admin.api.scopes.granular") },
|
||||||
|
{ id: "read_only", name: I18n.t("admin.api.scopes.read_only") },
|
||||||
|
{ id: "global", name: I18n.t("admin.api.scopes.global") },
|
||||||
|
];
|
||||||
|
globalScopes = null;
|
||||||
|
scopes = null;
|
||||||
|
|
||||||
|
@equal("userMode", "single") showUserSelector;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
this.set("userModes", [
|
|
||||||
{ id: "all", name: I18n.t("admin.api.all_users") },
|
|
||||||
{ id: "single", name: I18n.t("admin.api.single_user") },
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.set("scopeModes", [
|
|
||||||
{ id: "granular", name: I18n.t("admin.api.scopes.granular") },
|
|
||||||
{ id: "read_only", name: I18n.t("admin.api.scopes.read_only") },
|
|
||||||
{ id: "global", name: I18n.t("admin.api.scopes.global") },
|
|
||||||
]);
|
|
||||||
|
|
||||||
this._loadScopes();
|
this._loadScopes();
|
||||||
},
|
}
|
||||||
|
|
||||||
showUserSelector: equal("userMode", "single"),
|
|
||||||
|
|
||||||
@discourseComputed("model.{description,username}", "showUserSelector")
|
@discourseComputed("model.{description,username}", "showUserSelector")
|
||||||
saveDisabled(model, showUserSelector) {
|
saveDisabled(model, showUserSelector) {
|
||||||
@ -42,12 +37,12 @@ export default Controller.extend({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateUsername(selected) {
|
updateUsername(selected) {
|
||||||
this.set("model.username", get(selected, "firstObject"));
|
this.set("model.username", get(selected, "firstObject"));
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeUserMode(userMode) {
|
changeUserMode(userMode) {
|
||||||
@ -55,12 +50,12 @@ export default Controller.extend({
|
|||||||
this.model.set("username", null);
|
this.model.set("username", null);
|
||||||
}
|
}
|
||||||
this.set("userMode", userMode);
|
this.set("userMode", userMode);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeScopeMode(scopeMode) {
|
changeScopeMode(scopeMode) {
|
||||||
this.set("scopeMode", scopeMode);
|
this.set("scopeMode", scopeMode);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
save() {
|
save() {
|
||||||
@ -77,12 +72,12 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.model.save().catch(popupAjaxError);
|
return this.model.save().catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
continue() {
|
continue() {
|
||||||
this.transitionToRoute("adminApiKeys.show", this.model.id);
|
this.transitionToRoute("adminApiKeys.show", this.model.id);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showURLs(urls) {
|
showURLs(urls) {
|
||||||
@ -90,7 +85,7 @@ export default Controller.extend({
|
|||||||
admin: true,
|
admin: true,
|
||||||
model: { urls },
|
model: { urls },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_loadScopes() {
|
_loadScopes() {
|
||||||
return ajax("/admin/api/keys/scopes.json")
|
return ajax("/admin/api/keys/scopes.json")
|
||||||
@ -102,5 +97,5 @@ export default Controller.extend({
|
|||||||
this.set("scopes", data.scopes);
|
this.set("scopes", data.scopes);
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,66 +1,74 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { empty } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||||
import { empty } from "@ember/object/computed";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default Controller.extend(bufferedProperty("model"), {
|
export default class AdminApiKeysShowController extends Controller.extend(
|
||||||
isNew: empty("model.id"),
|
bufferedProperty("model")
|
||||||
|
) {
|
||||||
|
@empty("model.id") isNew;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
saveDescription() {
|
saveDescription() {
|
||||||
const buffered = this.buffered;
|
const buffered = this.buffered;
|
||||||
const attrs = buffered.getProperties("description");
|
const attrs = buffered.getProperties("description");
|
||||||
|
|
||||||
this.model
|
this.model
|
||||||
.save(attrs)
|
.save(attrs)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.set("editingDescription", false);
|
this.set("editingDescription", false);
|
||||||
this.rollbackBuffer();
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
const id = this.get("userField.id");
|
|
||||||
if (isEmpty(id)) {
|
|
||||||
this.destroyAction(this.userField);
|
|
||||||
} else {
|
|
||||||
this.rollbackBuffer();
|
this.rollbackBuffer();
|
||||||
this.set("editing", false);
|
})
|
||||||
}
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
editDescription() {
|
@action
|
||||||
this.toggleProperty("editingDescription");
|
cancel() {
|
||||||
if (!this.editingDescription) {
|
const id = this.get("userField.id");
|
||||||
this.rollbackBuffer();
|
if (isEmpty(id)) {
|
||||||
}
|
this.destroyAction(this.userField);
|
||||||
},
|
} else {
|
||||||
|
this.rollbackBuffer();
|
||||||
|
this.set("editing", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
revokeKey(key) {
|
@action
|
||||||
key.revoke().catch(popupAjaxError);
|
editDescription() {
|
||||||
},
|
this.toggleProperty("editingDescription");
|
||||||
|
if (!this.editingDescription) {
|
||||||
|
this.rollbackBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deleteKey(key) {
|
@action
|
||||||
key
|
revokeKey(key) {
|
||||||
.destroyRecord()
|
key.revoke().catch(popupAjaxError);
|
||||||
.then(() => this.transitionToRoute("adminApiKeys.index"))
|
}
|
||||||
.catch(popupAjaxError);
|
|
||||||
},
|
|
||||||
|
|
||||||
undoRevokeKey(key) {
|
@action
|
||||||
key.undoRevoke().catch(popupAjaxError);
|
deleteKey(key) {
|
||||||
},
|
key
|
||||||
|
.destroyRecord()
|
||||||
|
.then(() => this.transitionToRoute("adminApiKeys.index"))
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
}
|
||||||
|
|
||||||
showURLs(urls) {
|
@action
|
||||||
return showModal("admin-api-key-urls", {
|
undoRevokeKey(key) {
|
||||||
admin: true,
|
key.undoRevoke().catch(popupAjaxError);
|
||||||
model: {
|
}
|
||||||
urls,
|
|
||||||
},
|
@action
|
||||||
});
|
showURLs(urls) {
|
||||||
},
|
return showModal("admin-api-key-urls", {
|
||||||
},
|
admin: true,
|
||||||
});
|
model: {
|
||||||
|
urls,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Controller.extend();
|
export default class AdminApiKeysController extends Controller {}
|
||||||
|
|||||||
@ -1,19 +1,21 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { alias, equal } from "@ember/object/computed";
|
import { alias, equal } from "@ember/object/computed";
|
||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import { i18n, setting } from "discourse/lib/computed";
|
import { i18n, setting } from "discourse/lib/computed";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminBackupsIndexController extends Controller {
|
||||||
adminBackups: controller(),
|
@service dialog;
|
||||||
dialog: service(),
|
@controller adminBackups;
|
||||||
status: alias("adminBackups.model"),
|
|
||||||
uploadLabel: i18n("admin.backups.upload.label"),
|
@alias("adminBackups.model") status;
|
||||||
backupLocation: setting("backup_location"),
|
@i18n("admin.backups.upload.label") uploadLabel;
|
||||||
localBackupStorage: equal("backupLocation", "local"),
|
@setting("backup_location") backupLocation;
|
||||||
|
@equal("backupLocation", "local") localBackupStorage;
|
||||||
|
|
||||||
@discourseComputed("status.allowRestore", "status.isOperationRunning")
|
@discourseComputed("status.allowRestore", "status.isOperationRunning")
|
||||||
restoreTitle(allowRestore, isOperationRunning) {
|
restoreTitle(allowRestore, isOperationRunning) {
|
||||||
@ -24,35 +26,35 @@ export default Controller.extend({
|
|||||||
} else {
|
} else {
|
||||||
return "admin.backups.operations.restore.title";
|
return "admin.backups.operations.restore.title";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
toggleReadOnlyMode() {
|
toggleReadOnlyMode() {
|
||||||
if (!this.site.get("isReadOnly")) {
|
if (!this.site.get("isReadOnly")) {
|
||||||
this.dialog.yesNoConfirm({
|
this.dialog.yesNoConfirm({
|
||||||
message: I18n.t("admin.backups.read_only.enable.confirm"),
|
message: I18n.t("admin.backups.read_only.enable.confirm"),
|
||||||
didConfirm: () => {
|
didConfirm: () => {
|
||||||
this.set("currentUser.hideReadOnlyAlert", true);
|
this.set("currentUser.hideReadOnlyAlert", true);
|
||||||
this._toggleReadOnlyMode(true);
|
this._toggleReadOnlyMode(true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._toggleReadOnlyMode(false);
|
this._toggleReadOnlyMode(false);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
download(backup) {
|
@action
|
||||||
const link = backup.get("filename");
|
download(backup) {
|
||||||
ajax(`/admin/backups/${link}`, { type: "PUT" }).then(() =>
|
const link = backup.get("filename");
|
||||||
this.dialog.alert(I18n.t("admin.backups.operations.download.alert"))
|
ajax(`/admin/backups/${link}`, { type: "PUT" }).then(() =>
|
||||||
);
|
this.dialog.alert(I18n.t("admin.backups.operations.download.alert"))
|
||||||
},
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
_toggleReadOnlyMode(enable) {
|
_toggleReadOnlyMode(enable) {
|
||||||
ajax("/admin/backups/readonly", {
|
ajax("/admin/backups/readonly", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { enable },
|
data: { enable },
|
||||||
}).then(() => this.site.set("isReadOnly", enable));
|
}).then(() => this.site.set("isReadOnly", enable));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminBackupsLogsController extends Controller {
|
||||||
adminBackups: controller(),
|
@controller adminBackups;
|
||||||
status: alias("adminBackups.model"),
|
|
||||||
|
|
||||||
init() {
|
@alias("adminBackups.model") status;
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this.logs = [];
|
logs = [];
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import { and, not } from "@ember/object/computed";
|
import { and, not } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
export default Controller.extend({
|
export default class AdminBackupsController extends Controller {
|
||||||
noOperationIsRunning: not("model.isOperationRunning"),
|
@not("model.isOperationRunning") noOperationIsRunning;
|
||||||
rollbackEnabled: and(
|
@not("rollbackEnabled") rollbackDisabled;
|
||||||
"model.canRollback",
|
@and("model.canRollback", "model.restoreEnabled", "noOperationIsRunning")
|
||||||
"model.restoreEnabled",
|
rollbackEnabled;
|
||||||
"noOperationIsRunning"
|
}
|
||||||
),
|
|
||||||
rollbackDisabled: not("rollbackEnabled"),
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeColorsController extends Controller {
|
||||||
@discourseComputed("model.@each.id")
|
@discourseComputed("model.@each.id")
|
||||||
baseColorScheme() {
|
baseColorScheme() {
|
||||||
return this.model.findBy("is_base", true);
|
return this.model.findBy("is_base", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.@each.id")
|
@discourseComputed("model.@each.id")
|
||||||
baseColorSchemes() {
|
baseColorSchemes() {
|
||||||
return this.model.filterBy("is_base", true);
|
return this.model.filterBy("is_base", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("baseColorScheme")
|
@discourseComputed("baseColorScheme")
|
||||||
baseColors(baseColorScheme) {
|
baseColors(baseColorScheme) {
|
||||||
@ -22,28 +22,28 @@ export default Controller.extend({
|
|||||||
baseColorsHash.set(color.get("name"), color);
|
baseColorsHash.set(color.get("name"), color);
|
||||||
});
|
});
|
||||||
return baseColorsHash;
|
return baseColorsHash;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
newColorSchemeWithBase(baseKey) {
|
newColorSchemeWithBase(baseKey) {
|
||||||
const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey);
|
const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey);
|
||||||
const newColorScheme = base.copy();
|
const newColorScheme = base.copy();
|
||||||
newColorScheme.setProperties({
|
newColorScheme.setProperties({
|
||||||
name: I18n.t("admin.customize.colors.new_name"),
|
name: I18n.t("admin.customize.colors.new_name"),
|
||||||
base_scheme_id: base.get("base_scheme_id"),
|
base_scheme_id: base.get("base_scheme_id"),
|
||||||
});
|
});
|
||||||
newColorScheme.save().then(() => {
|
newColorScheme.save().then(() => {
|
||||||
this.model.pushObject(newColorScheme);
|
this.model.pushObject(newColorScheme);
|
||||||
newColorScheme.set("savingStatus", null);
|
newColorScheme.set("savingStatus", null);
|
||||||
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
newColorScheme() {
|
@action
|
||||||
showModal("admin-color-scheme-select-base", {
|
newColorScheme() {
|
||||||
model: this.baseColorSchemes,
|
showModal("admin-color-scheme-select-base", {
|
||||||
admin: true,
|
model: this.baseColorSchemes,
|
||||||
});
|
admin: true,
|
||||||
},
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,38 +1,38 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeEmailStyleEditController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
|
|
||||||
@discourseComputed("model.isSaving")
|
@discourseComputed("model.isSaving")
|
||||||
saveButtonText(isSaving) {
|
saveButtonText(isSaving) {
|
||||||
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.changed", "model.isSaving")
|
@discourseComputed("model.changed", "model.isSaving")
|
||||||
saveDisabled(changed, isSaving) {
|
saveDisabled(changed, isSaving) {
|
||||||
return !changed || isSaving;
|
return !changed || isSaving;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
save() {
|
save() {
|
||||||
if (!this.model.saving) {
|
if (!this.model.saving) {
|
||||||
this.set("saving", true);
|
this.set("saving", true);
|
||||||
this.model
|
this.model
|
||||||
.update(this.model.getProperties("html", "css"))
|
.update(this.model.getProperties("html", "css"))
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
const msg =
|
const msg =
|
||||||
e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors
|
e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors
|
||||||
? I18n.t("admin.customize.email_style.save_error_with_reason", {
|
? I18n.t("admin.customize.email_style.save_error_with_reason", {
|
||||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||||
})
|
})
|
||||||
: I18n.t("generic_error");
|
: I18n.t("generic_error");
|
||||||
this.dialog.alert(msg);
|
this.dialog.alert(msg);
|
||||||
})
|
})
|
||||||
.finally(() => this.set("model.changed", false));
|
.finally(() => this.set("model.changed", false));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,23 +1,26 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend(bufferedProperty("emailTemplate"), {
|
export default class AdminCustomizeEmailTemplatesEditController extends Controller.extend(
|
||||||
adminCustomizeEmailTemplates: controller(),
|
bufferedProperty("emailTemplate")
|
||||||
dialog: service(),
|
) {
|
||||||
emailTemplate: null,
|
@service dialog;
|
||||||
saved: false,
|
@controller adminCustomizeEmailTemplates;
|
||||||
|
|
||||||
|
emailTemplate = null;
|
||||||
|
saved = false;
|
||||||
|
|
||||||
@discourseComputed("buffered.body", "buffered.subject")
|
@discourseComputed("buffered.body", "buffered.subject")
|
||||||
saveDisabled(body, subject) {
|
saveDisabled(body, subject) {
|
||||||
return (
|
return (
|
||||||
this.emailTemplate.body === body && this.emailTemplate.subject === subject
|
this.emailTemplate.body === body && this.emailTemplate.subject === subject
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("buffered")
|
@discourseComputed("buffered")
|
||||||
hasMultipleSubjects(buffered) {
|
hasMultipleSubjects(buffered) {
|
||||||
@ -26,7 +29,7 @@ export default Controller.extend(bufferedProperty("emailTemplate"), {
|
|||||||
} else {
|
} else {
|
||||||
return buffered.getProperties("id")["id"];
|
return buffered.getProperties("id")["id"];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
saveChanges() {
|
saveChanges() {
|
||||||
@ -38,7 +41,7 @@ export default Controller.extend(bufferedProperty("emailTemplate"), {
|
|||||||
this.set("saved", true);
|
this.set("saved", true);
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
revertChanges() {
|
revertChanges() {
|
||||||
@ -57,5 +60,5 @@ export default Controller.extend(bufferedProperty("emailTemplate"), {
|
|||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,18 +1,13 @@
|
|||||||
|
import { sort } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { sort } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeEmailTemplatesController extends Controller {
|
||||||
sortedTemplates: sort("emailTemplates", "titleSorting"),
|
titleSorting = ["title"];
|
||||||
|
@sort("emailTemplates", "titleSorting") sortedTemplates;
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this.set("titleSorting", ["title"]);
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onSelectTemplate(template) {
|
onSelectTemplate(template) {
|
||||||
this.transitionToRoute("adminCustomizeEmailTemplates.edit", template);
|
this.transitionToRoute("adminCustomizeEmailTemplates.edit", template);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,47 +1,52 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { not } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||||
import { not } from "@ember/object/computed";
|
|
||||||
import { propertyEqual } from "discourse/lib/computed";
|
import { propertyEqual } from "discourse/lib/computed";
|
||||||
|
|
||||||
export default Controller.extend(bufferedProperty("model"), {
|
export default class AdminCustomizeRobotsTxtController extends Controller.extend(
|
||||||
saved: false,
|
bufferedProperty("model")
|
||||||
isSaving: false,
|
) {
|
||||||
saveDisabled: propertyEqual("model.robots_txt", "buffered.robots_txt"),
|
saved = false;
|
||||||
resetDisabled: not("model.overridden"),
|
isSaving = false;
|
||||||
|
|
||||||
actions: {
|
@propertyEqual("model.robots_txt", "buffered.robots_txt") saveDisabled;
|
||||||
save() {
|
|
||||||
this.setProperties({
|
|
||||||
isSaving: true,
|
|
||||||
saved: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
ajax("robots.json", {
|
@not("model.overridden") resetDisabled;
|
||||||
type: "PUT",
|
|
||||||
data: { robots_txt: this.buffered.get("robots_txt") },
|
@action
|
||||||
|
save() {
|
||||||
|
this.setProperties({
|
||||||
|
isSaving: true,
|
||||||
|
saved: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
ajax("robots.json", {
|
||||||
|
type: "PUT",
|
||||||
|
data: { robots_txt: this.buffered.get("robots_txt") },
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
this.commitBuffer();
|
||||||
|
this.set("saved", true);
|
||||||
|
this.set("model.overridden", data.overridden);
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.finally(() => this.set("isSaving", false));
|
||||||
this.commitBuffer();
|
}
|
||||||
this.set("saved", true);
|
|
||||||
this.set("model.overridden", data.overridden);
|
|
||||||
})
|
|
||||||
.finally(() => this.set("isSaving", false));
|
|
||||||
},
|
|
||||||
|
|
||||||
reset() {
|
@action
|
||||||
this.setProperties({
|
reset() {
|
||||||
isSaving: true,
|
this.setProperties({
|
||||||
saved: false,
|
isSaving: true,
|
||||||
});
|
saved: false,
|
||||||
ajax("robots.json", { type: "DELETE" })
|
});
|
||||||
.then((data) => {
|
ajax("robots.json", { type: "DELETE" })
|
||||||
this.buffered.set("robots_txt", data.robots_txt);
|
.then((data) => {
|
||||||
this.commitBuffer();
|
this.buffered.set("robots_txt", data.robots_txt);
|
||||||
this.set("saved", true);
|
this.commitBuffer();
|
||||||
this.set("model.overridden", false);
|
this.set("saved", true);
|
||||||
})
|
this.set("model.overridden", false);
|
||||||
.finally(() => this.set("isSaving", false));
|
})
|
||||||
},
|
.finally(() => this.set("isSaving", false));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,21 +1,24 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { url } from "discourse/lib/computed";
|
import { url } from "discourse/lib/computed";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeThemesEditController extends Controller {
|
||||||
section: null,
|
section = null;
|
||||||
currentTarget: 0,
|
currentTarget = 0;
|
||||||
maximized: false,
|
maximized = false;
|
||||||
previewUrl: url("model.id", "/admin/themes/%@/preview"),
|
|
||||||
showAdvanced: false,
|
@url("model.id", "/admin/themes/%@/preview") previewUrl;
|
||||||
editRouteName: "adminCustomizeThemes.edit",
|
|
||||||
showRouteName: "adminCustomizeThemes.show",
|
showAdvanced = false;
|
||||||
|
editRouteName = "adminCustomizeThemes.edit";
|
||||||
|
showRouteName = "adminCustomizeThemes.show";
|
||||||
|
|
||||||
setTargetName(name) {
|
setTargetName(name) {
|
||||||
const target = this.get("model.targets").find((t) => t.name === name);
|
const target = this.get("model.targets").find((t) => t.name === name);
|
||||||
this.set("currentTarget", target && target.id);
|
this.set("currentTarget", target && target.id);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentTarget")
|
@discourseComputed("currentTarget")
|
||||||
currentTargetName(id) {
|
currentTargetName(id) {
|
||||||
@ -23,50 +26,52 @@ export default Controller.extend({
|
|||||||
(t) => t.id === parseInt(id, 10)
|
(t) => t.id === parseInt(id, 10)
|
||||||
);
|
);
|
||||||
return target && target.name;
|
return target && target.name;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.isSaving")
|
@discourseComputed("model.isSaving")
|
||||||
saveButtonText(isSaving) {
|
saveButtonText(isSaving) {
|
||||||
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.changed", "model.isSaving")
|
@discourseComputed("model.changed", "model.isSaving")
|
||||||
saveDisabled(changed, isSaving) {
|
saveDisabled(changed, isSaving) {
|
||||||
return !changed || isSaving;
|
return !changed || isSaving;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
save() {
|
save() {
|
||||||
this.set("saving", true);
|
this.set("saving", true);
|
||||||
this.model.saveChanges("theme_fields").finally(() => {
|
this.model.saveChanges("theme_fields").finally(() => {
|
||||||
this.set("saving", false);
|
this.set("saving", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
fieldAdded(target, name) {
|
@action
|
||||||
this.replaceRoute(this.editRouteName, this.get("model.id"), target, name);
|
fieldAdded(target, name) {
|
||||||
},
|
this.replaceRoute(this.editRouteName, this.get("model.id"), target, name);
|
||||||
|
}
|
||||||
|
|
||||||
onlyOverriddenChanged(onlyShowOverridden) {
|
@action
|
||||||
if (onlyShowOverridden) {
|
onlyOverriddenChanged(onlyShowOverridden) {
|
||||||
if (!this.model.hasEdited(this.currentTargetName, this.fieldName)) {
|
if (onlyShowOverridden) {
|
||||||
let firstTarget = this.get("model.targets").find((t) => t.edited);
|
if (!this.model.hasEdited(this.currentTargetName, this.fieldName)) {
|
||||||
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
|
let firstTarget = this.get("model.targets").find((t) => t.edited);
|
||||||
(f) => f.edited
|
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
|
||||||
);
|
(f) => f.edited
|
||||||
|
);
|
||||||
|
|
||||||
this.replaceRoute(
|
this.replaceRoute(
|
||||||
this.editRouteName,
|
this.editRouteName,
|
||||||
this.get("model.id"),
|
this.get("model.id"),
|
||||||
firstTarget.name,
|
firstTarget.name,
|
||||||
firstField.name
|
firstField.name
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
goBack() {
|
@action
|
||||||
this.replaceRoute(this.showRouteName, this.model.id);
|
goBack() {
|
||||||
},
|
this.replaceRoute(this.showRouteName, this.model.id);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
import { inject as service } from "@ember/service";
|
||||||
import {
|
import {
|
||||||
empty,
|
empty,
|
||||||
filterBy,
|
filterBy,
|
||||||
@ -6,8 +6,9 @@ import {
|
|||||||
match,
|
match,
|
||||||
notEmpty,
|
notEmpty,
|
||||||
} from "@ember/object/computed";
|
} from "@ember/object/computed";
|
||||||
|
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ThemeSettings from "admin/models/theme-settings";
|
import ThemeSettings from "admin/models/theme-settings";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
@ -15,31 +16,35 @@ import { makeArray } from "discourse-common/lib/helpers";
|
|||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
import { url } from "discourse/lib/computed";
|
import { url } from "discourse/lib/computed";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
const THEME_UPLOAD_VAR = 2;
|
const THEME_UPLOAD_VAR = 2;
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeThemesShowController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
downloadUrl: url("model.id", "/admin/customize/themes/%@/export"),
|
|
||||||
previewUrl: url("model.id", "/admin/themes/%@/preview"),
|
editRouteName = "adminCustomizeThemes.edit";
|
||||||
addButtonDisabled: empty("selectedChildThemeId"),
|
|
||||||
editRouteName: "adminCustomizeThemes.edit",
|
@url("model.id", "/admin/customize/themes/%@/export") downloadUrl;
|
||||||
parentThemesNames: mapBy("model.parentThemes", "name"),
|
@url("model.id", "/admin/themes/%@/preview") previewUrl;
|
||||||
availableParentThemes: filterBy("allThemes", "component", false),
|
@empty("selectedChildThemeId") addButtonDisabled;
|
||||||
availableActiveParentThemes: filterBy("availableParentThemes", "isActive"),
|
@mapBy("model.parentThemes", "name") parentThemesNames;
|
||||||
availableThemesNames: mapBy("availableParentThemes", "name"),
|
@filterBy("allThemes", "component", false) availableParentThemes;
|
||||||
availableActiveThemesNames: mapBy("availableActiveParentThemes", "name"),
|
@filterBy("availableParentThemes", "isActive") availableActiveParentThemes;
|
||||||
availableActiveChildThemes: filterBy("availableChildThemes", "hasParents"),
|
@mapBy("availableParentThemes", "name") availableThemesNames;
|
||||||
availableComponentsNames: mapBy("availableChildThemes", "name"),
|
@mapBy("availableActiveParentThemes", "name") availableActiveThemesNames;
|
||||||
availableActiveComponentsNames: mapBy("availableActiveChildThemes", "name"),
|
@filterBy("availableChildThemes", "hasParents") availableActiveChildThemes;
|
||||||
childThemesNames: mapBy("model.childThemes", "name"),
|
@mapBy("availableChildThemes", "name") availableComponentsNames;
|
||||||
extraFiles: filterBy("model.theme_fields", "target", "extra_js"),
|
@mapBy("availableActiveChildThemes", "name") availableActiveComponentsNames;
|
||||||
|
@mapBy("model.childThemes", "name") childThemesNames;
|
||||||
|
@filterBy("model.theme_fields", "target", "extra_js") extraFiles;
|
||||||
|
@notEmpty("settings") hasSettings;
|
||||||
|
@notEmpty("translations") hasTranslations;
|
||||||
|
@match("model.remote_theme.remote_url", /^http(s)?:\/\//) sourceIsHttp;
|
||||||
|
|
||||||
@discourseComputed("model.component", "model.remote_theme")
|
@discourseComputed("model.component", "model.remote_theme")
|
||||||
showCheckboxes() {
|
showCheckboxes() {
|
||||||
return !this.model.component || this.model.remote_theme;
|
return !this.model.component || this.model.remote_theme;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.editedFields")
|
@discourseComputed("model.editedFields")
|
||||||
editedFieldsFormatted() {
|
editedFieldsFormatted() {
|
||||||
@ -57,13 +62,13 @@ export default Controller.extend({
|
|||||||
descriptions.push(resultString);
|
descriptions.push(resultString);
|
||||||
});
|
});
|
||||||
return descriptions;
|
return descriptions;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("colorSchemeId", "model.color_scheme_id")
|
@discourseComputed("colorSchemeId", "model.color_scheme_id")
|
||||||
colorSchemeChanged(colorSchemeId, existingId) {
|
colorSchemeChanged(colorSchemeId, existingId) {
|
||||||
colorSchemeId = colorSchemeId === null ? null : parseInt(colorSchemeId, 10);
|
colorSchemeId = colorSchemeId === null ? null : parseInt(colorSchemeId, 10);
|
||||||
return colorSchemeId !== existingId;
|
return colorSchemeId !== existingId;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("availableChildThemes", "model.childThemes.[]", "model")
|
@discourseComputed("availableChildThemes", "model.childThemes.[]", "model")
|
||||||
selectableChildThemes(available, childThemes) {
|
selectableChildThemes(available, childThemes) {
|
||||||
@ -73,7 +78,7 @@ export default Controller.extend({
|
|||||||
: available.filter((theme) => !childThemes.includes(theme));
|
: available.filter((theme) => !childThemes.includes(theme));
|
||||||
return themes.length === 0 ? null : themes;
|
return themes.length === 0 ? null : themes;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.parentThemes.[]")
|
@discourseComputed("model.parentThemes.[]")
|
||||||
relativesSelectorSettingsForComponent() {
|
relativesSelectorSettingsForComponent() {
|
||||||
@ -91,7 +96,7 @@ export default Controller.extend({
|
|||||||
allThemes: this.allThemes,
|
allThemes: this.allThemes,
|
||||||
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all_themes"),
|
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all_themes"),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.parentThemes.[]")
|
@discourseComputed("model.parentThemes.[]")
|
||||||
relativesSelectorSettingsForTheme() {
|
relativesSelectorSettingsForTheme() {
|
||||||
@ -109,7 +114,7 @@ export default Controller.extend({
|
|||||||
allThemes: this.allThemes,
|
allThemes: this.allThemes,
|
||||||
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all"),
|
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all"),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("allThemes", "model.component", "model")
|
@discourseComputed("allThemes", "model.component", "model")
|
||||||
availableChildThemes(allThemes) {
|
availableChildThemes(allThemes) {
|
||||||
@ -119,40 +124,36 @@ export default Controller.extend({
|
|||||||
(theme) => theme.get("id") !== themeId && theme.get("component")
|
(theme) => theme.get("id") !== themeId && theme.get("component")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.component")
|
@discourseComputed("model.component")
|
||||||
convertKey(component) {
|
convertKey(component) {
|
||||||
const type = component ? "component" : "theme";
|
const type = component ? "component" : "theme";
|
||||||
return `admin.customize.theme.convert_${type}`;
|
return `admin.customize.theme.convert_${type}`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.component")
|
@discourseComputed("model.component")
|
||||||
convertIcon(component) {
|
convertIcon(component) {
|
||||||
return component ? "cube" : "";
|
return component ? "cube" : "";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.component")
|
@discourseComputed("model.component")
|
||||||
convertTooltip(component) {
|
convertTooltip(component) {
|
||||||
const type = component ? "component" : "theme";
|
const type = component ? "component" : "theme";
|
||||||
return `admin.customize.theme.convert_${type}_tooltip`;
|
return `admin.customize.theme.convert_${type}_tooltip`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.settings")
|
@discourseComputed("model.settings")
|
||||||
settings(settings) {
|
settings(settings) {
|
||||||
return settings.map((setting) => ThemeSettings.create(setting));
|
return settings.map((setting) => ThemeSettings.create(setting));
|
||||||
},
|
}
|
||||||
|
|
||||||
hasSettings: notEmpty("settings"),
|
|
||||||
|
|
||||||
@discourseComputed("model.translations")
|
@discourseComputed("model.translations")
|
||||||
translations(translations) {
|
translations(translations) {
|
||||||
return translations.map((setting) =>
|
return translations.map((setting) =>
|
||||||
ThemeSettings.create({ ...setting, textarea: true })
|
ThemeSettings.create({ ...setting, textarea: true })
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
hasTranslations: notEmpty("translations"),
|
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.remote_theme.local_version",
|
"model.remote_theme.local_version",
|
||||||
@ -161,12 +162,12 @@ export default Controller.extend({
|
|||||||
)
|
)
|
||||||
hasOverwrittenHistory(localVersion, remoteVersion, commitsBehind) {
|
hasOverwrittenHistory(localVersion, remoteVersion, commitsBehind) {
|
||||||
return localVersion !== remoteVersion && commitsBehind === -1;
|
return localVersion !== remoteVersion && commitsBehind === -1;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.remoteError", "updatingRemote")
|
@discourseComputed("model.remoteError", "updatingRemote")
|
||||||
showRemoteError(errorMessage, updating) {
|
showRemoteError(errorMessage, updating) {
|
||||||
return errorMessage && !updating;
|
return errorMessage && !updating;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.remote_theme.remote_url",
|
"model.remote_theme.remote_url",
|
||||||
@ -175,13 +176,13 @@ export default Controller.extend({
|
|||||||
)
|
)
|
||||||
finishInstall(remoteUrl, localVersion, commitsBehind) {
|
finishInstall(remoteUrl, localVersion, commitsBehind) {
|
||||||
return remoteUrl && !localVersion && !commitsBehind;
|
return remoteUrl && !localVersion && !commitsBehind;
|
||||||
},
|
}
|
||||||
|
|
||||||
editedFieldsForTarget(target) {
|
editedFieldsForTarget(target) {
|
||||||
return this.get("model.editedFields").filter(
|
return this.get("model.editedFields").filter(
|
||||||
(field) => field.target === target
|
(field) => field.target === target
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
commitSwitchType() {
|
commitSwitchType() {
|
||||||
const model = this.model;
|
const model = this.model;
|
||||||
@ -222,7 +223,8 @@ export default Controller.extend({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
transitionToEditRoute() {
|
transitionToEditRoute() {
|
||||||
this.transitionToRoute(
|
this.transitionToRoute(
|
||||||
this.editRouteName,
|
this.editRouteName,
|
||||||
@ -230,8 +232,7 @@ export default Controller.extend({
|
|||||||
"common",
|
"common",
|
||||||
"scss"
|
"scss"
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
sourceIsHttp: match("model.remote_theme.remote_url", /^http(s)?:\/\//),
|
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.remote_theme.remote_url",
|
"model.remote_theme.remote_url",
|
||||||
@ -241,168 +242,186 @@ export default Controller.extend({
|
|||||||
return remoteThemeBranch
|
return remoteThemeBranch
|
||||||
? `${remoteThemeUrl.replace(/\.git$/, "")}/tree/${remoteThemeBranch}`
|
? `${remoteThemeUrl.replace(/\.git$/, "")}/tree/${remoteThemeBranch}`
|
||||||
: remoteThemeUrl;
|
: remoteThemeUrl;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.user.id", "model.default")
|
@discourseComputed("model.user.id", "model.default")
|
||||||
showConvert(userId, defaultTheme) {
|
showConvert(userId, defaultTheme) {
|
||||||
return userId > 0 && !defaultTheme;
|
return userId > 0 && !defaultTheme;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
updateToLatest() {
|
updateToLatest() {
|
||||||
this.set("updatingRemote", true);
|
this.set("updatingRemote", true);
|
||||||
this.model
|
this.model
|
||||||
.updateToLatest()
|
.updateToLatest()
|
||||||
.catch(popupAjaxError)
|
.catch(popupAjaxError)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.set("updatingRemote", false);
|
this.set("updatingRemote", false);
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
checkForThemeUpdates() {
|
|
||||||
this.set("updatingRemote", true);
|
|
||||||
this.model
|
|
||||||
.checkForUpdates()
|
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(() => {
|
|
||||||
this.set("updatingRemote", false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
addUploadModal() {
|
|
||||||
showModal("admin-add-upload", { admin: true, name: "" });
|
|
||||||
},
|
|
||||||
|
|
||||||
addUpload(info) {
|
|
||||||
let model = this.model;
|
|
||||||
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
|
||||||
model.saveChanges("theme_fields").catch((e) => popupAjaxError(e));
|
|
||||||
},
|
|
||||||
|
|
||||||
cancelChangeScheme() {
|
|
||||||
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
|
||||||
},
|
|
||||||
changeScheme() {
|
|
||||||
let schemeId = this.colorSchemeId;
|
|
||||||
this.set(
|
|
||||||
"model.color_scheme_id",
|
|
||||||
schemeId === null ? null : parseInt(schemeId, 10)
|
|
||||||
);
|
|
||||||
this.model.saveChanges("color_scheme_id");
|
|
||||||
},
|
|
||||||
startEditingName() {
|
|
||||||
this.set("oldName", this.get("model.name"));
|
|
||||||
this.set("editingName", true);
|
|
||||||
},
|
|
||||||
cancelEditingName() {
|
|
||||||
this.set("model.name", this.oldName);
|
|
||||||
this.set("editingName", false);
|
|
||||||
},
|
|
||||||
finishedEditingName() {
|
|
||||||
this.model.saveChanges("name");
|
|
||||||
this.set("editingName", false);
|
|
||||||
},
|
|
||||||
|
|
||||||
editTheme() {
|
|
||||||
if (this.get("model.remote_theme.is_git")) {
|
|
||||||
this.dialog.confirm({
|
|
||||||
message: I18n.t("admin.customize.theme.edit_confirm"),
|
|
||||||
didConfirm: () => this.transitionToEditRoute(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.transitionToEditRoute();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
applyDefault() {
|
|
||||||
const model = this.model;
|
|
||||||
model.saveChanges("default").then(() => {
|
|
||||||
if (model.get("default")) {
|
|
||||||
this.allThemes.forEach((theme) => {
|
|
||||||
if (theme !== model && theme.get("default")) {
|
|
||||||
theme.set("default", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
applyUserSelectable() {
|
@action
|
||||||
this.model.saveChanges("user_selectable");
|
checkForThemeUpdates() {
|
||||||
},
|
this.set("updatingRemote", true);
|
||||||
|
this.model
|
||||||
applyAutoUpdateable() {
|
.checkForUpdates()
|
||||||
this.model.saveChanges("auto_update");
|
.catch(popupAjaxError)
|
||||||
},
|
.finally(() => {
|
||||||
|
this.set("updatingRemote", false);
|
||||||
addChildTheme() {
|
|
||||||
let themeId = parseInt(this.selectedChildThemeId, 10);
|
|
||||||
let theme = this.allThemes.findBy("id", themeId);
|
|
||||||
this.model.addChildTheme(theme).then(() => this.store.findAll("theme"));
|
|
||||||
},
|
|
||||||
|
|
||||||
removeUpload(upload) {
|
|
||||||
return this.dialog.yesNoConfirm({
|
|
||||||
message: I18n.t("admin.customize.theme.delete_upload_confirm"),
|
|
||||||
didConfirm: () => this.model.removeField(upload),
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
removeChildTheme(theme) {
|
@action
|
||||||
this.model
|
addUploadModal() {
|
||||||
.removeChildTheme(theme)
|
showModal("admin-add-upload", { admin: true, name: "" });
|
||||||
.then(() => this.store.findAll("theme"));
|
}
|
||||||
},
|
|
||||||
|
|
||||||
destroy() {
|
@action
|
||||||
return this.dialog.yesNoConfirm({
|
addUpload(info) {
|
||||||
message: I18n.t("admin.customize.delete_confirm", {
|
let model = this.model;
|
||||||
theme_name: this.get("model.name"),
|
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
||||||
}),
|
model.saveChanges("theme_fields").catch((e) => popupAjaxError(e));
|
||||||
didConfirm: () => {
|
}
|
||||||
const model = this.model;
|
|
||||||
model.setProperties({ recentlyInstalled: false });
|
@action
|
||||||
model.destroyRecord().then(() => {
|
cancelChangeScheme() {
|
||||||
this.allThemes.removeObject(model);
|
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
||||||
this.transitionToRoute("adminCustomizeThemes");
|
}
|
||||||
});
|
|
||||||
},
|
@action
|
||||||
|
changeScheme() {
|
||||||
|
let schemeId = this.colorSchemeId;
|
||||||
|
this.set(
|
||||||
|
"model.color_scheme_id",
|
||||||
|
schemeId === null ? null : parseInt(schemeId, 10)
|
||||||
|
);
|
||||||
|
this.model.saveChanges("color_scheme_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
startEditingName() {
|
||||||
|
this.set("oldName", this.get("model.name"));
|
||||||
|
this.set("editingName", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancelEditingName() {
|
||||||
|
this.set("model.name", this.oldName);
|
||||||
|
this.set("editingName", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
finishedEditingName() {
|
||||||
|
this.model.saveChanges("name");
|
||||||
|
this.set("editingName", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
editTheme() {
|
||||||
|
if (this.get("model.remote_theme.is_git")) {
|
||||||
|
this.dialog.confirm({
|
||||||
|
message: I18n.t("admin.customize.theme.edit_confirm"),
|
||||||
|
didConfirm: () => this.transitionToEditRoute(),
|
||||||
});
|
});
|
||||||
},
|
} else {
|
||||||
|
this.transitionToEditRoute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switchType() {
|
@action
|
||||||
const relatives = this.get("model.component")
|
applyDefault() {
|
||||||
? this.get("model.parentThemes")
|
const model = this.model;
|
||||||
: this.get("model.childThemes");
|
model.saveChanges("default").then(() => {
|
||||||
|
if (model.get("default")) {
|
||||||
let message = I18n.t(`${this.convertKey}_alert_generic`);
|
this.allThemes.forEach((theme) => {
|
||||||
|
if (theme !== model && theme.get("default")) {
|
||||||
if (relatives && relatives.length > 0) {
|
theme.set("default", false);
|
||||||
message = I18n.t(`${this.convertKey}_alert`, {
|
}
|
||||||
relatives: relatives
|
|
||||||
.map((relative) => relative.get("name"))
|
|
||||||
.join(", "),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return this.dialog.yesNoConfirm({
|
@action
|
||||||
message,
|
applyUserSelectable() {
|
||||||
didConfirm: () => this.commitSwitchType(),
|
this.model.saveChanges("user_selectable");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
applyAutoUpdateable() {
|
||||||
|
this.model.saveChanges("auto_update");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
addChildTheme() {
|
||||||
|
let themeId = parseInt(this.selectedChildThemeId, 10);
|
||||||
|
let theme = this.allThemes.findBy("id", themeId);
|
||||||
|
this.model.addChildTheme(theme).then(() => this.store.findAll("theme"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
removeUpload(upload) {
|
||||||
|
return this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("admin.customize.theme.delete_upload_confirm"),
|
||||||
|
didConfirm: () => this.model.removeField(upload),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
removeChildTheme(theme) {
|
||||||
|
this.model.removeChildTheme(theme).then(() => this.store.findAll("theme"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
destroyTheme() {
|
||||||
|
return this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("admin.customize.delete_confirm", {
|
||||||
|
theme_name: this.get("model.name"),
|
||||||
|
}),
|
||||||
|
didConfirm: () => {
|
||||||
|
const model = this.model;
|
||||||
|
model.setProperties({ recentlyInstalled: false });
|
||||||
|
model.destroyRecord().then(() => {
|
||||||
|
this.allThemes.removeObject(model);
|
||||||
|
this.transitionToRoute("adminCustomizeThemes");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
switchType() {
|
||||||
|
const relatives = this.get("model.component")
|
||||||
|
? this.get("model.parentThemes")
|
||||||
|
: this.get("model.childThemes");
|
||||||
|
|
||||||
|
let message = I18n.t(`${this.convertKey}_alert_generic`);
|
||||||
|
|
||||||
|
if (relatives && relatives.length > 0) {
|
||||||
|
message = I18n.t(`${this.convertKey}_alert`, {
|
||||||
|
relatives: relatives.map((relative) => relative.get("name")).join(", "),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
enableComponent() {
|
return this.dialog.yesNoConfirm({
|
||||||
this.model.set("enabled", true);
|
message,
|
||||||
this.model
|
didConfirm: () => this.commitSwitchType(),
|
||||||
.saveChanges("enabled")
|
});
|
||||||
.catch(() => this.model.set("enabled", false));
|
}
|
||||||
},
|
|
||||||
|
|
||||||
disableComponent() {
|
@action
|
||||||
this.model.set("enabled", false);
|
enableComponent() {
|
||||||
this.model
|
this.model.set("enabled", true);
|
||||||
.saveChanges("enabled")
|
this.model
|
||||||
.catch(() => this.model.set("enabled", true));
|
.saveChanges("enabled")
|
||||||
},
|
.catch(() => this.model.set("enabled", false));
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
@action
|
||||||
|
disableComponent() {
|
||||||
|
this.model.set("enabled", false);
|
||||||
|
this.model
|
||||||
|
.saveChanges("enabled")
|
||||||
|
.catch(() => this.model.set("enabled", true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,21 +2,21 @@ import Controller from "@ember/controller";
|
|||||||
import { THEMES } from "admin/models/theme";
|
import { THEMES } from "admin/models/theme";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminCustomizeThemesController extends Controller {
|
||||||
currentTab: THEMES,
|
currentTab = THEMES;
|
||||||
|
|
||||||
@discourseComputed("model", "model.@each.component")
|
@discourseComputed("model", "model.@each.component")
|
||||||
fullThemes(themes) {
|
fullThemes(themes) {
|
||||||
return themes.filter((t) => !t.get("component"));
|
return themes.filter((t) => !t.get("component"));
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model", "model.@each.component")
|
@discourseComputed("model", "model.@each.component")
|
||||||
childThemes(themes) {
|
childThemes(themes) {
|
||||||
return themes.filter((t) => t.get("component"));
|
return themes.filter((t) => t.get("component"));
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.content")
|
@discourseComputed("model.content")
|
||||||
installedThemes(content) {
|
installedThemes(content) {
|
||||||
return content || [];
|
return content || [];
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
import { computed } from "@ember/object";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import AdminDashboard from "admin/models/admin-dashboard";
|
import AdminDashboard from "admin/models/admin-dashboard";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||||
import Report from "admin/models/report";
|
import Report from "admin/models/report";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
import { makeArray } from "discourse-common/lib/helpers";
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
@ -15,41 +15,49 @@ function staticReport(reportType) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Controller.extend(PeriodComputationMixin, {
|
export default class AdminDashboardGeneralController extends Controller.extend(
|
||||||
isLoading: false,
|
PeriodComputationMixin
|
||||||
dashboardFetchedAt: null,
|
) {
|
||||||
exceptionController: controller("exception"),
|
@controller("exception") exceptionController;
|
||||||
logSearchQueriesEnabled: setting("log_search_queries"),
|
|
||||||
|
isLoading = false;
|
||||||
|
dashboardFetchedAt = null;
|
||||||
|
|
||||||
|
@setting("log_search_queries") logSearchQueriesEnabled;
|
||||||
|
|
||||||
|
@staticReport("users_by_type") usersByTypeReport;
|
||||||
|
@staticReport("users_by_trust_level") usersByTrustLevelReport;
|
||||||
|
@staticReport("storage_report") storageReport;
|
||||||
|
|
||||||
@discourseComputed("siteSettings.dashboard_general_tab_activity_metrics")
|
@discourseComputed("siteSettings.dashboard_general_tab_activity_metrics")
|
||||||
activityMetrics(metrics) {
|
activityMetrics(metrics) {
|
||||||
return (metrics || "").split("|").filter(Boolean);
|
return (metrics || "").split("|").filter(Boolean);
|
||||||
},
|
}
|
||||||
|
|
||||||
hiddenReports: computed("siteSettings.dashboard_hidden_reports", function () {
|
@computed("siteSettings.dashboard_hidden_reports")
|
||||||
|
get hiddenReports() {
|
||||||
return (this.siteSettings.dashboard_hidden_reports || "")
|
return (this.siteSettings.dashboard_hidden_reports || "")
|
||||||
.split("|")
|
.split("|")
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}),
|
}
|
||||||
|
|
||||||
isActivityMetricsVisible: computed(
|
@computed("activityMetrics", "hiddenReports")
|
||||||
"activityMetrics",
|
get isActivityMetricsVisible() {
|
||||||
"hiddenReports",
|
return (
|
||||||
function () {
|
this.activityMetrics.length &&
|
||||||
return (
|
this.activityMetrics.some((x) => !this.hiddenReports.includes(x))
|
||||||
this.activityMetrics.length &&
|
);
|
||||||
this.activityMetrics.some((x) => !this.hiddenReports.includes(x))
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
isSearchReportsVisible: computed("hiddenReports", function () {
|
@computed("hiddenReports")
|
||||||
|
get isSearchReportsVisible() {
|
||||||
return ["top_referred_topics", "trending_search"].some(
|
return ["top_referred_topics", "trending_search"].some(
|
||||||
(x) => !this.hiddenReports.includes(x)
|
(x) => !this.hiddenReports.includes(x)
|
||||||
);
|
);
|
||||||
}),
|
}
|
||||||
|
|
||||||
isCommunityHealthVisible: computed("hiddenReports", function () {
|
@computed("hiddenReports")
|
||||||
|
get isCommunityHealthVisible() {
|
||||||
return [
|
return [
|
||||||
"consolidated_page_views",
|
"consolidated_page_views",
|
||||||
"signups",
|
"signups",
|
||||||
@ -59,7 +67,7 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
"daily_engaged_users",
|
"daily_engaged_users",
|
||||||
"new_contributors",
|
"new_contributors",
|
||||||
].some((x) => !this.hiddenReports.includes(x));
|
].some((x) => !this.hiddenReports.includes(x));
|
||||||
}),
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
activityMetricsFilters() {
|
activityMetricsFilters() {
|
||||||
@ -67,14 +75,14 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
startDate: this.lastMonth,
|
startDate: this.lastMonth,
|
||||||
endDate: this.today,
|
endDate: this.today,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
topReferredTopicsOptions() {
|
topReferredTopicsOptions() {
|
||||||
return {
|
return {
|
||||||
table: { total: false, limit: 8 },
|
table: { total: false, limit: 8 },
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
topReferredTopicsFilters() {
|
topReferredTopicsFilters() {
|
||||||
@ -82,7 +90,7 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
startDate: moment().subtract(6, "days").startOf("day"),
|
startDate: moment().subtract(6, "days").startOf("day"),
|
||||||
endDate: this.today,
|
endDate: this.today,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
trendingSearchFilters() {
|
trendingSearchFilters() {
|
||||||
@ -90,25 +98,21 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
startDate: moment().subtract(1, "month").startOf("day"),
|
startDate: moment().subtract(1, "month").startOf("day"),
|
||||||
endDate: this.today,
|
endDate: this.today,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
trendingSearchOptions() {
|
trendingSearchOptions() {
|
||||||
return {
|
return {
|
||||||
table: { total: false, limit: 8 },
|
table: { total: false, limit: 8 },
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
trendingSearchDisabledLabel() {
|
trendingSearchDisabledLabel() {
|
||||||
return I18n.t("admin.dashboard.reports.trending_search.disabled", {
|
return I18n.t("admin.dashboard.reports.trending_search.disabled", {
|
||||||
basePath: getURL(""),
|
basePath: getURL(""),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
usersByTypeReport: staticReport("users_by_type"),
|
|
||||||
usersByTrustLevelReport: staticReport("users_by_trust_level"),
|
|
||||||
storageReport: staticReport("storage_report"),
|
|
||||||
|
|
||||||
fetchDashboard() {
|
fetchDashboard() {
|
||||||
if (this.isLoading) {
|
if (this.isLoading) {
|
||||||
@ -137,14 +141,14 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
})
|
})
|
||||||
.finally(() => this.set("isLoading", false));
|
.finally(() => this.set("isLoading", false));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("startDate", "endDate")
|
@discourseComputed("startDate", "endDate")
|
||||||
filters(startDate, endDate) {
|
filters(startDate, endDate) {
|
||||||
return { startDate, endDate };
|
return { startDate, endDate };
|
||||||
},
|
}
|
||||||
|
|
||||||
_reportsForPeriodURL(period) {
|
_reportsForPeriodURL(period) {
|
||||||
return getURL(`/admin?period=${period}`);
|
return getURL(`/admin?period=${period}`);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
import { computed } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
|
|
||||||
export default Controller.extend(PeriodComputationMixin, {
|
export default class AdminDashboardModerationController extends Controller.extend(
|
||||||
|
PeriodComputationMixin
|
||||||
|
) {
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
flagsStatusOptions() {
|
flagsStatusOptions() {
|
||||||
return {
|
return {
|
||||||
@ -13,17 +15,15 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
perPage: 10,
|
perPage: 10,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
isModeratorsActivityVisible: computed(
|
@computed("siteSettings.dashboard_hidden_reports")
|
||||||
"siteSettings.dashboard_hidden_reports",
|
get isModeratorsActivityVisible() {
|
||||||
function () {
|
return !(this.siteSettings.dashboard_hidden_reports || "")
|
||||||
return !(this.siteSettings.dashboard_hidden_reports || "")
|
.split("|")
|
||||||
.split("|")
|
.filter(Boolean)
|
||||||
.filter(Boolean)
|
.includes("moderators_activity");
|
||||||
.includes("moderators_activity");
|
}
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
userFlaggingRatioOptions() {
|
userFlaggingRatioOptions() {
|
||||||
@ -33,19 +33,19 @@ export default Controller.extend(PeriodComputationMixin, {
|
|||||||
perPage: 10,
|
perPage: 10,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("startDate", "endDate")
|
@discourseComputed("startDate", "endDate")
|
||||||
filters(startDate, endDate) {
|
filters(startDate, endDate) {
|
||||||
return { startDate, endDate };
|
return { startDate, endDate };
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("lastWeek", "endDate")
|
@discourseComputed("lastWeek", "endDate")
|
||||||
lastWeekfilters(startDate, endDate) {
|
lastWeekfilters(startDate, endDate) {
|
||||||
return { startDate, endDate };
|
return { startDate, endDate };
|
||||||
},
|
}
|
||||||
|
|
||||||
_reportsForPeriodURL(period) {
|
_reportsForPeriodURL(period) {
|
||||||
return getURL(`/admin/dashboard/moderation?period=${period}`);
|
return getURL(`/admin/dashboard/moderation?period=${period}`);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import Controller from "@ember/controller";
|
|||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { get } from "@ember/object";
|
import { action, get } from "@ember/object";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminDashboardReportsController extends Controller {
|
||||||
filter: null,
|
filter = null;
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.[]",
|
"model.[]",
|
||||||
@ -29,15 +29,14 @@ export default Controller.extend({
|
|||||||
reports = reports.filter((report) => !hiddenReports.includes(report.type));
|
reports = reports.filter((report) => !hiddenReports.includes(report.type));
|
||||||
|
|
||||||
return reports;
|
return reports;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
filterReports(filter) {
|
filterReports(filter) {
|
||||||
discourseDebounce(this, this._performFiltering, filter, INPUT_DELAY);
|
discourseDebounce(this, this._performFiltering, filter, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_performFiltering(filter) {
|
_performFiltering(filter) {
|
||||||
this.set("filter", filter);
|
this.set("filter", filter);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,17 +1,19 @@
|
|||||||
|
import { action, computed } from "@ember/object";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import AdminDashboard from "admin/models/admin-dashboard";
|
import AdminDashboard from "admin/models/admin-dashboard";
|
||||||
import VersionCheck from "admin/models/version-check";
|
import VersionCheck from "admin/models/version-check";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { setting } from "discourse/lib/computed";
|
import { setting } from "discourse/lib/computed";
|
||||||
|
|
||||||
const PROBLEMS_CHECK_MINUTES = 1;
|
const PROBLEMS_CHECK_MINUTES = 1;
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminDashboardController extends Controller {
|
||||||
isLoading: false,
|
@controller("exception") exceptionController;
|
||||||
dashboardFetchedAt: null,
|
|
||||||
exceptionController: controller("exception"),
|
isLoading = false;
|
||||||
showVersionChecks: setting("version_checks"),
|
dashboardFetchedAt = null;
|
||||||
|
|
||||||
|
@setting("version_checks") showVersionChecks;
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"lowPriorityProblems.length",
|
"lowPriorityProblems.length",
|
||||||
@ -21,25 +23,29 @@ export default Controller.extend({
|
|||||||
const problemsLength =
|
const problemsLength =
|
||||||
lowPriorityProblemsLength + highPriorityProblemsLength;
|
lowPriorityProblemsLength + highPriorityProblemsLength;
|
||||||
return this.currentUser.admin && problemsLength > 0;
|
return this.currentUser.admin && problemsLength > 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
visibleTabs: computed("siteSettings.dashboard_visible_tabs", function () {
|
@computed("siteSettings.dashboard_visible_tabs")
|
||||||
|
get visibleTabs() {
|
||||||
return (this.siteSettings.dashboard_visible_tabs || "")
|
return (this.siteSettings.dashboard_visible_tabs || "")
|
||||||
.split("|")
|
.split("|")
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}),
|
}
|
||||||
|
|
||||||
isModerationTabVisible: computed("visibleTabs", function () {
|
@computed("visibleTabs")
|
||||||
|
get isModerationTabVisible() {
|
||||||
return this.visibleTabs.includes("moderation");
|
return this.visibleTabs.includes("moderation");
|
||||||
}),
|
}
|
||||||
|
|
||||||
isSecurityTabVisible: computed("visibleTabs", function () {
|
@computed("visibleTabs")
|
||||||
|
get isSecurityTabVisible() {
|
||||||
return this.visibleTabs.includes("security");
|
return this.visibleTabs.includes("security");
|
||||||
}),
|
}
|
||||||
|
|
||||||
isReportsTabVisible: computed("visibleTabs", function () {
|
@computed("visibleTabs")
|
||||||
|
get isReportsTabVisible() {
|
||||||
return this.visibleTabs.includes("reports");
|
return this.visibleTabs.includes("reports");
|
||||||
}),
|
}
|
||||||
|
|
||||||
fetchProblems() {
|
fetchProblems() {
|
||||||
if (this.isLoadingProblems) {
|
if (this.isLoadingProblems) {
|
||||||
@ -53,7 +59,7 @@ export default Controller.extend({
|
|||||||
) {
|
) {
|
||||||
this._loadProblems();
|
this._loadProblems();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
fetchDashboard() {
|
fetchDashboard() {
|
||||||
const versionChecks = this.siteSettings.version_checks;
|
const versionChecks = this.siteSettings.version_checks;
|
||||||
@ -88,7 +94,7 @@ export default Controller.extend({
|
|||||||
this.set("isLoading", false);
|
this.set("isLoading", false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_loadProblems() {
|
_loadProblems() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
@ -108,16 +114,15 @@ export default Controller.extend({
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.finally(() => this.set("loadingProblems", false));
|
.finally(() => this.set("loadingProblems", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("problemsFetchedAt")
|
@discourseComputed("problemsFetchedAt")
|
||||||
problemsTimestamp(problemsFetchedAt) {
|
problemsTimestamp(problemsFetchedAt) {
|
||||||
return moment(problemsFetchedAt).locale("en").format("LLL");
|
return moment(problemsFetchedAt).locale("en").format("LLL");
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
refreshProblems() {
|
refreshProblems() {
|
||||||
this._loadProblems();
|
this._loadProblems();
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmailAdvancedTestController extends Controller {
|
||||||
email: null,
|
email = null;
|
||||||
text: null,
|
text = null;
|
||||||
elided: null,
|
elided = null;
|
||||||
format: null,
|
format = null;
|
||||||
loading: null,
|
loading = null;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
run() {
|
run() {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
|
|
||||||
ajax("/admin/email/advanced-test", {
|
ajax("/admin/email/advanced-test", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { email: this.email },
|
data: { email: this.email },
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
this.setProperties({
|
||||||
|
text: data.text,
|
||||||
|
elided: data.elided,
|
||||||
|
format: data.format,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.catch(popupAjaxError)
|
||||||
this.setProperties({
|
.finally(() => this.set("loading", false));
|
||||||
text: data.text,
|
}
|
||||||
elided: data.elided,
|
}
|
||||||
format: data.format,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(() => this.set("loading", false));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default class AdminEmailBouncedController extends AdminEmailLogsController {
|
||||||
@action
|
@action
|
||||||
handleShowIncomingEmail(id, event) {
|
handleShowIncomingEmail(id, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.send("showIncomingEmail", id);
|
this.send("showIncomingEmail", id);
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("filter.{status,user,address,type}")
|
@observes("filter.{status,user,address,type}")
|
||||||
filterEmailLogs() {
|
filterEmailLogs() {
|
||||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { empty } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { empty } from "@ember/object/computed";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
import { escapeExpression } from "discourse/lib/utilities";
|
import { escapeExpression } from "discourse/lib/utilities";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmailIndexController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Is the "send test email" button disabled?
|
Is the "send test email" button disabled?
|
||||||
|
|
||||||
@property sendTestEmailDisabled
|
@property sendTestEmailDisabled
|
||||||
**/
|
**/
|
||||||
sendTestEmailDisabled: empty("testEmailAddress"),
|
@empty("testEmailAddress") sendTestEmailDisabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Clears the 'sentTestEmail' property on successful send.
|
Clears the 'sentTestEmail' property on successful send.
|
||||||
@ -25,43 +26,40 @@ export default Controller.extend({
|
|||||||
@observes("testEmailAddress")
|
@observes("testEmailAddress")
|
||||||
testEmailAddressChanged() {
|
testEmailAddressChanged() {
|
||||||
this.set("sentTestEmail", false);
|
this.set("sentTestEmail", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
/**
|
||||||
/**
|
Sends a test email to the currently entered email address
|
||||||
Sends a test email to the currently entered email address
|
|
||||||
|
|
||||||
@method sendTestEmail
|
@method sendTestEmail
|
||||||
**/
|
**/
|
||||||
sendTestEmail() {
|
@action
|
||||||
this.setProperties({
|
sendTestEmail() {
|
||||||
sendingEmail: true,
|
this.setProperties({
|
||||||
sentTestEmail: false,
|
sendingEmail: true,
|
||||||
});
|
sentTestEmail: false,
|
||||||
|
});
|
||||||
|
|
||||||
ajax("/admin/email/test", {
|
ajax("/admin/email/test", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { email_address: this.testEmailAddress },
|
data: { email_address: this.testEmailAddress },
|
||||||
|
})
|
||||||
|
.then((response) =>
|
||||||
|
this.set("sentTestEmailMessage", response.sent_test_email_message)
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
if (e.jqXHR.responseJSON?.errors) {
|
||||||
|
this.dialog.alert({
|
||||||
|
message: htmlSafe(
|
||||||
|
I18n.t("admin.email.error", {
|
||||||
|
server_error: escapeExpression(e.jqXHR.responseJSON.errors[0]),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.dialog.alert({ message: I18n.t("admin.email.test_error") });
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then((response) =>
|
.finally(() => this.set("sendingEmail", false));
|
||||||
this.set("sentTestEmailMessage", response.sent_test_email_message)
|
}
|
||||||
)
|
}
|
||||||
.catch((e) => {
|
|
||||||
if (e.jqXHR.responseJSON?.errors) {
|
|
||||||
this.dialog.alert({
|
|
||||||
message: htmlSafe(
|
|
||||||
I18n.t("admin.email.error", {
|
|
||||||
server_error: escapeExpression(
|
|
||||||
e.jqXHR.responseJSON.errors[0]
|
|
||||||
),
|
|
||||||
})
|
|
||||||
),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.dialog.alert({ message: I18n.t("admin.email.test_error") });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => this.set("sendingEmail", false));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import EmailLog from "admin/models/email-log";
|
import EmailLog from "admin/models/email-log";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmailLogsController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
|
filter = EmberObject.create();
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.set("filter", EmberObject.create());
|
|
||||||
},
|
|
||||||
loadLogs(sourceModel, loadMore) {
|
loadLogs(sourceModel, loadMore) {
|
||||||
if ((loadMore && this.loading) || this.get("model.allLoaded")) {
|
if ((loadMore && this.loading) || this.get("model.allLoaded")) {
|
||||||
return;
|
return;
|
||||||
@ -38,11 +35,10 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => this.set("loading", false));
|
.finally(() => this.set("loading", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this.loadLogs(EmailLog, true);
|
this.loadLogs(EmailLog, true);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,66 +1,67 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { empty, notEmpty, or } from "@ember/object/computed";
|
import { empty, notEmpty, or } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import EmailPreview from "admin/models/email-preview";
|
import EmailPreview from "admin/models/email-preview";
|
||||||
import { action, get } from "@ember/object";
|
import { action, get } from "@ember/object";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmailPreviewDigestController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
username: null,
|
|
||||||
lastSeen: null,
|
username = null;
|
||||||
emailEmpty: empty("email"),
|
lastSeen = null;
|
||||||
sendEmailDisabled: or("emailEmpty", "sendingEmail"),
|
|
||||||
showSendEmailForm: notEmpty("model.html_content"),
|
@empty("email") emailEmpty;
|
||||||
htmlEmpty: empty("model.html_content"),
|
@or("emailEmpty", "sendingEmail") sendEmailDisabled;
|
||||||
|
@notEmpty("model.html_content") showSendEmailForm;
|
||||||
|
@empty("model.html_content") htmlEmpty;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleShowHtml(event) {
|
toggleShowHtml(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.toggleProperty("showHtml");
|
this.toggleProperty("showHtml");
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
updateUsername(selected) {
|
updateUsername(selected) {
|
||||||
this.set("username", get(selected, "firstObject"));
|
this.set("username", get(selected, "firstObject"));
|
||||||
},
|
}
|
||||||
|
|
||||||
refresh() {
|
@action
|
||||||
const model = this.model;
|
refresh() {
|
||||||
|
const model = this.model;
|
||||||
|
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
this.set("sentEmail", false);
|
this.set("sentEmail", false);
|
||||||
|
|
||||||
let username = this.username;
|
let username = this.username;
|
||||||
if (!username) {
|
if (!username) {
|
||||||
username = this.currentUser.get("username");
|
username = this.currentUser.get("username");
|
||||||
this.set("username", username);
|
this.set("username", username);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmailPreview.findDigest(username, this.lastSeen).then((email) => {
|
EmailPreview.findDigest(username, this.lastSeen).then((email) => {
|
||||||
model.setProperties(
|
model.setProperties(email.getProperties("html_content", "text_content"));
|
||||||
email.getProperties("html_content", "text_content")
|
this.set("loading", false);
|
||||||
);
|
});
|
||||||
this.set("loading", false);
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
sendEmail() {
|
||||||
|
this.set("sendingEmail", true);
|
||||||
|
this.set("sentEmail", false);
|
||||||
|
|
||||||
|
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
|
||||||
|
.then((result) => {
|
||||||
|
if (result.errors) {
|
||||||
|
this.dialog.alert(result.errors);
|
||||||
|
} else {
|
||||||
|
this.set("sentEmail", true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(() => {
|
||||||
|
this.set("sendingEmail", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
}
|
||||||
sendEmail() {
|
|
||||||
this.set("sendingEmail", true);
|
|
||||||
this.set("sentEmail", false);
|
|
||||||
|
|
||||||
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
|
|
||||||
.then((result) => {
|
|
||||||
if (result.errors) {
|
|
||||||
this.dialog.alert(result.errors);
|
|
||||||
} else {
|
|
||||||
this.set("sentEmail", true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(() => {
|
|
||||||
this.set("sendingEmail", false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import IncomingEmail from "admin/models/incoming-email";
|
import IncomingEmail from "admin/models/incoming-email";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default class AdminEmailReceivedController extends AdminEmailLogsController {
|
||||||
@observes("filter.{status,from,to,subject}")
|
@observes("filter.{status,from,to,subject}")
|
||||||
filterIncomingEmails() {
|
filterIncomingEmails() {
|
||||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this.loadLogs(IncomingEmail, true);
|
this.loadLogs(IncomingEmail, true);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -2,24 +2,23 @@ import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
|||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import IncomingEmail from "admin/models/incoming-email";
|
import IncomingEmail from "admin/models/incoming-email";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default class AdminEmailRejectedController extends AdminEmailLogsController {
|
||||||
@observes("filter.{status,from,to,subject,error}")
|
@observes("filter.{status,from,to,subject,error}")
|
||||||
filterIncomingEmails() {
|
filterIncomingEmails() {
|
||||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
handleShowIncomingEmail(id, event) {
|
handleShowIncomingEmail(id, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.send("showIncomingEmail", id);
|
this.send("showIncomingEmail", id);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this.loadLogs(IncomingEmail, true);
|
this.loadLogs(IncomingEmail, true);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default class AdminEmailSentController extends AdminEmailLogsController {
|
||||||
@observes("filter.{status,user,address,type,reply_key}")
|
@observes("filter.{status,user,address,type,reply_key}")
|
||||||
filterEmailLogs() {
|
filterEmailLogs() {
|
||||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default class AdminEmailSkippedController extends AdminEmailLogsController {
|
||||||
@observes("filter.{status,user,address,type}")
|
@observes("filter.{status,user,address,type}")
|
||||||
filterEmailLogs() {
|
filterEmailLogs() {
|
||||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmbeddingController extends Controller {
|
||||||
saved: false,
|
saved = false;
|
||||||
embedding: null,
|
embedding = null;
|
||||||
|
|
||||||
// show settings if we have at least one created host
|
// show settings if we have at least one created host
|
||||||
@discourseComputed("embedding.embeddable_hosts.@each.isCreated")
|
@discourseComputed("embedding.embeddable_hosts.@each.isCreated")
|
||||||
showSecondary() {
|
showSecondary() {
|
||||||
const hosts = this.get("embedding.embeddable_hosts");
|
const hosts = this.get("embedding.embeddable_hosts");
|
||||||
return hosts.length && hosts.findBy("isCreated");
|
return hosts.length && hosts.findBy("isCreated");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("embedding.base_url")
|
@discourseComputed("embedding.base_url")
|
||||||
embeddingCode(baseUrl) {
|
embeddingCode(baseUrl) {
|
||||||
@ -33,27 +34,28 @@ export default Controller.extend({
|
|||||||
</script>`;
|
</script>`;
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
saveChanges() {
|
saveChanges() {
|
||||||
const embedding = this.embedding;
|
const embedding = this.embedding;
|
||||||
const updates = embedding.getProperties(embedding.get("fields"));
|
const updates = embedding.getProperties(embedding.get("fields"));
|
||||||
|
|
||||||
this.set("saved", false);
|
this.set("saved", false);
|
||||||
this.embedding
|
this.embedding
|
||||||
.update(updates)
|
.update(updates)
|
||||||
.then(() => this.set("saved", true))
|
.then(() => this.set("saved", true))
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
addHost() {
|
@action
|
||||||
const host = this.store.createRecord("embeddable-host");
|
addHost() {
|
||||||
this.get("embedding.embeddable_hosts").pushObject(host);
|
const host = this.store.createRecord("embeddable-host");
|
||||||
},
|
this.get("embedding.embeddable_hosts").pushObject(host);
|
||||||
|
}
|
||||||
|
|
||||||
deleteHost(host) {
|
@action
|
||||||
this.get("embedding.embeddable_hosts").removeObject(host);
|
deleteHost(host) {
|
||||||
},
|
this.get("embedding.embeddable_hosts").removeObject(host);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,49 +1,46 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { sort } from "@ember/object/computed";
|
||||||
import EmberObject, { action, computed } from "@ember/object";
|
import EmberObject, { action, computed } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { sort } from "@ember/object/computed";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
const ALL_FILTER = "all";
|
const ALL_FILTER = "all";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminEmojisController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
filter: null,
|
|
||||||
sorting: null,
|
|
||||||
|
|
||||||
|
filter = null;
|
||||||
|
sorting = null;
|
||||||
|
|
||||||
|
@sort("filteredEmojis.[]", "sorting") sortedEmojis;
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
filter: ALL_FILTER,
|
filter: ALL_FILTER,
|
||||||
sorting: ["group", "name"],
|
sorting: ["group", "name"],
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
sortedEmojis: sort("filteredEmojis.[]", "sorting"),
|
@computed("model")
|
||||||
|
get emojiGroups() {
|
||||||
|
return this.model.mapBy("group").uniq();
|
||||||
|
}
|
||||||
|
|
||||||
emojiGroups: computed("model", {
|
@computed("emojiGroups.[]")
|
||||||
get() {
|
get sortingGroups() {
|
||||||
return this.model.mapBy("group").uniq();
|
return [ALL_FILTER].concat(this.emojiGroups);
|
||||||
},
|
}
|
||||||
}),
|
|
||||||
|
|
||||||
sortingGroups: computed("emojiGroups.[]", {
|
@computed("model.[]", "filter")
|
||||||
get() {
|
get filteredEmojis() {
|
||||||
return [ALL_FILTER].concat(this.emojiGroups);
|
if (!this.filter || this.filter === ALL_FILTER) {
|
||||||
},
|
return this.model;
|
||||||
}),
|
} else {
|
||||||
|
return this.model.filterBy("group", this.filter);
|
||||||
filteredEmojis: computed("model.[]", "filter", {
|
}
|
||||||
get() {
|
}
|
||||||
if (!this.filter || this.filter === ALL_FILTER) {
|
|
||||||
return this.model;
|
|
||||||
} else {
|
|
||||||
return this.model.filterBy("group", this.filter);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
_highlightEmojiList() {
|
_highlightEmojiList() {
|
||||||
const customEmojiListEl = document.querySelector("#custom_emoji");
|
const customEmojiListEl = document.querySelector("#custom_emoji");
|
||||||
@ -56,12 +53,12 @@ export default Controller.extend({
|
|||||||
customEmojiListEl.classList.remove("highlighted");
|
customEmojiListEl.classList.remove("highlighted");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterGroups(value) {
|
filterGroups(value) {
|
||||||
this.set("filter", value);
|
this.set("filter", value);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
emojiUploaded(emoji, group) {
|
emojiUploaded(emoji, group) {
|
||||||
@ -69,7 +66,7 @@ export default Controller.extend({
|
|||||||
emoji.group = group;
|
emoji.group = group;
|
||||||
this.model.pushObject(EmberObject.create(emoji));
|
this.model.pushObject(EmberObject.create(emoji));
|
||||||
this._highlightEmojiList();
|
this._highlightEmojiList();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
destroyEmoji(emoji) {
|
destroyEmoji(emoji) {
|
||||||
@ -85,5 +82,5 @@ export default Controller.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,23 +1,24 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import ScreenedEmail from "admin/models/screened-email";
|
import ScreenedEmail from "admin/models/screened-email";
|
||||||
import { exportEntity } from "discourse/lib/export-csv";
|
import { exportEntity } from "discourse/lib/export-csv";
|
||||||
import { outputExportResult } from "discourse/lib/export-result";
|
import { outputExportResult } from "discourse/lib/export-result";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminLogsScreenedEmailsController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
clearBlock(row) {
|
clearBlock(row) {
|
||||||
row.clearBlock().then(function () {
|
row.clearBlock().then(function () {
|
||||||
// feeling lazy
|
// feeling lazy
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
exportScreenedEmailList() {
|
@action
|
||||||
exportEntity("screened_email").then(outputExportResult);
|
exportScreenedEmailList() {
|
||||||
},
|
exportEntity("screened_email").then(outputExportResult);
|
||||||
},
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
@ -25,5 +26,5 @@ export default Controller.extend({
|
|||||||
this.set("model", result);
|
this.set("model", result);
|
||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,31 +1,32 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { exportEntity } from "discourse/lib/export-csv";
|
import { exportEntity } from "discourse/lib/export-csv";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { outputExportResult } from "discourse/lib/export-result";
|
import { outputExportResult } from "discourse/lib/export-result";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminLogsScreenedIpAddressesController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
loading: false,
|
|
||||||
filter: null,
|
loading = false;
|
||||||
savedIpAddress: null,
|
filter = null;
|
||||||
|
savedIpAddress = null;
|
||||||
|
|
||||||
_debouncedShow() {
|
_debouncedShow() {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
ScreenedIpAddress.findAll(this.filter).then((result) => {
|
ScreenedIpAddress.findAll(this.filter).then((result) => {
|
||||||
this.setProperties({ model: result, loading: false });
|
this.setProperties({ model: result, loading: false });
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("filter")
|
@observes("filter")
|
||||||
show() {
|
show() {
|
||||||
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
edit(record, event) {
|
edit(record, event) {
|
||||||
@ -34,81 +35,86 @@ export default Controller.extend({
|
|||||||
this.set("savedIpAddress", record.get("ip_address"));
|
this.set("savedIpAddress", record.get("ip_address"));
|
||||||
}
|
}
|
||||||
record.set("editing", true);
|
record.set("editing", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
allow(record) {
|
allow(record) {
|
||||||
record.set("action_name", "do_nothing");
|
record.set("action_name", "do_nothing");
|
||||||
record.save();
|
record.save();
|
||||||
},
|
}
|
||||||
|
|
||||||
block(record) {
|
@action
|
||||||
record.set("action_name", "block");
|
block(record) {
|
||||||
record.save();
|
record.set("action_name", "block");
|
||||||
},
|
record.save();
|
||||||
|
}
|
||||||
|
|
||||||
cancel(record) {
|
@action
|
||||||
const savedIpAddress = this.savedIpAddress;
|
cancel(record) {
|
||||||
if (savedIpAddress && record.get("editing")) {
|
const savedIpAddress = this.savedIpAddress;
|
||||||
record.set("ip_address", savedIpAddress);
|
if (savedIpAddress && record.get("editing")) {
|
||||||
}
|
record.set("ip_address", savedIpAddress);
|
||||||
record.set("editing", false);
|
}
|
||||||
},
|
record.set("editing", false);
|
||||||
|
}
|
||||||
|
|
||||||
save(record) {
|
@action
|
||||||
const wasEditing = record.get("editing");
|
save(record) {
|
||||||
record.set("editing", false);
|
const wasEditing = record.get("editing");
|
||||||
record
|
record.set("editing", false);
|
||||||
.save()
|
record
|
||||||
.then(() => this.set("savedIpAddress", null))
|
.save()
|
||||||
.catch((e) => {
|
.then(() => this.set("savedIpAddress", null))
|
||||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
.catch((e) => {
|
||||||
|
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||||
|
this.dialog.alert(
|
||||||
|
I18n.t("generic_error_with_reason", {
|
||||||
|
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.dialog.alert(I18n.t("generic_error"));
|
||||||
|
}
|
||||||
|
if (wasEditing) {
|
||||||
|
record.set("editing", true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
destroyRecord(record) {
|
||||||
|
return this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("admin.logs.screened_ips.delete_confirm", {
|
||||||
|
ip_address: record.get("ip_address"),
|
||||||
|
}),
|
||||||
|
didConfirm: () => {
|
||||||
|
return record
|
||||||
|
.destroy()
|
||||||
|
.then((deleted) => {
|
||||||
|
if (deleted) {
|
||||||
|
this.model.removeObject(record);
|
||||||
|
} else {
|
||||||
|
this.dialog.alert(I18n.t("generic_error"));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
this.dialog.alert(
|
this.dialog.alert(
|
||||||
I18n.t("generic_error_with_reason", {
|
I18n.t("generic_error_with_reason", {
|
||||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
error: `http: ${e.status} - ${e.body}`,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
});
|
||||||
this.dialog.alert(I18n.t("generic_error"));
|
},
|
||||||
}
|
});
|
||||||
if (wasEditing) {
|
}
|
||||||
record.set("editing", true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy(record) {
|
@action
|
||||||
return this.dialog.yesNoConfirm({
|
recordAdded(arg) {
|
||||||
message: I18n.t("admin.logs.screened_ips.delete_confirm", {
|
this.model.unshiftObject(arg);
|
||||||
ip_address: record.get("ip_address"),
|
}
|
||||||
}),
|
|
||||||
didConfirm: () => {
|
|
||||||
return record
|
|
||||||
.destroy()
|
|
||||||
.then((deleted) => {
|
|
||||||
if (deleted) {
|
|
||||||
this.model.removeObject(record);
|
|
||||||
} else {
|
|
||||||
this.dialog.alert(I18n.t("generic_error"));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
this.dialog.alert(
|
|
||||||
I18n.t("generic_error_with_reason", {
|
|
||||||
error: `http: ${e.status} - ${e.body}`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
recordAdded(arg) {
|
@action
|
||||||
this.model.unshiftObject(arg);
|
exportScreenedIpList() {
|
||||||
},
|
exportEntity("screened_ip").then(outputExportResult);
|
||||||
|
}
|
||||||
exportScreenedIpList() {
|
}
|
||||||
exportEntity("screened_ip").then(outputExportResult);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import ScreenedUrl from "admin/models/screened-url";
|
import ScreenedUrl from "admin/models/screened-url";
|
||||||
import { exportEntity } from "discourse/lib/export-csv";
|
import { exportEntity } from "discourse/lib/export-csv";
|
||||||
import { outputExportResult } from "discourse/lib/export-result";
|
import { outputExportResult } from "discourse/lib/export-result";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminLogsScreenedUrlsController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
@ -12,11 +13,10 @@ export default Controller.extend({
|
|||||||
this.set("model", result);
|
this.set("model", result);
|
||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
exportScreenedUrlList() {
|
exportScreenedUrlList() {
|
||||||
exportEntity("screened_url").then(outputExportResult);
|
exportEntity("screened_url").then(outputExportResult);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -7,22 +7,21 @@ import { outputExportResult } from "discourse/lib/export-result";
|
|||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminLogsStaffActionLogsController extends Controller {
|
||||||
queryParams: ["filters"],
|
queryParams = ["filters"];
|
||||||
|
model = null;
|
||||||
model: null,
|
filters = null;
|
||||||
filters: null,
|
userHistoryActions = null;
|
||||||
userHistoryActions: null,
|
|
||||||
|
|
||||||
@discourseComputed("filters.action_name")
|
@discourseComputed("filters.action_name")
|
||||||
actionFilter(name) {
|
actionFilter(name) {
|
||||||
return name ? I18n.t("admin.logs.staff_actions.actions." + name) : null;
|
return name ? I18n.t("admin.logs.staff_actions.actions." + name) : null;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("filters")
|
@discourseComputed("filters")
|
||||||
filtersExists(filters) {
|
filtersExists(filters) {
|
||||||
return filters && Object.keys(filters).length > 0;
|
return filters && Object.keys(filters).length > 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
_refresh() {
|
_refresh() {
|
||||||
this.store.findAll("staff-action-log", this.filters).then((result) => {
|
this.store.findAll("staff-action-log", this.filters).then((result) => {
|
||||||
@ -44,11 +43,11 @@ export default Controller.extend({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
scheduleRefresh() {
|
scheduleRefresh() {
|
||||||
scheduleOnce("afterRender", this, this._refresh);
|
scheduleOnce("afterRender", this, this._refresh);
|
||||||
},
|
}
|
||||||
|
|
||||||
resetFilters() {
|
resetFilters() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
@ -56,7 +55,7 @@ export default Controller.extend({
|
|||||||
filters: EmberObject.create(),
|
filters: EmberObject.create(),
|
||||||
});
|
});
|
||||||
this.scheduleRefresh();
|
this.scheduleRefresh();
|
||||||
},
|
}
|
||||||
|
|
||||||
changeFilters(props) {
|
changeFilters(props) {
|
||||||
this.set("model", EmberObject.create({ loadingMore: true }));
|
this.set("model", EmberObject.create({ loadingMore: true }));
|
||||||
@ -76,7 +75,7 @@ export default Controller.extend({
|
|||||||
|
|
||||||
this.send("onFiltersChange", this.filters);
|
this.send("onFiltersChange", this.filters);
|
||||||
this.scheduleRefresh();
|
this.scheduleRefresh();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterActionIdChanged(filterActionId) {
|
filterActionIdChanged(filterActionId) {
|
||||||
@ -87,7 +86,7 @@ export default Controller.extend({
|
|||||||
.action_id,
|
.action_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
clearFilter(key, event) {
|
clearFilter(key, event) {
|
||||||
@ -102,14 +101,14 @@ export default Controller.extend({
|
|||||||
} else {
|
} else {
|
||||||
this.changeFilters({ [key]: null });
|
this.changeFilters({ [key]: null });
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
clearAllFilters(event) {
|
clearAllFilters(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.set("filterActionId", null);
|
this.set("filterActionId", null);
|
||||||
this.resetFilters();
|
this.resetFilters();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterByAction(logItem, event) {
|
filterByAction(logItem, event) {
|
||||||
@ -119,35 +118,35 @@ export default Controller.extend({
|
|||||||
action_id: logItem.get("action"),
|
action_id: logItem.get("action"),
|
||||||
custom_type: logItem.get("custom_type"),
|
custom_type: logItem.get("custom_type"),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterByStaffUser(acting_user, event) {
|
filterByStaffUser(acting_user, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.changeFilters({ acting_user: acting_user.username });
|
this.changeFilters({ acting_user: acting_user.username });
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterByTargetUser(target_user, event) {
|
filterByTargetUser(target_user, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.changeFilters({ target_user: target_user.username });
|
this.changeFilters({ target_user: target_user.username });
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
filterBySubject(subject, event) {
|
filterBySubject(subject, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.changeFilters({ subject });
|
this.changeFilters({ subject });
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
exportStaffActionLogs() {
|
exportStaffActionLogs() {
|
||||||
exportEntity("staff_action").then(outputExportResult);
|
exportEntity("staff_action").then(outputExportResult);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this.model.loadMore();
|
this.model.loadMore();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showDetailsModal(model, event) {
|
showDetailsModal(model, event) {
|
||||||
@ -157,7 +156,7 @@ export default Controller.extend({
|
|||||||
admin: true,
|
admin: true,
|
||||||
modalClass: "log-details-modal",
|
modalClass: "log-details-modal",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showCustomDetailsModal(model, event) {
|
showCustomDetailsModal(model, event) {
|
||||||
@ -168,5 +167,5 @@ export default Controller.extend({
|
|||||||
modalClass: "history-modal",
|
modalClass: "history-modal",
|
||||||
});
|
});
|
||||||
modal.loadDiff();
|
modal.loadDiff();
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,59 +1,63 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { or } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import Permalink from "admin/models/permalink";
|
import Permalink from "admin/models/permalink";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { clipboardCopy } from "discourse/lib/utilities";
|
import { clipboardCopy } from "discourse/lib/utilities";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { or } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminPermalinksController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
loading: false,
|
|
||||||
filter: null,
|
loading = false;
|
||||||
showSearch: or("model.length", "filter"),
|
filter = null;
|
||||||
|
|
||||||
|
@or("model.length", "filter") showSearch;
|
||||||
|
|
||||||
_debouncedShow() {
|
_debouncedShow() {
|
||||||
Permalink.findAll(this.filter).then((result) => {
|
Permalink.findAll(this.filter).then((result) => {
|
||||||
this.set("model", result);
|
this.set("model", result);
|
||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("filter")
|
@observes("filter")
|
||||||
show() {
|
show() {
|
||||||
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
recordAdded(arg) {
|
recordAdded(arg) {
|
||||||
this.model.unshiftObject(arg);
|
this.model.unshiftObject(arg);
|
||||||
},
|
}
|
||||||
|
|
||||||
copyUrl(pl) {
|
@action
|
||||||
let linkElement = document.querySelector(`#admin-permalink-${pl.id}`);
|
copyUrl(pl) {
|
||||||
clipboardCopy(linkElement.textContent);
|
let linkElement = document.querySelector(`#admin-permalink-${pl.id}`);
|
||||||
},
|
clipboardCopy(linkElement.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
destroy(record) {
|
@action
|
||||||
return this.dialog.yesNoConfirm({
|
destroyRecord(record) {
|
||||||
message: I18n.t("admin.permalink.delete_confirm"),
|
return this.dialog.yesNoConfirm({
|
||||||
didConfirm: () => {
|
message: I18n.t("admin.permalink.delete_confirm"),
|
||||||
return record.destroy().then(
|
didConfirm: () => {
|
||||||
(deleted) => {
|
return record.destroy().then(
|
||||||
if (deleted) {
|
(deleted) => {
|
||||||
this.model.removeObject(record);
|
if (deleted) {
|
||||||
} else {
|
this.model.removeObject(record);
|
||||||
this.dialog.alert(I18n.t("generic_error"));
|
} else {
|
||||||
}
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
this.dialog.alert(I18n.t("generic_error"));
|
this.dialog.alert(I18n.t("generic_error"));
|
||||||
}
|
}
|
||||||
);
|
},
|
||||||
},
|
function () {
|
||||||
});
|
this.dialog.alert(I18n.t("generic_error"));
|
||||||
},
|
}
|
||||||
},
|
);
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import Controller from "@ember/controller";
|
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminPluginsController extends Controller {
|
||||||
router: service(),
|
@service router;
|
||||||
|
|
||||||
get adminRoutes() {
|
get adminRoutes() {
|
||||||
return this.allAdminRoutes.filter((r) => this.routeExists(r.full_location));
|
return this.allAdminRoutes.filter((r) => this.routeExists(r.full_location));
|
||||||
},
|
}
|
||||||
|
|
||||||
get brokenAdminRoutes() {
|
get brokenAdminRoutes() {
|
||||||
return this.allAdminRoutes.filter(
|
return this.allAdminRoutes.filter(
|
||||||
(r) => !this.routeExists(r.full_location)
|
(r) => !this.routeExists(r.full_location)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
get allAdminRoutes() {
|
get allAdminRoutes() {
|
||||||
return this.model
|
return this.model
|
||||||
@ -21,7 +21,7 @@ export default Controller.extend({
|
|||||||
return p.admin_route;
|
return p.admin_route;
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
},
|
}
|
||||||
|
|
||||||
routeExists(routeName) {
|
routeExists(routeName) {
|
||||||
try {
|
try {
|
||||||
@ -30,5 +30,5 @@ export default Controller.extend({
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminReportsShowController extends Controller {
|
||||||
queryParams: ["start_date", "end_date", "filters", "chart_grouping", "mode"],
|
queryParams = ["start_date", "end_date", "filters", "chart_grouping", "mode"];
|
||||||
start_date: null,
|
start_date = null;
|
||||||
end_date: null,
|
end_date = null;
|
||||||
filters: null,
|
filters = null;
|
||||||
chart_grouping: null,
|
chart_grouping = null;
|
||||||
|
|
||||||
@discourseComputed("model.type")
|
@discourseComputed("model.type")
|
||||||
reportOptions(type) {
|
reportOptions(type) {
|
||||||
@ -19,5 +19,5 @@ export default Controller.extend({
|
|||||||
options.chartGrouping = this.chart_grouping;
|
options.chartGrouping = this.chart_grouping;
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,24 +2,19 @@ import Controller from "@ember/controller";
|
|||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
export const DEFAULT_PERIOD = "yearly";
|
export const DEFAULT_PERIOD = "yearly";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminSearchLogsIndexController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
period: DEFAULT_PERIOD,
|
period = DEFAULT_PERIOD;
|
||||||
searchType: "all",
|
searchType = "all";
|
||||||
|
searchTypeOptions = [
|
||||||
init() {
|
{
|
||||||
this._super(...arguments);
|
id: "all",
|
||||||
|
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||||
this.searchTypeOptions = [
|
},
|
||||||
{
|
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||||
id: "all",
|
{
|
||||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
id: "full_page",
|
||||||
},
|
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
},
|
||||||
{
|
];
|
||||||
id: "full_page",
|
}
|
||||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -2,29 +2,24 @@ import Controller from "@ember/controller";
|
|||||||
import { DEFAULT_PERIOD } from "admin/controllers/admin-search-logs-index";
|
import { DEFAULT_PERIOD } from "admin/controllers/admin-search-logs-index";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminSearchLogsTermController extends Controller {
|
||||||
loading: false,
|
loading = false;
|
||||||
term: null,
|
term = null;
|
||||||
period: DEFAULT_PERIOD,
|
period = DEFAULT_PERIOD;
|
||||||
searchType: "all",
|
searchType = "all";
|
||||||
|
searchTypeOptions = [
|
||||||
init() {
|
{
|
||||||
this._super(...arguments);
|
id: "all",
|
||||||
|
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||||
this.searchTypeOptions = [
|
},
|
||||||
{
|
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||||
id: "all",
|
{
|
||||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
id: "full_page",
|
||||||
},
|
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
},
|
||||||
{
|
{
|
||||||
id: "full_page",
|
id: "click_through_only",
|
||||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
name: I18n.t("admin.logs.search_logs.types.click_through_only"),
|
||||||
},
|
},
|
||||||
{
|
];
|
||||||
id: "click_through_only",
|
}
|
||||||
name: I18n.t("admin.logs.search_logs.types.click_through_only"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminSiteSettingsCategoryController extends Controller {
|
||||||
adminSiteSettings: controller(),
|
@controller adminSiteSettings;
|
||||||
categoryNameKey: null,
|
|
||||||
|
categoryNameKey = null;
|
||||||
|
|
||||||
@discourseComputed("adminSiteSettings.visibleSiteSettings", "categoryNameKey")
|
@discourseComputed("adminSiteSettings.visibleSiteSettings", "categoryNameKey")
|
||||||
category(categories, nameKey) {
|
category(categories, nameKey) {
|
||||||
return (categories || []).findBy("nameKey", nameKey);
|
return (categories || []).findBy("nameKey", nameKey);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("category")
|
@discourseComputed("category")
|
||||||
filteredContent(category) {
|
filteredContent(category) {
|
||||||
return category ? category.siteSettings : [];
|
return category ? category.siteSettings : [];
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { debounce, observes } from "discourse-common/utils/decorators";
|
import { debounce } from "discourse-common/utils/decorators";
|
||||||
|
import { observes } from "@ember-decorators/object";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminSiteSettingsController extends Controller {
|
||||||
filter: null,
|
filter = null;
|
||||||
allSiteSettings: alias("model"),
|
|
||||||
visibleSiteSettings: null,
|
@alias("model") allSiteSettings;
|
||||||
onlyOverridden: false,
|
|
||||||
|
visibleSiteSettings = null;
|
||||||
|
onlyOverridden = false;
|
||||||
|
|
||||||
filterContentNow(category) {
|
filterContentNow(category) {
|
||||||
// If we have no content, don't bother filtering anything
|
// If we have no content, don't bother filtering anything
|
||||||
@ -109,9 +112,13 @@ export default Controller.extend({
|
|||||||
"adminSiteSettingsCategory",
|
"adminSiteSettingsCategory",
|
||||||
category || "all_results"
|
category || "all_results"
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("filter", "onlyOverridden", "model")
|
@observes("filter", "onlyOverridden", "model")
|
||||||
|
optsChanged() {
|
||||||
|
this.filterContent();
|
||||||
|
}
|
||||||
|
|
||||||
@debounce(INPUT_DELAY)
|
@debounce(INPUT_DELAY)
|
||||||
filterContent() {
|
filterContent() {
|
||||||
if (this._skipBounce) {
|
if (this._skipBounce) {
|
||||||
@ -119,12 +126,12 @@ export default Controller.extend({
|
|||||||
} else {
|
} else {
|
||||||
this.filterContentNow(this.categoryNameKey);
|
this.filterContentNow(this.categoryNameKey);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
clearFilter() {
|
clearFilter() {
|
||||||
this.setProperties({ filter: "", onlyOverridden: false });
|
this.setProperties({ filter: "", onlyOverridden: false });
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleMenu() {
|
toggleMenu() {
|
||||||
@ -132,5 +139,5 @@ export default Controller.extend({
|
|||||||
["mobile-closed", "mobile-open"].forEach((state) => {
|
["mobile-closed", "mobile-open"].forEach((state) => {
|
||||||
adminDetail.classList.toggle(state);
|
adminDetail.classList.toggle(state);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
let lastSearch;
|
let lastSearch;
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminSiteTextIndexController extends Controller {
|
||||||
searching: false,
|
searching = false;
|
||||||
siteTexts: null,
|
siteTexts = null;
|
||||||
preferred: false,
|
preferred = false;
|
||||||
queryParams: ["q", "overridden", "locale"],
|
queryParams = ["q", "overridden", "locale"];
|
||||||
locale: null,
|
locale = null;
|
||||||
|
q = null;
|
||||||
q: null,
|
overridden = false;
|
||||||
overridden: false,
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
this.set("locale", this.siteSettings.default_locale);
|
this.set("locale", this.siteSettings.default_locale);
|
||||||
},
|
}
|
||||||
|
|
||||||
_performSearch() {
|
_performSearch() {
|
||||||
this.store
|
this.store
|
||||||
@ -26,12 +26,12 @@ export default Controller.extend({
|
|||||||
this.set("siteTexts", results);
|
this.set("siteTexts", results);
|
||||||
})
|
})
|
||||||
.finally(() => this.set("searching", false));
|
.finally(() => this.set("searching", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
availableLocales() {
|
availableLocales() {
|
||||||
return JSON.parse(this.siteSettings.available_locales);
|
return JSON.parse(this.siteSettings.available_locales);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("locale")
|
@discourseComputed("locale")
|
||||||
fallbackLocaleFullName() {
|
fallbackLocaleFullName() {
|
||||||
@ -40,39 +40,41 @@ export default Controller.extend({
|
|||||||
return l.value === this.siteTexts.extras.fallback_locale;
|
return l.value === this.siteTexts.extras.fallback_locale;
|
||||||
}).name;
|
}).name;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
edit(siteText) {
|
edit(siteText) {
|
||||||
this.transitionToRoute("adminSiteText.edit", siteText.get("id"), {
|
this.transitionToRoute("adminSiteText.edit", siteText.get("id"), {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
locale: this.locale,
|
locale: this.locale,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
toggleOverridden() {
|
@action
|
||||||
this.toggleProperty("overridden");
|
toggleOverridden() {
|
||||||
|
this.toggleProperty("overridden");
|
||||||
|
this.set("searching", true);
|
||||||
|
discourseDebounce(this, this._performSearch, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
search() {
|
||||||
|
const q = this.q;
|
||||||
|
if (q !== lastSearch) {
|
||||||
this.set("searching", true);
|
this.set("searching", true);
|
||||||
discourseDebounce(this, this._performSearch, 400);
|
discourseDebounce(this, this._performSearch, 400);
|
||||||
},
|
lastSearch = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
search() {
|
@action
|
||||||
const q = this.q;
|
updateLocale(value) {
|
||||||
if (q !== lastSearch) {
|
this.setProperties({
|
||||||
this.set("searching", true);
|
searching: true,
|
||||||
discourseDebounce(this, this._performSearch, 400);
|
locale: value,
|
||||||
lastSearch = q;
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateLocale(value) {
|
discourseDebounce(this, this._performSearch, 400);
|
||||||
this.setProperties({
|
}
|
||||||
searching: true,
|
}
|
||||||
locale: value,
|
|
||||||
});
|
|
||||||
|
|
||||||
discourseDebounce(this, this._performSearch, 400);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { alias, sort } from "@ember/object/computed";
|
import { alias, sort } from "@ember/object/computed";
|
||||||
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import GrantBadgeController from "discourse/mixins/grant-badge-controller";
|
import GrantBadgeController from "discourse/mixins/grant-badge-controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend(GrantBadgeController, {
|
export default class AdminUserBadgesController extends Controller.extend(
|
||||||
adminUser: controller(),
|
GrantBadgeController
|
||||||
dialog: service(),
|
) {
|
||||||
user: alias("adminUser.model"),
|
@service dialog;
|
||||||
userBadges: alias("model"),
|
@controller adminUser;
|
||||||
allBadges: alias("badges"),
|
|
||||||
sortedBadges: sort("model", "badgeSortOrder"),
|
|
||||||
|
|
||||||
init() {
|
@alias("adminUser.model") user;
|
||||||
this._super(...arguments);
|
@alias("model") userBadges;
|
||||||
|
@alias("badges") allBadges;
|
||||||
|
@sort("model", "badgeSortOrder") sortedBadges;
|
||||||
|
|
||||||
this.badgeSortOrder = ["granted_at:desc"];
|
badgeSortOrder = ["granted_at:desc"];
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("model", "model.[]", "model.expandedBadges.[]")
|
@discourseComputed("model", "model.[]", "model.expandedBadges.[]")
|
||||||
groupedBadges() {
|
groupedBadges() {
|
||||||
@ -59,46 +59,47 @@ export default Controller.extend(GrantBadgeController, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return expanded.sortBy("granted_at").reverse();
|
return expanded.sortBy("granted_at").reverse();
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
expandGroup(userBadge) {
|
expandGroup(userBadge) {
|
||||||
const model = this.model;
|
const model = this.model;
|
||||||
model.set("expandedBadges", model.get("expandedBadges") || []);
|
model.set("expandedBadges", model.get("expandedBadges") || []);
|
||||||
model.get("expandedBadges").pushObject(userBadge.badge.id);
|
model.get("expandedBadges").pushObject(userBadge.badge.id);
|
||||||
},
|
}
|
||||||
|
|
||||||
grantBadge() {
|
@action
|
||||||
this.grantBadge(
|
grantBadge() {
|
||||||
this.selectedBadgeId,
|
this.grantBadge(
|
||||||
this.get("user.username"),
|
this.selectedBadgeId,
|
||||||
this.badgeReason
|
this.get("user.username"),
|
||||||
).then(
|
this.badgeReason
|
||||||
() => {
|
).then(
|
||||||
this.set("badgeReason", "");
|
() => {
|
||||||
next(() => {
|
this.set("badgeReason", "");
|
||||||
// Update the selected badge ID after the combobox has re-rendered.
|
next(() => {
|
||||||
const newSelectedBadge = this.grantableBadges[0];
|
// Update the selected badge ID after the combobox has re-rendered.
|
||||||
if (newSelectedBadge) {
|
const newSelectedBadge = this.grantableBadges[0];
|
||||||
this.set("selectedBadgeId", newSelectedBadge.get("id"));
|
if (newSelectedBadge) {
|
||||||
}
|
this.set("selectedBadgeId", newSelectedBadge.get("id"));
|
||||||
});
|
}
|
||||||
},
|
});
|
||||||
function (error) {
|
},
|
||||||
popupAjaxError(error);
|
function (error) {
|
||||||
}
|
popupAjaxError(error);
|
||||||
);
|
}
|
||||||
},
|
);
|
||||||
|
}
|
||||||
|
|
||||||
revokeBadge(userBadge) {
|
@action
|
||||||
return this.dialog.yesNoConfirm({
|
revokeBadge(userBadge) {
|
||||||
message: I18n.t("admin.badges.revoke_confirm"),
|
return this.dialog.yesNoConfirm({
|
||||||
didConfirm: () => {
|
message: I18n.t("admin.badges.revoke_confirm"),
|
||||||
return userBadge.revoke().then(() => {
|
didConfirm: () => {
|
||||||
this.model.removeObject(userBadge);
|
return userBadge.revoke().then(() => {
|
||||||
});
|
this.model.removeObject(userBadge);
|
||||||
},
|
});
|
||||||
});
|
},
|
||||||
},
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,73 +1,74 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { gte, sort } from "@ember/object/computed";
|
import { gte, sort } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
const MAX_FIELDS = 30;
|
const MAX_FIELDS = 30;
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminUserFieldsController extends Controller {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
fieldTypes: null,
|
|
||||||
createDisabled: gte("model.length", MAX_FIELDS),
|
|
||||||
sortedFields: sort("model", "fieldSortOrder"),
|
|
||||||
|
|
||||||
init() {
|
fieldTypes = null;
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this.fieldSortOrder = ["position"];
|
@gte("model.length", MAX_FIELDS) createDisabled;
|
||||||
},
|
@sort("model", "fieldSortOrder") sortedFields;
|
||||||
|
|
||||||
actions: {
|
fieldSortOrder = ["position"];
|
||||||
createField() {
|
|
||||||
const f = this.store.createRecord("user-field", {
|
@action
|
||||||
field_type: "text",
|
createField() {
|
||||||
position: MAX_FIELDS,
|
const f = this.store.createRecord("user-field", {
|
||||||
|
field_type: "text",
|
||||||
|
position: MAX_FIELDS,
|
||||||
|
});
|
||||||
|
this.model.pushObject(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
moveUp(f) {
|
||||||
|
const idx = this.sortedFields.indexOf(f);
|
||||||
|
if (idx) {
|
||||||
|
const prev = this.sortedFields.objectAt(idx - 1);
|
||||||
|
const prevPos = prev.get("position");
|
||||||
|
|
||||||
|
prev.update({ position: f.get("position") });
|
||||||
|
f.update({ position: prevPos });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
moveDown(f) {
|
||||||
|
const idx = this.sortedFields.indexOf(f);
|
||||||
|
if (idx > -1) {
|
||||||
|
const next = this.sortedFields.objectAt(idx + 1);
|
||||||
|
const nextPos = next.get("position");
|
||||||
|
|
||||||
|
next.update({ position: f.get("position") });
|
||||||
|
f.update({ position: nextPos });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
destroyField(f) {
|
||||||
|
const model = this.model;
|
||||||
|
|
||||||
|
// Only confirm if we already been saved
|
||||||
|
if (f.get("id")) {
|
||||||
|
this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("admin.user_fields.delete_confirm"),
|
||||||
|
didConfirm: () => {
|
||||||
|
return f
|
||||||
|
.destroyRecord()
|
||||||
|
.then(function () {
|
||||||
|
model.removeObject(f);
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.model.pushObject(f);
|
} else {
|
||||||
},
|
model.removeObject(f);
|
||||||
|
}
|
||||||
moveUp(f) {
|
}
|
||||||
const idx = this.sortedFields.indexOf(f);
|
}
|
||||||
if (idx) {
|
|
||||||
const prev = this.sortedFields.objectAt(idx - 1);
|
|
||||||
const prevPos = prev.get("position");
|
|
||||||
|
|
||||||
prev.update({ position: f.get("position") });
|
|
||||||
f.update({ position: prevPos });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
moveDown(f) {
|
|
||||||
const idx = this.sortedFields.indexOf(f);
|
|
||||||
if (idx > -1) {
|
|
||||||
const next = this.sortedFields.objectAt(idx + 1);
|
|
||||||
const nextPos = next.get("position");
|
|
||||||
|
|
||||||
next.update({ position: f.get("position") });
|
|
||||||
f.update({ position: nextPos });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy(f) {
|
|
||||||
const model = this.model;
|
|
||||||
|
|
||||||
// Only confirm if we already been saved
|
|
||||||
if (f.get("id")) {
|
|
||||||
this.dialog.yesNoConfirm({
|
|
||||||
message: I18n.t("admin.user_fields.delete_confirm"),
|
|
||||||
didConfirm: () => {
|
|
||||||
return f
|
|
||||||
.destroyRecord()
|
|
||||||
.then(function () {
|
|
||||||
model.removeObject(f);
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
model.removeObject(f);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
export default Controller.extend();
|
export default class AdminUserController extends Controller {}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import { action } from "@ember/object";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import { observes } from "@ember-decorators/object";
|
||||||
import AdminUser from "admin/models/admin-user";
|
import AdminUser from "admin/models/admin-user";
|
||||||
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
@ -7,41 +9,55 @@ import { INPUT_DELAY } from "discourse-common/config/environment";
|
|||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { i18n } from "discourse/lib/computed";
|
import { i18n } from "discourse/lib/computed";
|
||||||
|
|
||||||
export default Controller.extend(CanCheckEmails, {
|
export default class AdminUsersListShowController extends Controller.extend(
|
||||||
model: null,
|
CanCheckEmails
|
||||||
query: null,
|
) {
|
||||||
order: null,
|
model = null;
|
||||||
asc: null,
|
query = null;
|
||||||
showEmails: false,
|
order = null;
|
||||||
refreshing: false,
|
asc = null;
|
||||||
listFilter: null,
|
showEmails = false;
|
||||||
selectAll: false,
|
refreshing = false;
|
||||||
searchHint: i18n("search_hint"),
|
listFilter = null;
|
||||||
|
selectAll = false;
|
||||||
|
|
||||||
init() {
|
@i18n("search_hint") searchHint;
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this._page = 1;
|
_page = 1;
|
||||||
this._results = [];
|
_results = [];
|
||||||
this._canLoadMore = true;
|
_canLoadMore = true;
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("query")
|
@discourseComputed("query")
|
||||||
title(query) {
|
title(query) {
|
||||||
return I18n.t("admin.users.titles." + query);
|
return I18n.t("admin.users.titles." + query);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
@discourseComputed("showEmails")
|
||||||
|
columnCount(showEmails) {
|
||||||
|
let colCount = 7; // note that the first column is hardcoded in the template
|
||||||
|
|
||||||
|
if (showEmails) {
|
||||||
|
colCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.siteSettings.must_approve_users) {
|
||||||
|
colCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return colCount;
|
||||||
|
}
|
||||||
|
|
||||||
@observes("listFilter")
|
@observes("listFilter")
|
||||||
_filterUsers() {
|
_filterUsers() {
|
||||||
discourseDebounce(this, this.resetFilters, INPUT_DELAY);
|
discourseDebounce(this, this.resetFilters, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
resetFilters() {
|
resetFilters() {
|
||||||
this._page = 1;
|
this._page = 1;
|
||||||
this._results = [];
|
this._results = [];
|
||||||
this._canLoadMore = true;
|
this._canLoadMore = true;
|
||||||
this._refreshUsers();
|
this._refreshUsers();
|
||||||
},
|
}
|
||||||
|
|
||||||
_refreshUsers() {
|
_refreshUsers() {
|
||||||
if (!this._canLoadMore) {
|
if (!this._canLoadMore) {
|
||||||
@ -69,17 +85,17 @@ export default Controller.extend(CanCheckEmails, {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.set("refreshing", false);
|
this.set("refreshing", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this._page += 1;
|
this._page += 1;
|
||||||
this._refreshUsers();
|
this._refreshUsers();
|
||||||
},
|
}
|
||||||
|
|
||||||
toggleEmailVisibility() {
|
@action
|
||||||
this.toggleProperty("showEmails");
|
toggleEmailVisibility() {
|
||||||
this.resetFilters();
|
this.toggleProperty("showEmails");
|
||||||
},
|
this.resetFilters();
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,32 +1,35 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { or } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import WatchedWord from "admin/models/watched-word";
|
import WatchedWord from "admin/models/watched-word";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { fmt } from "discourse/lib/computed";
|
import { fmt } from "discourse/lib/computed";
|
||||||
import { or } from "@ember/object/computed";
|
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminWatchedWordsActionController extends Controller {
|
||||||
adminWatchedWords: controller(),
|
@service dialog;
|
||||||
actionNameKey: null,
|
@controller adminWatchedWords;
|
||||||
dialog: service(),
|
|
||||||
downloadLink: fmt(
|
actionNameKey = null;
|
||||||
"actionNameKey",
|
|
||||||
"/admin/customize/watched_words/action/%@/download"
|
@fmt("actionNameKey", "/admin/customize/watched_words/action/%@/download")
|
||||||
),
|
downloadLink;
|
||||||
showWordsList: or("adminWatchedWords.showWords", "adminWatchedWords.filter"),
|
|
||||||
|
@or("adminWatchedWords.showWords", "adminWatchedWords.filter")
|
||||||
|
showWordsList;
|
||||||
|
|
||||||
findAction(actionName) {
|
findAction(actionName) {
|
||||||
return (this.adminWatchedWords.model || []).findBy("nameKey", actionName);
|
return (this.adminWatchedWords.model || []).findBy("nameKey", actionName);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("actionNameKey", "adminWatchedWords.model")
|
@discourseComputed("actionNameKey", "adminWatchedWords.model")
|
||||||
currentAction(actionName) {
|
currentAction(actionName) {
|
||||||
return this.findAction(actionName);
|
return this.findAction(actionName);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentAction.words.[]")
|
@discourseComputed("currentAction.words.[]")
|
||||||
regexpError(words) {
|
regexpError(words) {
|
||||||
@ -37,78 +40,81 @@ export default Controller.extend({
|
|||||||
return I18n.t("admin.watched_words.invalid_regex", { word });
|
return I18n.t("admin.watched_words.invalid_regex", { word });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("actionNameKey")
|
@discourseComputed("actionNameKey")
|
||||||
actionDescription(actionNameKey) {
|
actionDescription(actionNameKey) {
|
||||||
return I18n.t("admin.watched_words.action_descriptions." + actionNameKey);
|
return I18n.t("admin.watched_words.action_descriptions." + actionNameKey);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
recordAdded(arg) {
|
recordAdded(arg) {
|
||||||
const action = this.findAction(this.actionNameKey);
|
const foundAction = this.findAction(this.actionNameKey);
|
||||||
if (!action) {
|
if (!foundAction) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
action.words.unshiftObject(arg);
|
foundAction.words.unshiftObject(arg);
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
// remove from other actions lists
|
// remove from other actions lists
|
||||||
let match = null;
|
let match = null;
|
||||||
this.adminWatchedWords.model.forEach((otherAction) => {
|
this.adminWatchedWords.model.forEach((otherAction) => {
|
||||||
|
if (match) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherAction.nameKey !== this.actionNameKey) {
|
||||||
|
match = otherAction.words.findBy("id", arg.id);
|
||||||
if (match) {
|
if (match) {
|
||||||
return;
|
otherAction.words.removeObject(match);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (otherAction.nameKey !== this.actionNameKey) {
|
@action
|
||||||
match = otherAction.words.findBy("id", arg.id);
|
recordRemoved(arg) {
|
||||||
if (match) {
|
if (this.currentAction) {
|
||||||
otherAction.words.removeObject(match);
|
this.currentAction.words.removeObject(arg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
uploadComplete() {
|
||||||
|
WatchedWord.findAll().then((data) => {
|
||||||
|
this.adminWatchedWords.set("model", data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
test() {
|
||||||
|
WatchedWord.findAll().then((data) => {
|
||||||
|
this.adminWatchedWords.set("model", data);
|
||||||
|
showModal("admin-watched-word-test", {
|
||||||
|
admin: true,
|
||||||
|
model: this.currentAction,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
clearAll() {
|
||||||
|
const actionKey = this.actionNameKey;
|
||||||
|
this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("admin.watched_words.clear_all_confirm", {
|
||||||
|
action: I18n.t("admin.watched_words.actions." + actionKey),
|
||||||
|
}),
|
||||||
|
didConfirm: () => {
|
||||||
|
ajax(`/admin/customize/watched_words/action/${actionKey}.json`, {
|
||||||
|
type: "DELETE",
|
||||||
|
}).then(() => {
|
||||||
|
const foundAction = this.findAction(actionKey);
|
||||||
|
if (foundAction) {
|
||||||
|
foundAction.set("words", []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
},
|
});
|
||||||
|
}
|
||||||
recordRemoved(arg) {
|
}
|
||||||
if (this.currentAction) {
|
|
||||||
this.currentAction.words.removeObject(arg);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
uploadComplete() {
|
|
||||||
WatchedWord.findAll().then((data) => {
|
|
||||||
this.adminWatchedWords.set("model", data);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
test() {
|
|
||||||
WatchedWord.findAll().then((data) => {
|
|
||||||
this.adminWatchedWords.set("model", data);
|
|
||||||
showModal("admin-watched-word-test", {
|
|
||||||
admin: true,
|
|
||||||
model: this.currentAction,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
clearAll() {
|
|
||||||
const actionKey = this.actionNameKey;
|
|
||||||
this.dialog.yesNoConfirm({
|
|
||||||
message: I18n.t("admin.watched_words.clear_all_confirm", {
|
|
||||||
action: I18n.t("admin.watched_words.actions." + actionKey),
|
|
||||||
}),
|
|
||||||
didConfirm: () => {
|
|
||||||
ajax(`/admin/customize/watched_words/action/${actionKey}.json`, {
|
|
||||||
type: "DELETE",
|
|
||||||
}).then(() => {
|
|
||||||
const action = this.findAction(actionKey);
|
|
||||||
if (action) {
|
|
||||||
action.set("words", []);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import EmberObject, { action } from "@ember/object";
|
|||||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminWatchedWordsController extends Controller {
|
||||||
filter: null,
|
filter = null;
|
||||||
showWords: false,
|
showWords = false;
|
||||||
|
|
||||||
_filterContent() {
|
_filterContent() {
|
||||||
if (isEmpty(this.allWatchedWords)) {
|
if (isEmpty(this.allWatchedWords)) {
|
||||||
@ -36,17 +36,17 @@ export default Controller.extend({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.set("model", model);
|
this.set("model", model);
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("filter")
|
@observes("filter")
|
||||||
filterContent() {
|
filterContent() {
|
||||||
discourseDebounce(this, this._filterContent, INPUT_DELAY);
|
discourseDebounce(this, this._filterContent, INPUT_DELAY);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
clearFilter() {
|
clearFilter() {
|
||||||
this.set("filter", "");
|
this.set("filter", "");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleMenu() {
|
toggleMenu() {
|
||||||
@ -54,5 +54,5 @@ export default Controller.extend({
|
|||||||
["mobile-closed", "mobile-open"].forEach((state) => {
|
["mobile-closed", "mobile-open"].forEach((state) => {
|
||||||
adminDetail.classList.toggle(state);
|
adminDetail.classList.toggle(state);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,23 +1,24 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import EmberObject, { action } from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminWebHooksEditController extends Controller {
|
||||||
adminWebHooks: controller(),
|
@service dialog;
|
||||||
dialog: service(),
|
@controller adminWebHooks;
|
||||||
eventTypes: alias("adminWebHooks.eventTypes"),
|
|
||||||
defaultEventTypes: alias("adminWebHooks.defaultEventTypes"),
|
@alias("adminWebHooks.eventTypes") eventTypes;
|
||||||
contentTypes: alias("adminWebHooks.contentTypes"),
|
@alias("adminWebHooks.defaultEventTypes") defaultEventTypes;
|
||||||
|
@alias("adminWebHooks.contentTypes") contentTypes;
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
showTagsFilter() {
|
showTagsFilter() {
|
||||||
return this.siteSettings.tagging_enabled;
|
return this.siteSettings.tagging_enabled;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.isSaving", "saved", "saveButtonDisabled")
|
@discourseComputed("model.isSaving", "saved", "saveButtonDisabled")
|
||||||
savingStatus(isSaving, saved, saveButtonDisabled) {
|
savingStatus(isSaving, saved, saveButtonDisabled) {
|
||||||
@ -29,14 +30,14 @@ export default Controller.extend({
|
|||||||
// Use side effect of validation to clear saved text
|
// Use side effect of validation to clear saved text
|
||||||
this.set("saved", false);
|
this.set("saved", false);
|
||||||
return "";
|
return "";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.isNew")
|
@discourseComputed("model.isNew")
|
||||||
saveButtonText(isNew) {
|
saveButtonText(isNew) {
|
||||||
return isNew
|
return isNew
|
||||||
? I18n.t("admin.web_hooks.create")
|
? I18n.t("admin.web_hooks.create")
|
||||||
: I18n.t("admin.web_hooks.save");
|
: I18n.t("admin.web_hooks.save");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.secret")
|
@discourseComputed("model.secret")
|
||||||
secretValidation(secret) {
|
secretValidation(secret) {
|
||||||
@ -55,7 +56,7 @@ export default Controller.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.wildcard_web_hook", "model.web_hook_event_types.[]")
|
@discourseComputed("model.wildcard_web_hook", "model.web_hook_event_types.[]")
|
||||||
eventTypeValidation(isWildcard, eventTypes) {
|
eventTypeValidation(isWildcard, eventTypes) {
|
||||||
@ -65,7 +66,7 @@ export default Controller.extend({
|
|||||||
reason: I18n.t("admin.web_hooks.event_type_missing"),
|
reason: I18n.t("admin.web_hooks.event_type_missing"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.isSaving",
|
"model.isSaving",
|
||||||
@ -82,7 +83,7 @@ export default Controller.extend({
|
|||||||
return isSaving
|
return isSaving
|
||||||
? false
|
? false
|
||||||
: secretValidation || eventTypeValidation || isEmpty(payloadUrl);
|
: secretValidation || eventTypeValidation || isEmpty(payloadUrl);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async save() {
|
async save() {
|
||||||
@ -97,5 +98,5 @@ export default Controller.extend({
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
popupAjaxError(e);
|
popupAjaxError(e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminWebHooksIndexController extends Controller {
|
||||||
adminWebHooks: controller(),
|
@service dialog;
|
||||||
dialog: service(),
|
@controller adminWebHooks;
|
||||||
contentTypes: alias("adminWebHooks.contentTypes"),
|
|
||||||
defaultEventTypes: alias("adminWebHooks.defaultEventTypes"),
|
@alias("adminWebHooks.contentTypes") contentTypes;
|
||||||
deliveryStatuses: alias("adminWebHooks.deliveryStatuses"),
|
@alias("adminWebHooks.defaultEventTypes") defaultEventTypes;
|
||||||
eventTypes: alias("adminWebHooks.eventTypes"),
|
@alias("adminWebHooks.deliveryStatuses") deliveryStatuses;
|
||||||
model: alias("adminWebHooks.model"),
|
@alias("adminWebHooks.eventTypes") eventTypes;
|
||||||
|
@alias("adminWebHooks.model") model;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
destroy(webhook) {
|
destroy(webhook) {
|
||||||
@ -27,10 +28,10 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
this.model.loadMore();
|
this.model.loadMore();
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminWebHooksShowController extends Controller {
|
||||||
adminWebHooks: controller(),
|
@service dialog;
|
||||||
dialog: service(),
|
@service router;
|
||||||
router: service(),
|
@controller adminWebHooks;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
edit() {
|
edit() {
|
||||||
return this.router.transitionTo("adminWebHooks.edit", this.model);
|
return this.router.transitionTo("adminWebHooks.edit", this.model);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -28,5 +28,5 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
|
|
||||||
export default Controller.extend({});
|
export default class AdminWebHooksController extends Controller {}
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminController extends Controller {
|
||||||
router: service(),
|
@service router;
|
||||||
|
|
||||||
@discourseComputed("siteSettings.enable_group_directory")
|
@discourseComputed("siteSettings.enable_group_directory")
|
||||||
showGroups(enableGroupDirectory) {
|
showGroups(enableGroupDirectory) {
|
||||||
return !enableGroupDirectory;
|
return !enableGroupDirectory;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("siteSettings.enable_badges")
|
@discourseComputed("siteSettings.enable_badges")
|
||||||
showBadges(enableBadges) {
|
showBadges(enableBadges) {
|
||||||
return this.currentUser.get("admin") && enableBadges;
|
return this.currentUser.get("admin") && enableBadges;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("router._router.currentPath")
|
@discourseComputed("router._router.currentPath")
|
||||||
adminContentsClassName(currentPath) {
|
adminContentsClassName(currentPath) {
|
||||||
@ -37,5 +37,5 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return cssClasses;
|
return cssClasses;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import Controller, { inject as controller } from "@ember/controller";
|
import { action } from "@ember/object";
|
||||||
import { and, not } from "@ember/object/computed";
|
import { and, not } from "@ember/object/computed";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
import { observes } from "@ember-decorators/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
@ -53,18 +55,20 @@ const SCSS_VARIABLE_NAMES = [
|
|||||||
"love-low",
|
"love-low",
|
||||||
];
|
];
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminAddUploadController extends Controller.extend(
|
||||||
adminCustomizeThemesShow: controller(),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
@controller adminCustomizeThemesShow;
|
||||||
|
|
||||||
uploadUrl: "/admin/themes/upload_asset",
|
uploadUrl = "/admin/themes/upload_asset";
|
||||||
|
|
||||||
|
@and("nameValid", "fileSelected") enabled;
|
||||||
|
@not("enabled") disabled;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.set("name", null);
|
this.set("name", null);
|
||||||
this.set("fileSelected", false);
|
this.set("fileSelected", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
enabled: and("nameValid", "fileSelected"),
|
|
||||||
disabled: not("enabled"),
|
|
||||||
|
|
||||||
@discourseComputed("name", "adminCustomizeThemesShow.model.theme_fields")
|
@discourseComputed("name", "adminCustomizeThemesShow.model.theme_fields")
|
||||||
errorMessage(name, themeFields) {
|
errorMessage(name, themeFields) {
|
||||||
@ -89,54 +93,54 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("errorMessage")
|
@discourseComputed("errorMessage")
|
||||||
nameValid(errorMessage) {
|
nameValid(errorMessage) {
|
||||||
return null === errorMessage;
|
return null === errorMessage;
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("name")
|
@observes("name")
|
||||||
uploadChanged() {
|
uploadChanged() {
|
||||||
const file = $("#file-input")[0];
|
const file = $("#file-input")[0];
|
||||||
this.set("fileSelected", file && file.files[0]);
|
this.set("fileSelected", file && file.files[0]);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
updateName() {
|
updateName() {
|
||||||
let name = this.name;
|
let name = this.name;
|
||||||
if (isEmpty(name)) {
|
if (isEmpty(name)) {
|
||||||
name = $("#file-input")[0].files[0].name;
|
name = $("#file-input")[0].files[0].name;
|
||||||
this.set("name", name.split(".")[0]);
|
this.set("name", name.split(".")[0]);
|
||||||
}
|
}
|
||||||
this.uploadChanged();
|
this.uploadChanged();
|
||||||
},
|
}
|
||||||
|
|
||||||
upload() {
|
@action
|
||||||
const file = $("#file-input")[0].files[0];
|
upload() {
|
||||||
|
const file = $("#file-input")[0].files[0];
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
processData: false,
|
processData: false,
|
||||||
contentType: false,
|
contentType: false,
|
||||||
data: new FormData(),
|
data: new FormData(),
|
||||||
};
|
};
|
||||||
|
|
||||||
options.data.append("file", file);
|
options.data.append("file", file);
|
||||||
|
|
||||||
ajax(this.uploadUrl, options)
|
ajax(this.uploadUrl, options)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
const upload = {
|
const upload = {
|
||||||
upload_id: result.upload_id,
|
upload_id: result.upload_id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
original_filename: file.name,
|
original_filename: file.name,
|
||||||
};
|
};
|
||||||
this.adminCustomizeThemesShow.send("addUpload", upload);
|
this.adminCustomizeThemesShow.send("addUpload", upload);
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
popupAjaxError(e);
|
popupAjaxError(e);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -4,39 +4,12 @@ import I18n from "I18n";
|
|||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { escapeExpression } from "discourse/lib/utilities";
|
import { escapeExpression } from "discourse/lib/utilities";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default class AdminBadgePreviewController extends Controller {
|
||||||
sample: alias("model.sample"),
|
@alias("model.sample") sample;
|
||||||
errors: alias("model.errors"),
|
@alias("model.errors") errors;
|
||||||
count: alias("model.grant_count"),
|
@alias("model.grant_count") count;
|
||||||
|
|
||||||
@discourseComputed("count", "sample.length")
|
@map("model.sample", (grant) => {
|
||||||
countWarning(count, sampleLength) {
|
|
||||||
if (count <= 10) {
|
|
||||||
return sampleLength !== count;
|
|
||||||
} else {
|
|
||||||
return sampleLength !== 10;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("model.query_plan")
|
|
||||||
hasQueryPlan(queryPlan) {
|
|
||||||
return !!queryPlan;
|
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("model.query_plan")
|
|
||||||
queryPlanHtml(queryPlan) {
|
|
||||||
let output = `<pre class="badge-query-plan">`;
|
|
||||||
|
|
||||||
queryPlan.forEach((linehash) => {
|
|
||||||
output += escapeExpression(linehash["QUERY PLAN"]);
|
|
||||||
output += "<br>";
|
|
||||||
});
|
|
||||||
|
|
||||||
output += "</pre>";
|
|
||||||
return output;
|
|
||||||
},
|
|
||||||
|
|
||||||
processedSample: map("model.sample", (grant) => {
|
|
||||||
let i18nKey = "admin.badges.preview.grant.with";
|
let i18nKey = "admin.badges.preview.grant.with";
|
||||||
const i18nParams = { username: escapeExpression(grant.username) };
|
const i18nParams = { username: escapeExpression(grant.username) };
|
||||||
|
|
||||||
@ -55,5 +28,33 @@ export default Controller.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return I18n.t(i18nKey, i18nParams);
|
return I18n.t(i18nKey, i18nParams);
|
||||||
}),
|
})
|
||||||
});
|
processedSample;
|
||||||
|
|
||||||
|
@discourseComputed("count", "sample.length")
|
||||||
|
countWarning(count, sampleLength) {
|
||||||
|
if (count <= 10) {
|
||||||
|
return sampleLength !== count;
|
||||||
|
} else {
|
||||||
|
return sampleLength !== 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("model.query_plan")
|
||||||
|
hasQueryPlan(queryPlan) {
|
||||||
|
return !!queryPlan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("model.query_plan")
|
||||||
|
queryPlanHtml(queryPlan) {
|
||||||
|
let output = `<pre class="badge-query-plan">`;
|
||||||
|
|
||||||
|
queryPlan.forEach((linehash) => {
|
||||||
|
output += escapeExpression(linehash["QUERY PLAN"]);
|
||||||
|
output += "<br>";
|
||||||
|
});
|
||||||
|
|
||||||
|
output += "</pre>";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,27 +1,29 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminColorSchemeSelectBaseController extends Controller.extend(
|
||||||
adminCustomizeColors: controller(),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
@controller adminCustomizeColors;
|
||||||
|
|
||||||
selectedBaseThemeId: null,
|
selectedBaseThemeId = null;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
const defaultScheme = this.get(
|
const defaultScheme = this.get(
|
||||||
"adminCustomizeColors.baseColorSchemes.0.base_scheme_id"
|
"adminCustomizeColors.baseColorSchemes.0.base_scheme_id"
|
||||||
);
|
);
|
||||||
this.set("selectedBaseThemeId", defaultScheme);
|
this.set("selectedBaseThemeId", defaultScheme);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
selectBase() {
|
selectBase() {
|
||||||
this.adminCustomizeColors.send(
|
this.adminCustomizeColors.send(
|
||||||
"newColorSchemeWithBase",
|
"newColorSchemeWithBase",
|
||||||
this.selectedBaseThemeId
|
this.selectedBaseThemeId
|
||||||
);
|
);
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminDeletePostsConfirmationController extends Controller.extend(
|
||||||
adminUserIndex: controller(),
|
ModalFunctionality
|
||||||
username: alias("model.username"),
|
) {
|
||||||
postCount: alias("model.post_count"),
|
@controller adminUserIndex;
|
||||||
|
|
||||||
|
@alias("model.username") username;
|
||||||
|
@alias("model.post_count") postCount;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.set("value", null);
|
this.set("value", null);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username", "postCount")
|
@discourseComputed("username", "postCount")
|
||||||
text(username, postCount) {
|
text(username, postCount) {
|
||||||
@ -20,27 +23,27 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
username,
|
username,
|
||||||
postCount,
|
postCount,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username")
|
@discourseComputed("username")
|
||||||
deleteButtonText(username) {
|
deleteButtonText(username) {
|
||||||
return I18n.t(`admin.user.delete_posts.confirmation.delete`, {
|
return I18n.t(`admin.user.delete_posts.confirmation.delete`, {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("value", "text")
|
@discourseComputed("value", "text")
|
||||||
deleteDisabled(value, text) {
|
deleteDisabled(value, text) {
|
||||||
return !value || text !== value;
|
return !value || text !== value;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
confirm() {
|
confirm() {
|
||||||
this.adminUserIndex.send("deleteAllPosts");
|
this.adminUserIndex.send("deleteAllPosts");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
close() {
|
close() {
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminDeleteUserPostsProgressController extends Controller.extend(
|
||||||
deletedPercentage: 0,
|
ModalFunctionality
|
||||||
});
|
) {
|
||||||
|
deletedPercentage = 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "discourse-common/utils/decorators";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminEditBadgeGroupingsController extends Controller.extend(
|
||||||
dialog: service(),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
@service dialog;
|
||||||
|
|
||||||
@observes("model")
|
@observes("model")
|
||||||
modelChanged() {
|
modelChanged() {
|
||||||
@ -22,7 +25,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.set("workingCopy", copy);
|
this.set("workingCopy", copy);
|
||||||
},
|
}
|
||||||
|
|
||||||
moveItem(item, delta) {
|
moveItem(item, delta) {
|
||||||
const copy = this.workingCopy;
|
const copy = this.workingCopy;
|
||||||
@ -33,55 +36,68 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
|
|
||||||
copy.removeAt(index);
|
copy.removeAt(index);
|
||||||
copy.insertAt(index + delta, item);
|
copy.insertAt(index + delta, item);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
up(item) {
|
up(item) {
|
||||||
this.moveItem(item, -1);
|
this.moveItem(item, -1);
|
||||||
},
|
}
|
||||||
down(item) {
|
|
||||||
this.moveItem(item, 1);
|
|
||||||
},
|
|
||||||
delete(item) {
|
|
||||||
this.workingCopy.removeObject(item);
|
|
||||||
},
|
|
||||||
cancel() {
|
|
||||||
this.setProperties({ model: null, workingCopy: null });
|
|
||||||
this.send("closeModal");
|
|
||||||
},
|
|
||||||
edit(item) {
|
|
||||||
item.set("editing", true);
|
|
||||||
},
|
|
||||||
save(item) {
|
|
||||||
item.set("editing", false);
|
|
||||||
},
|
|
||||||
add() {
|
|
||||||
const obj = this.store.createRecord("badge-grouping", {
|
|
||||||
editing: true,
|
|
||||||
name: I18n.t("admin.badges.badge_grouping"),
|
|
||||||
});
|
|
||||||
this.workingCopy.pushObject(obj);
|
|
||||||
},
|
|
||||||
saveAll() {
|
|
||||||
let items = this.workingCopy;
|
|
||||||
const groupIds = items.map((i) => i.get("id") || -1);
|
|
||||||
const names = items.map((i) => i.get("name"));
|
|
||||||
|
|
||||||
ajax("/admin/badges/badge_groupings", {
|
@action
|
||||||
data: { ids: groupIds, names },
|
down(item) {
|
||||||
type: "POST",
|
this.moveItem(item, 1);
|
||||||
}).then(
|
}
|
||||||
(data) => {
|
|
||||||
items = this.model;
|
@action
|
||||||
items.clear();
|
delete(item) {
|
||||||
data.badge_groupings.forEach((g) => {
|
this.workingCopy.removeObject(item);
|
||||||
items.pushObject(this.store.createRecord("badge-grouping", g));
|
}
|
||||||
});
|
|
||||||
this.setProperties({ model: null, workingCopy: null });
|
@action
|
||||||
this.send("closeModal");
|
cancel() {
|
||||||
},
|
this.setProperties({ model: null, workingCopy: null });
|
||||||
() => this.dialog.alert(I18n.t("generic_error"))
|
this.send("closeModal");
|
||||||
);
|
}
|
||||||
},
|
|
||||||
},
|
@action
|
||||||
});
|
edit(item) {
|
||||||
|
item.set("editing", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
save(item) {
|
||||||
|
item.set("editing", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
add() {
|
||||||
|
const obj = this.store.createRecord("badge-grouping", {
|
||||||
|
editing: true,
|
||||||
|
name: I18n.t("admin.badges.badge_grouping"),
|
||||||
|
});
|
||||||
|
this.workingCopy.pushObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
saveAll() {
|
||||||
|
let items = this.workingCopy;
|
||||||
|
const groupIds = items.map((i) => i.get("id") || -1);
|
||||||
|
const names = items.map((i) => i.get("name"));
|
||||||
|
|
||||||
|
ajax("/admin/badges/badge_groupings", {
|
||||||
|
data: { ids: groupIds, names },
|
||||||
|
type: "POST",
|
||||||
|
}).then(
|
||||||
|
(data) => {
|
||||||
|
items = this.model;
|
||||||
|
items.clear();
|
||||||
|
data.badge_groupings.forEach((g) => {
|
||||||
|
items.pushObject(this.store.createRecord("badge-grouping", g));
|
||||||
|
});
|
||||||
|
this.setProperties({ model: null, workingCopy: null });
|
||||||
|
this.send("closeModal");
|
||||||
|
},
|
||||||
|
() => this.dialog.alert(I18n.t("generic_error"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,15 +5,17 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||||||
import { longDate } from "discourse/lib/formatter";
|
import { longDate } from "discourse/lib/formatter";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminIncomingEmailController extends Controller.extend(
|
||||||
|
ModalFunctionality
|
||||||
|
) {
|
||||||
@discourseComputed("model.date")
|
@discourseComputed("model.date")
|
||||||
date(d) {
|
date(d) {
|
||||||
return longDate(d);
|
return longDate(d);
|
||||||
},
|
}
|
||||||
|
|
||||||
load(id) {
|
load(id) {
|
||||||
return IncomingEmail.find(id).then((result) => this.set("model", result));
|
return IncomingEmail.find(id).then((result) => this.set("model", result));
|
||||||
},
|
}
|
||||||
|
|
||||||
loadFromBounced(id) {
|
loadFromBounced(id) {
|
||||||
return IncomingEmail.findByBounced(id)
|
return IncomingEmail.findByBounced(id)
|
||||||
@ -22,5 +24,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
popupAjaxError(error);
|
popupAjaxError(error);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,46 +1,46 @@
|
|||||||
|
import { alias, equal, match } from "@ember/object/computed";
|
||||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import { alias, equal, match } from "@ember/object/computed";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { POPULAR_THEMES } from "discourse-common/helpers/popular-themes";
|
import { POPULAR_THEMES } from "discourse-common/helpers/popular-themes";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { set } from "@ember/object";
|
import { action, set } from "@ember/object";
|
||||||
|
|
||||||
const MIN_NAME_LENGTH = 4;
|
const MIN_NAME_LENGTH = 4;
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminInstallThemeController extends Controller.extend(
|
||||||
adminCustomizeThemes: controller(),
|
ModalFunctionality
|
||||||
themesController: controller("adminCustomizeThemes"),
|
) {
|
||||||
popular: equal("selection", "popular"),
|
@controller adminCustomizeThemes;
|
||||||
local: equal("selection", "local"),
|
@controller("adminCustomizeThemes") themesController;
|
||||||
remote: equal("selection", "remote"),
|
|
||||||
create: equal("selection", "create"),
|
|
||||||
directRepoInstall: equal("selection", "directRepoInstall"),
|
|
||||||
selection: "popular",
|
|
||||||
loading: false,
|
|
||||||
keyGenUrl: "/admin/themes/generate_key_pair",
|
|
||||||
importUrl: "/admin/themes/import",
|
|
||||||
recordType: "theme",
|
|
||||||
checkPrivate: match("uploadUrl", /^ssh:\/\/.+@.+$|.+@.+:.+$/),
|
|
||||||
localFile: null,
|
|
||||||
uploadUrl: null,
|
|
||||||
uploadName: null,
|
|
||||||
advancedVisible: false,
|
|
||||||
selectedType: alias("themesController.currentTab"),
|
|
||||||
component: equal("selectedType", COMPONENTS),
|
|
||||||
urlPlaceholder: "https://github.com/discourse/sample_theme",
|
|
||||||
|
|
||||||
init() {
|
@equal("selection", "popular") popular;
|
||||||
this._super(...arguments);
|
@equal("selection", "local") local;
|
||||||
|
@equal("selection", "remote") remote;
|
||||||
|
@equal("selection", "create") create;
|
||||||
|
@equal("selection", "directRepoInstall") directRepoInstall;
|
||||||
|
selection = "popular";
|
||||||
|
loading = false;
|
||||||
|
keyGenUrl = "/admin/themes/generate_key_pair";
|
||||||
|
importUrl = "/admin/themes/import";
|
||||||
|
recordType = "theme";
|
||||||
|
@match("uploadUrl", /^ssh:\/\/.+@.+$|.+@.+:.+$/) checkPrivate;
|
||||||
|
localFile = null;
|
||||||
|
uploadUrl = null;
|
||||||
|
uploadName = null;
|
||||||
|
advancedVisible = false;
|
||||||
|
@alias("themesController.currentTab") selectedType;
|
||||||
|
@equal("selectedType", COMPONENTS) component;
|
||||||
|
urlPlaceholder = "https://github.com/discourse/sample_theme";
|
||||||
|
|
||||||
this.createTypes = [
|
createTypes = [
|
||||||
{ name: I18n.t("admin.customize.theme.theme"), value: THEMES },
|
{ name: I18n.t("admin.customize.theme.theme"), value: THEMES },
|
||||||
{ name: I18n.t("admin.customize.theme.component"), value: COMPONENTS },
|
{ name: I18n.t("admin.customize.theme.component"), value: COMPONENTS },
|
||||||
];
|
];
|
||||||
},
|
|
||||||
|
|
||||||
@discourseComputed("themesController.installedThemes")
|
@discourseComputed("themesController.installedThemes")
|
||||||
themes(installedThemes) {
|
themes(installedThemes) {
|
||||||
@ -52,7 +52,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"loading",
|
"loading",
|
||||||
@ -78,12 +78,12 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
(isLocal && !localFile) ||
|
(isLocal && !localFile) ||
|
||||||
(isCreate && nameTooShort)
|
(isCreate && nameTooShort)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("name")
|
@discourseComputed("name")
|
||||||
nameTooShort(name) {
|
nameTooShort(name) {
|
||||||
return !name || name.length < MIN_NAME_LENGTH;
|
return !name || name.length < MIN_NAME_LENGTH;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("component")
|
@discourseComputed("component")
|
||||||
placeholder(component) {
|
placeholder(component) {
|
||||||
@ -92,7 +92,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} else {
|
} else {
|
||||||
return I18n.t("admin.customize.theme.theme_name");
|
return I18n.t("admin.customize.theme.theme_name");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("checkPrivate")
|
@observes("checkPrivate")
|
||||||
privateWasChecked() {
|
privateWasChecked() {
|
||||||
@ -108,7 +108,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
this._keyLoading = false;
|
this._keyLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("selection", "themeCannotBeInstalled")
|
@discourseComputed("selection", "themeCannotBeInstalled")
|
||||||
submitLabel(selection, themeCannotBeInstalled) {
|
submitLabel(selection, themeCannotBeInstalled) {
|
||||||
@ -119,12 +119,12 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
return `admin.customize.theme.${
|
return `admin.customize.theme.${
|
||||||
selection === "create" ? "create" : "install"
|
selection === "create" ? "create" : "install"
|
||||||
}`;
|
}`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("checkPrivate", "publicKey")
|
@discourseComputed("checkPrivate", "publicKey")
|
||||||
showPublicKey(checkPrivate, publicKey) {
|
showPublicKey(checkPrivate, publicKey) {
|
||||||
return checkPrivate && publicKey;
|
return checkPrivate && publicKey;
|
||||||
},
|
}
|
||||||
|
|
||||||
onClose() {
|
onClose() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
@ -140,7 +140,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
repoName: null,
|
repoName: null,
|
||||||
repoUrl: null,
|
repoUrl: null,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
themeHasSameUrl(theme, url) {
|
themeHasSameUrl(theme, url) {
|
||||||
const themeUrl = theme.remote_theme && theme.remote_theme.remote_url;
|
const themeUrl = theme.remote_theme && theme.remote_theme.remote_url;
|
||||||
@ -149,100 +149,101 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
url &&
|
url &&
|
||||||
url.replace(/\.git$/, "") === themeUrl.replace(/\.git$/, "")
|
url.replace(/\.git$/, "") === themeUrl.replace(/\.git$/, "")
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
uploadLocaleFile() {
|
uploadLocaleFile() {
|
||||||
this.set("localFile", $("#file-input")[0].files[0]);
|
this.set("localFile", $("#file-input")[0].files[0]);
|
||||||
},
|
}
|
||||||
|
|
||||||
toggleAdvanced() {
|
@action
|
||||||
this.toggleProperty("advancedVisible");
|
toggleAdvanced() {
|
||||||
},
|
this.toggleProperty("advancedVisible");
|
||||||
|
}
|
||||||
|
|
||||||
installThemeFromList(url) {
|
@action
|
||||||
this.set("uploadUrl", url);
|
installThemeFromList(url) {
|
||||||
this.send("installTheme");
|
this.set("uploadUrl", url);
|
||||||
},
|
this.send("installTheme");
|
||||||
|
}
|
||||||
installTheme() {
|
|
||||||
if (this.create) {
|
|
||||||
this.set("loading", true);
|
|
||||||
const theme = this.store.createRecord(this.recordType);
|
|
||||||
theme
|
|
||||||
.save({ name: this.name, component: this.component })
|
|
||||||
.then(() => {
|
|
||||||
this.themesController.send("addTheme", theme);
|
|
||||||
this.send("closeModal");
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(() => this.set("loading", false));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
type: "POST",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.local) {
|
|
||||||
options.processData = false;
|
|
||||||
options.contentType = false;
|
|
||||||
options.data = new FormData();
|
|
||||||
options.data.append("theme", this.localFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.remote || this.popular || this.directRepoInstall) {
|
|
||||||
const duplicate = this.themesController.model.content.find((theme) =>
|
|
||||||
this.themeHasSameUrl(theme, this.uploadUrl)
|
|
||||||
);
|
|
||||||
if (duplicate && !this.duplicateRemoteThemeWarning) {
|
|
||||||
const warning = I18n.t(
|
|
||||||
"admin.customize.theme.duplicate_remote_theme",
|
|
||||||
{ name: duplicate.name }
|
|
||||||
);
|
|
||||||
this.set("duplicateRemoteThemeWarning", warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
options.data = {
|
|
||||||
remote: this.uploadUrl,
|
|
||||||
branch: this.branch,
|
|
||||||
public_key: this.publicKey,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// User knows that theme cannot be installed, but they want to continue
|
|
||||||
// to force install it.
|
|
||||||
if (this.themeCannotBeInstalled) {
|
|
||||||
options.data["force"] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.get("model.user_id")) {
|
|
||||||
// Used by theme-creator
|
|
||||||
options.data["user_id"] = this.get("model.user_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@action
|
||||||
|
installTheme() {
|
||||||
|
if (this.create) {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
ajax(this.importUrl, options)
|
const theme = this.store.createRecord(this.recordType);
|
||||||
.then((result) => {
|
theme
|
||||||
const theme = this.store.createRecord(this.recordType, result.theme);
|
.save({ name: this.name, component: this.component })
|
||||||
this.adminCustomizeThemes.send("addTheme", theme);
|
.then(() => {
|
||||||
|
this.themesController.send("addTheme", theme);
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
})
|
})
|
||||||
.then(() => {
|
.catch(popupAjaxError)
|
||||||
this.set("publicKey", null);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
if (!this.publicKey || this.themeCannotBeInstalled) {
|
|
||||||
return popupAjaxError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set(
|
|
||||||
"themeCannotBeInstalled",
|
|
||||||
I18n.t("admin.customize.theme.force_install")
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.finally(() => this.set("loading", false));
|
.finally(() => this.set("loading", false));
|
||||||
},
|
|
||||||
},
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
let options = {
|
||||||
|
type: "POST",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.local) {
|
||||||
|
options.processData = false;
|
||||||
|
options.contentType = false;
|
||||||
|
options.data = new FormData();
|
||||||
|
options.data.append("theme", this.localFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.remote || this.popular || this.directRepoInstall) {
|
||||||
|
const duplicate = this.themesController.model.content.find((theme) =>
|
||||||
|
this.themeHasSameUrl(theme, this.uploadUrl)
|
||||||
|
);
|
||||||
|
if (duplicate && !this.duplicateRemoteThemeWarning) {
|
||||||
|
const warning = I18n.t("admin.customize.theme.duplicate_remote_theme", {
|
||||||
|
name: duplicate.name,
|
||||||
|
});
|
||||||
|
this.set("duplicateRemoteThemeWarning", warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
options.data = {
|
||||||
|
remote: this.uploadUrl,
|
||||||
|
branch: this.branch,
|
||||||
|
public_key: this.publicKey,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// User knows that theme cannot be installed, but they want to continue
|
||||||
|
// to force install it.
|
||||||
|
if (this.themeCannotBeInstalled) {
|
||||||
|
options.data["force"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.get("model.user_id")) {
|
||||||
|
// Used by theme-creator
|
||||||
|
options.data["user_id"] = this.get("model.user_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set("loading", true);
|
||||||
|
ajax(this.importUrl, options)
|
||||||
|
.then((result) => {
|
||||||
|
const theme = this.store.createRecord(this.recordType, result.theme);
|
||||||
|
this.adminCustomizeThemes.send("addTheme", theme);
|
||||||
|
this.send("closeModal");
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.set("publicKey", null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (!this.publicKey || this.themeCannotBeInstalled) {
|
||||||
|
return popupAjaxError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set(
|
||||||
|
"themeCannotBeInstalled",
|
||||||
|
I18n.t("admin.customize.theme.force_install")
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.finally(() => this.set("loading", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminMergeUsersConfirmationController extends Controller.extend(
|
||||||
adminUserIndex: controller(),
|
ModalFunctionality
|
||||||
username: alias("model.username"),
|
) {
|
||||||
targetUsername: alias("model.targetUsername"),
|
@controller adminUserIndex;
|
||||||
|
|
||||||
|
@alias("model.username") username;
|
||||||
|
@alias("model.targetUsername") targetUsername;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.set("value", null);
|
this.set("value", null);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username", "targetUsername")
|
@discourseComputed("username", "targetUsername")
|
||||||
text(username, targetUsername) {
|
text(username, targetUsername) {
|
||||||
@ -20,28 +23,28 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
username,
|
username,
|
||||||
targetUsername,
|
targetUsername,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username")
|
@discourseComputed("username")
|
||||||
mergeButtonText(username) {
|
mergeButtonText(username) {
|
||||||
return I18n.t(`admin.user.merge.confirmation.transfer_and_delete`, {
|
return I18n.t(`admin.user.merge.confirmation.transfer_and_delete`, {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("value", "text")
|
@discourseComputed("value", "text")
|
||||||
mergeDisabled(value, text) {
|
mergeDisabled(value, text) {
|
||||||
return !value || text !== value;
|
return !value || text !== value;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
confirm() {
|
confirm() {
|
||||||
this.adminUserIndex.send("merge", this.targetUsername);
|
this.adminUserIndex.send("merge", this.targetUsername);
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
close() {
|
close() {
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -4,16 +4,18 @@ import I18n from "I18n";
|
|||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminMergeUsersProgressController extends Controller.extend(
|
||||||
message: I18n.t("admin.user.merging_user"),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
message = I18n.t("admin.user.merging_user");
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.messageBus.subscribe("/merge_user", this.onMessage);
|
this.messageBus.subscribe("/merge_user", this.onMessage);
|
||||||
},
|
}
|
||||||
|
|
||||||
onClose() {
|
onClose() {
|
||||||
this.messageBus.unsubscribe("/merge_user", this.onMessage);
|
this.messageBus.unsubscribe("/merge_user", this.onMessage);
|
||||||
},
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
onMessage(data) {
|
onMessage(data) {
|
||||||
@ -30,5 +32,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} else if (data.failed) {
|
} else if (data.failed) {
|
||||||
this.set("message", I18n.t("admin.user.merge_failed"));
|
this.set("message", I18n.t("admin.user.merge_failed"));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,43 +1,46 @@
|
|||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { action, get } from "@ember/object";
|
import { action, get } from "@ember/object";
|
||||||
import { alias } from "@ember/object/computed";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminMergeUsersPromptController extends Controller.extend(
|
||||||
adminUserIndex: controller(),
|
ModalFunctionality
|
||||||
username: alias("model.username"),
|
) {
|
||||||
|
@controller adminUserIndex;
|
||||||
|
|
||||||
|
@alias("model.username") username;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.set("targetUsername", null);
|
this.set("targetUsername", null);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username", "targetUsername")
|
@discourseComputed("username", "targetUsername")
|
||||||
mergeDisabled(username, targetUsername) {
|
mergeDisabled(username, targetUsername) {
|
||||||
return !targetUsername || username === targetUsername;
|
return !targetUsername || username === targetUsername;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username")
|
@discourseComputed("username")
|
||||||
mergeButtonText(username) {
|
mergeButtonText(username) {
|
||||||
return I18n.t(`admin.user.merge.confirmation.transfer_and_delete`, {
|
return I18n.t(`admin.user.merge.confirmation.transfer_and_delete`, {
|
||||||
username,
|
username,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showConfirmation() {
|
showConfirmation() {
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
this.adminUserIndex.send("showMergeConfirmation", this.targetUsername);
|
this.adminUserIndex.send("showMergeConfirmation", this.targetUsername);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
close() {
|
close() {
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateUsername(selected) {
|
updateUsername(selected) {
|
||||||
this.set("targetUsername", get(selected, "firstObject"));
|
this.set("targetUsername", get(selected, "firstObject"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,29 +1,31 @@
|
|||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { extractError } from "discourse/lib/ajax-error";
|
import { extractError } from "discourse/lib/ajax-error";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminPenalizeUserController extends Controller.extend(
|
||||||
dialog: service(),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
@service dialog;
|
||||||
|
|
||||||
loadingUser: false,
|
loadingUser = false;
|
||||||
errorMessage: null,
|
errorMessage = null;
|
||||||
penaltyType: null,
|
penaltyType = null;
|
||||||
penalizeUntil: null,
|
penalizeUntil = null;
|
||||||
reason: null,
|
reason = null;
|
||||||
message: null,
|
message = null;
|
||||||
postId: null,
|
postId = null;
|
||||||
postAction: null,
|
postAction = null;
|
||||||
postEdit: null,
|
postEdit = null;
|
||||||
user: null,
|
user = null;
|
||||||
otherUserIds: null,
|
otherUserIds = null;
|
||||||
loading: false,
|
loading = false;
|
||||||
confirmClose: false,
|
confirmClose = false;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
@ -44,11 +46,11 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
message: null,
|
message: null,
|
||||||
confirmClose: false,
|
confirmClose: false,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
finishedSetup() {
|
finishedSetup() {
|
||||||
this.set("penalizeUntil", this.user?.next_penalty);
|
this.set("penalizeUntil", this.user?.next_penalty);
|
||||||
},
|
}
|
||||||
|
|
||||||
beforeClose() {
|
beforeClose() {
|
||||||
if (this.confirmClose) {
|
if (this.confirmClose) {
|
||||||
@ -73,7 +75,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("penaltyType")
|
@discourseComputed("penaltyType")
|
||||||
modalTitle(penaltyType) {
|
modalTitle(penaltyType) {
|
||||||
@ -82,7 +84,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} else if (penaltyType === "silence") {
|
} else if (penaltyType === "silence") {
|
||||||
return "admin.user.silence_modal_title";
|
return "admin.user.silence_modal_title";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("penaltyType")
|
@discourseComputed("penaltyType")
|
||||||
buttonLabel(penaltyType) {
|
buttonLabel(penaltyType) {
|
||||||
@ -91,7 +93,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} else if (penaltyType === "silence") {
|
} else if (penaltyType === "silence") {
|
||||||
return "admin.user.silence";
|
return "admin.user.silence";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"user.penalty_counts.suspended",
|
"user.penalty_counts.suspended",
|
||||||
@ -102,7 +104,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
SUSPENDED: suspendedCount,
|
SUSPENDED: suspendedCount,
|
||||||
SILENCED: silencedCount,
|
SILENCED: silencedCount,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("penaltyType", "user.canSuspend", "user.canSilence")
|
@discourseComputed("penaltyType", "user.canSuspend", "user.canSilence")
|
||||||
canPenalize(penaltyType, canSuspend, canSilence) {
|
canPenalize(penaltyType, canSuspend, canSilence) {
|
||||||
@ -113,12 +115,12 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("penalizing", "penalizeUntil", "reason")
|
@discourseComputed("penalizing", "penalizeUntil", "reason")
|
||||||
submitDisabled(penalizing, penalizeUntil, reason) {
|
submitDisabled(penalizing, penalizeUntil, reason) {
|
||||||
return penalizing || isEmpty(penalizeUntil) || !reason || reason.length < 1;
|
return penalizing || isEmpty(penalizeUntil) || !reason || reason.length < 1;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async penalizeUser() {
|
async penalizeUser() {
|
||||||
@ -164,5 +166,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
} finally {
|
} finally {
|
||||||
this.set("penalizing", false);
|
this.set("penalizing", false);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminReseedController extends Controller.extend(
|
||||||
dialog: service(),
|
ModalFunctionality
|
||||||
loading: true,
|
) {
|
||||||
reseeding: false,
|
@service dialog;
|
||||||
categories: null,
|
|
||||||
topics: null,
|
loading = true;
|
||||||
|
reseeding = false;
|
||||||
|
categories = null;
|
||||||
|
topics = null;
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
ajax("/admin/customize/reseed")
|
ajax("/admin/customize/reseed")
|
||||||
@ -20,27 +24,26 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.finally(() => this.set("loading", false));
|
.finally(() => this.set("loading", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
_extractSelectedIds(items) {
|
_extractSelectedIds(items) {
|
||||||
return items.filter((item) => item.selected).map((item) => item.id);
|
return items.filter((item) => item.selected).map((item) => item.id);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
reseed() {
|
reseed() {
|
||||||
this.set("reseeding", true);
|
this.set("reseeding", true);
|
||||||
ajax("/admin/customize/reseed", {
|
ajax("/admin/customize/reseed", {
|
||||||
data: {
|
data: {
|
||||||
category_ids: this._extractSelectedIds(this.categories),
|
category_ids: this._extractSelectedIds(this.categories),
|
||||||
topic_ids: this._extractSelectedIds(this.topics),
|
topic_ids: this._extractSelectedIds(this.topics),
|
||||||
},
|
},
|
||||||
type: "POST",
|
type: "POST",
|
||||||
})
|
})
|
||||||
.catch(() => this.dialog.alert(I18n.t("generic_error")))
|
.catch(() => this.dialog.alert(I18n.t("generic_error")))
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.set("reseeding", false);
|
this.set("reseeding", false);
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality);
|
export default class AdminStaffActionLogDetailsController extends Controller.extend(
|
||||||
|
ModalFunctionality
|
||||||
|
) {}
|
||||||
|
|||||||
@ -1,35 +1,39 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Controller, { inject as controller } from "@ember/controller";
|
import Controller, { inject as controller } from "@ember/controller";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminStartBackupController extends Controller.extend(
|
||||||
adminBackupsLogs: controller(),
|
ModalFunctionality
|
||||||
|
) {
|
||||||
|
@controller adminBackupsLogs;
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
warningMessage() {
|
warningMessage() {
|
||||||
// this is never shown here, but we may want to show different
|
// this is never shown here, but we may want to show different
|
||||||
// messages in plugins
|
// messages in plugins
|
||||||
return "";
|
return "";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
yesLabel() {
|
yesLabel() {
|
||||||
return "yes_value";
|
return "yes_value";
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
startBackupWithUploads() {
|
startBackupWithUploads() {
|
||||||
this.send("closeModal");
|
this.send("closeModal");
|
||||||
this.send("startBackup", true);
|
this.send("startBackup", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
startBackupWithoutUploads() {
|
@action
|
||||||
this.send("closeModal");
|
startBackupWithoutUploads() {
|
||||||
this.send("startBackup", false);
|
this.send("closeModal");
|
||||||
},
|
this.send("startBackup", false);
|
||||||
|
}
|
||||||
|
|
||||||
cancel() {
|
@action
|
||||||
this.send("closeModal");
|
cancel() {
|
||||||
},
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,7 +2,9 @@ import Controller from "@ember/controller";
|
|||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminThemeChangeController extends Controller.extend(
|
||||||
|
ModalFunctionality
|
||||||
|
) {
|
||||||
loadDiff() {
|
loadDiff() {
|
||||||
this.set("loading", true);
|
this.set("loading", true);
|
||||||
ajax(
|
ajax(
|
||||||
@ -11,5 +13,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
this.set("loading", false);
|
this.set("loading", false);
|
||||||
this.set("diff", diff.side_by_side);
|
this.set("diff", diff.side_by_side);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,30 +1,32 @@
|
|||||||
import { observes, on } from "discourse-common/utils/decorators";
|
import { observes, on } from "@ember-decorators/object";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminUploadedImageListController extends Controller.extend(
|
||||||
|
ModalFunctionality
|
||||||
|
) {
|
||||||
@on("init")
|
@on("init")
|
||||||
@observes("model.value")
|
@observes("model.value")
|
||||||
_setup() {
|
_setup() {
|
||||||
const value = this.get("model.value");
|
const value = this.get("model.value");
|
||||||
this.set("images", value && value.length ? value.split("|") : []);
|
this.set("images", value && value.length ? value.split("|") : []);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
remove(url, event) {
|
remove(url, event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.images.removeObject(url);
|
this.images.removeObject(url);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
uploadDone({ url }) {
|
uploadDone({ url }) {
|
||||||
this.images.addObject(url);
|
this.images.addObject(url);
|
||||||
},
|
}
|
||||||
|
|
||||||
close() {
|
@action
|
||||||
this.save(this.images.join("|"));
|
close() {
|
||||||
this.send("closeModal");
|
this.save(this.images.join("|"));
|
||||||
},
|
this.send("closeModal");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
|
import { equal } from "@ember/object/computed";
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { equal } from "@ember/object/computed";
|
|
||||||
import {
|
import {
|
||||||
createWatchedWordRegExp,
|
createWatchedWordRegExp,
|
||||||
toWatchedWord,
|
toWatchedWord,
|
||||||
} from "discourse-common/utils/watched-words";
|
} from "discourse-common/utils/watched-words";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
export default class AdminWatchedWordTestController extends Controller.extend(
|
||||||
isReplace: equal("model.nameKey", "replace"),
|
ModalFunctionality
|
||||||
isTag: equal("model.nameKey", "tag"),
|
) {
|
||||||
isLink: equal("model.nameKey", "link"),
|
@equal("model.nameKey", "replace") isReplace;
|
||||||
|
|
||||||
|
@equal("model.nameKey", "tag") isTag;
|
||||||
|
@equal("model.nameKey", "link") isLink;
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"value",
|
"value",
|
||||||
@ -71,5 +74,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,4 +2,7 @@ import Controller from "@ember/controller";
|
|||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||||
import ModalUpdateExistingUsers from "discourse/mixins/modal-update-existing-users";
|
import ModalUpdateExistingUsers from "discourse/mixins/modal-update-existing-users";
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, ModalUpdateExistingUsers);
|
export default class SiteSettingDefaultCategoriesController extends Controller.extend(
|
||||||
|
ModalFunctionality,
|
||||||
|
ModalUpdateExistingUsers
|
||||||
|
) {}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import Helper from "@ember/component/helper";
|
|||||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||||
import { htmlSafe } from "@ember/template";
|
import { htmlSafe } from "@ember/template";
|
||||||
|
|
||||||
export default Helper.extend({
|
export default class DispositionIcon extends Helper {
|
||||||
compute([disposition]) {
|
compute([disposition]) {
|
||||||
if (!disposition) {
|
if (!disposition) {
|
||||||
return null;
|
return null;
|
||||||
@ -24,5 +24,5 @@ export default Helper.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return htmlSafe(iconHTML(icon, { title }));
|
return htmlSafe(iconHTML(icon, { title }));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -7,19 +7,17 @@ const GENERAL_ATTRIBUTES = [
|
|||||||
"release_notes_link",
|
"release_notes_link",
|
||||||
];
|
];
|
||||||
|
|
||||||
const AdminDashboard = EmberObject.extend({});
|
export default class AdminDashboard extends EmberObject {
|
||||||
|
static fetch() {
|
||||||
AdminDashboard.reopenClass({
|
|
||||||
fetch() {
|
|
||||||
return ajax("/admin/dashboard.json").then((json) => {
|
return ajax("/admin/dashboard.json").then((json) => {
|
||||||
const model = AdminDashboard.create();
|
const model = AdminDashboard.create();
|
||||||
model.set("version_check", json.version_check);
|
model.set("version_check", json.version_check);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
fetchGeneral() {
|
static fetchGeneral() {
|
||||||
return ajax("/admin/dashboard/general.json").then((json) => {
|
return ajax("/admin/dashboard/general.json").then((json) => {
|
||||||
const model = AdminDashboard.create();
|
const model = AdminDashboard.create();
|
||||||
|
|
||||||
@ -34,15 +32,13 @@ AdminDashboard.reopenClass({
|
|||||||
|
|
||||||
return model;
|
return model;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
fetchProblems() {
|
static fetchProblems() {
|
||||||
return ajax("/admin/dashboard/problems.json").then((json) => {
|
return ajax("/admin/dashboard/problems.json").then((json) => {
|
||||||
const model = AdminDashboard.create(json);
|
const model = AdminDashboard.create(json);
|
||||||
model.set("loaded", true);
|
model.set("loaded", true);
|
||||||
return model;
|
return model;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default AdminDashboard;
|
|
||||||
|
|||||||
@ -10,14 +10,30 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
|||||||
import { propertyNotEqual } from "discourse/lib/computed";
|
import { propertyNotEqual } from "discourse/lib/computed";
|
||||||
import { userPath } from "discourse/lib/url";
|
import { userPath } from "discourse/lib/url";
|
||||||
|
|
||||||
const wrapAdmin = (user) => (user ? AdminUser.create(user) : null);
|
export default class AdminUser extends User {
|
||||||
|
static find(user_id) {
|
||||||
|
return ajax(`/admin/users/${user_id}.json`).then((result) => {
|
||||||
|
result.loadedDetails = true;
|
||||||
|
return AdminUser.create(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const AdminUser = User.extend({
|
static findAll(query, userFilter) {
|
||||||
adminUserView: true,
|
return ajax(`/admin/users/list/${query}.json`, {
|
||||||
customGroups: filter("groups", (g) => !g.automatic && Group.create(g)),
|
data: userFilter,
|
||||||
automaticGroups: filter("groups", (g) => g.automatic && Group.create(g)),
|
}).then((users) => users.map((u) => AdminUser.create(u)));
|
||||||
|
}
|
||||||
|
|
||||||
canViewProfile: or("active", "staged"),
|
adminUserView = true;
|
||||||
|
|
||||||
|
@filter("groups", (g) => !g.automatic && Group.create(g)) customGroups;
|
||||||
|
@filter("groups", (g) => g.automatic && Group.create(g)) automaticGroups;
|
||||||
|
@or("active", "staged") canViewProfile;
|
||||||
|
@gt("bounce_score", 0) canResetBounceScore;
|
||||||
|
@propertyNotEqual("originalTrustLevel", "trust_level") dirty;
|
||||||
|
@lt("trust_level", 4) canLockTrustLevel;
|
||||||
|
@not("staff") canSuspend;
|
||||||
|
@not("staff") canSilence;
|
||||||
|
|
||||||
@discourseComputed("bounce_score", "reset_bounce_score_after")
|
@discourseComputed("bounce_score", "reset_bounce_score_after")
|
||||||
bounceScore(bounce_score, reset_bounce_score_after) {
|
bounceScore(bounce_score, reset_bounce_score_after) {
|
||||||
@ -28,7 +44,7 @@ const AdminUser = User.extend({
|
|||||||
} else {
|
} else {
|
||||||
return bounce_score;
|
return bounce_score;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("bounce_score")
|
@discourseComputed("bounce_score")
|
||||||
bounceScoreExplanation(bounce_score) {
|
bounceScoreExplanation(bounce_score) {
|
||||||
@ -39,14 +55,12 @@ const AdminUser = User.extend({
|
|||||||
} else {
|
} else {
|
||||||
return I18n.t("admin.user.bounce_score_explanation.threshold_reached");
|
return I18n.t("admin.user.bounce_score_explanation.threshold_reached");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
bounceLink() {
|
bounceLink() {
|
||||||
return getURL("/admin/email/bounced");
|
return getURL("/admin/email/bounced");
|
||||||
},
|
}
|
||||||
|
|
||||||
canResetBounceScore: gt("bounce_score", 0),
|
|
||||||
|
|
||||||
resetBounceScore() {
|
resetBounceScore() {
|
||||||
return ajax(`/admin/users/${this.id}/reset_bounce_score`, {
|
return ajax(`/admin/users/${this.id}/reset_bounce_score`, {
|
||||||
@ -57,14 +71,14 @@ const AdminUser = User.extend({
|
|||||||
reset_bounce_score_after: null,
|
reset_bounce_score_after: null,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
groupAdded(added) {
|
groupAdded(added) {
|
||||||
return ajax(`/admin/users/${this.id}/groups`, {
|
return ajax(`/admin/users/${this.id}/groups`, {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { group_id: added.id },
|
data: { group_id: added.id },
|
||||||
}).then(() => this.groups.pushObject(added));
|
}).then(() => this.groups.pushObject(added));
|
||||||
},
|
}
|
||||||
|
|
||||||
groupRemoved(groupId) {
|
groupRemoved(groupId) {
|
||||||
return ajax(`/admin/users/${this.id}/groups/${groupId}`, {
|
return ajax(`/admin/users/${this.id}/groups/${groupId}`, {
|
||||||
@ -75,13 +89,13 @@ const AdminUser = User.extend({
|
|||||||
this.set("primary_group_id", null);
|
this.set("primary_group_id", null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
deleteAllPosts() {
|
deleteAllPosts() {
|
||||||
return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, {
|
return ajax(`/admin/users/${this.get("id")}/delete_posts_batch`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
revokeAdmin() {
|
revokeAdmin() {
|
||||||
return ajax(`/admin/users/${this.id}/revoke_admin`, {
|
return ajax(`/admin/users/${this.id}/revoke_admin`, {
|
||||||
@ -97,7 +111,7 @@ const AdminUser = User.extend({
|
|||||||
can_delete_all_posts: resp.can_delete_all_posts,
|
can_delete_all_posts: resp.can_delete_all_posts,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
grantAdmin(data) {
|
grantAdmin(data) {
|
||||||
return ajax(`/admin/users/${this.id}/grant_admin`, {
|
return ajax(`/admin/users/${this.id}/grant_admin`, {
|
||||||
@ -114,7 +128,7 @@ const AdminUser = User.extend({
|
|||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
revokeModeration() {
|
revokeModeration() {
|
||||||
return ajax(`/admin/users/${this.id}/revoke_moderation`, {
|
return ajax(`/admin/users/${this.id}/revoke_moderation`, {
|
||||||
@ -130,7 +144,7 @@ const AdminUser = User.extend({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
grantModeration() {
|
grantModeration() {
|
||||||
return ajax(`/admin/users/${this.id}/grant_moderation`, {
|
return ajax(`/admin/users/${this.id}/grant_moderation`, {
|
||||||
@ -146,7 +160,7 @@ const AdminUser = User.extend({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
disableSecondFactor() {
|
disableSecondFactor() {
|
||||||
return ajax(`/admin/users/${this.id}/disable_second_factor`, {
|
return ajax(`/admin/users/${this.id}/disable_second_factor`, {
|
||||||
@ -156,7 +170,7 @@ const AdminUser = User.extend({
|
|||||||
this.set("second_factor_enabled", false);
|
this.set("second_factor_enabled", false);
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
|
|
||||||
approve(approvedBy) {
|
approve(approvedBy) {
|
||||||
return ajax(`/admin/users/${this.id}/approve`, {
|
return ajax(`/admin/users/${this.id}/approve`, {
|
||||||
@ -168,83 +182,76 @@ const AdminUser = User.extend({
|
|||||||
approved_by: approvedBy,
|
approved_by: approvedBy,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
setOriginalTrustLevel() {
|
setOriginalTrustLevel() {
|
||||||
this.set("originalTrustLevel", this.trust_level);
|
this.set("originalTrustLevel", this.trust_level);
|
||||||
},
|
}
|
||||||
|
|
||||||
dirty: propertyNotEqual("originalTrustLevel", "trust_level"),
|
|
||||||
|
|
||||||
saveTrustLevel() {
|
saveTrustLevel() {
|
||||||
return ajax(`/admin/users/${this.id}/trust_level`, {
|
return ajax(`/admin/users/${this.id}/trust_level`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { level: this.trust_level },
|
data: { level: this.trust_level },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
restoreTrustLevel() {
|
restoreTrustLevel() {
|
||||||
this.set("trust_level", this.originalTrustLevel);
|
this.set("trust_level", this.originalTrustLevel);
|
||||||
},
|
}
|
||||||
|
|
||||||
lockTrustLevel(locked) {
|
lockTrustLevel(locked) {
|
||||||
return ajax(`/admin/users/${this.id}/trust_level_lock`, {
|
return ajax(`/admin/users/${this.id}/trust_level_lock`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { locked: !!locked },
|
data: { locked: !!locked },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
canLockTrustLevel: lt("trust_level", 4),
|
|
||||||
|
|
||||||
canSuspend: not("staff"),
|
|
||||||
canSilence: not("staff"),
|
|
||||||
|
|
||||||
@discourseComputed("suspended_till", "suspended_at")
|
@discourseComputed("suspended_till", "suspended_at")
|
||||||
suspendDuration(suspendedTill, suspendedAt) {
|
suspendDuration(suspendedTill, suspendedAt) {
|
||||||
suspendedAt = moment(suspendedAt);
|
suspendedAt = moment(suspendedAt);
|
||||||
suspendedTill = moment(suspendedTill);
|
suspendedTill = moment(suspendedTill);
|
||||||
return suspendedAt.format("L") + " - " + suspendedTill.format("L");
|
return suspendedAt.format("L") + " - " + suspendedTill.format("L");
|
||||||
},
|
}
|
||||||
|
|
||||||
suspend(data) {
|
suspend(data) {
|
||||||
return ajax(`/admin/users/${this.id}/suspend`, {
|
return ajax(`/admin/users/${this.id}/suspend`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data,
|
data,
|
||||||
}).then((result) => this.setProperties(result.suspension));
|
}).then((result) => this.setProperties(result.suspension));
|
||||||
},
|
}
|
||||||
|
|
||||||
unsuspend() {
|
unsuspend() {
|
||||||
return ajax(`/admin/users/${this.id}/unsuspend`, {
|
return ajax(`/admin/users/${this.id}/unsuspend`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
}).then((result) => this.setProperties(result.suspension));
|
}).then((result) => this.setProperties(result.suspension));
|
||||||
},
|
}
|
||||||
|
|
||||||
logOut() {
|
logOut() {
|
||||||
return ajax("/admin/users/" + this.id + "/log_out", {
|
return ajax("/admin/users/" + this.id + "/log_out", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { username_or_email: this.username },
|
data: { username_or_email: this.username },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
impersonate() {
|
impersonate() {
|
||||||
return ajax("/admin/impersonate", {
|
return ajax("/admin/impersonate", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { username_or_email: this.username },
|
data: { username_or_email: this.username },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
return ajax(`/admin/users/${this.id}/activate`, {
|
return ajax(`/admin/users/${this.id}/activate`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
return ajax(`/admin/users/${this.id}/deactivate`, {
|
return ajax(`/admin/users/${this.id}/deactivate`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { context: document.location.pathname },
|
data: { context: document.location.pathname },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
unsilence() {
|
unsilence() {
|
||||||
this.set("silencingUser", true);
|
this.set("silencingUser", true);
|
||||||
@ -254,7 +261,7 @@ const AdminUser = User.extend({
|
|||||||
})
|
})
|
||||||
.then((result) => this.setProperties(result.unsilence))
|
.then((result) => this.setProperties(result.unsilence))
|
||||||
.finally(() => this.set("silencingUser", false));
|
.finally(() => this.set("silencingUser", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
silence(data) {
|
silence(data) {
|
||||||
this.set("silencingUser", true);
|
this.set("silencingUser", true);
|
||||||
@ -265,20 +272,20 @@ const AdminUser = User.extend({
|
|||||||
})
|
})
|
||||||
.then((result) => this.setProperties(result.silence))
|
.then((result) => this.setProperties(result.silence))
|
||||||
.finally(() => this.set("silencingUser", false));
|
.finally(() => this.set("silencingUser", false));
|
||||||
},
|
}
|
||||||
|
|
||||||
sendActivationEmail() {
|
sendActivationEmail() {
|
||||||
return ajax(userPath("action/send_activation_email"), {
|
return ajax(userPath("action/send_activation_email"), {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { username: this.username },
|
data: { username: this.username },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
anonymize() {
|
anonymize() {
|
||||||
return ajax(`/admin/users/${this.id}/anonymize.json`, {
|
return ajax(`/admin/users/${this.id}/anonymize.json`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
destroy(formData) {
|
destroy(formData) {
|
||||||
return ajax(`/admin/users/${this.id}.json`, {
|
return ajax(`/admin/users/${this.id}.json`, {
|
||||||
@ -295,14 +302,14 @@ const AdminUser = User.extend({
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.find(this.id).then((u) => this.setProperties(u));
|
this.find(this.id).then((u) => this.setProperties(u));
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
merge(formData) {
|
merge(formData) {
|
||||||
return ajax(`/admin/users/${this.id}/merge.json`, {
|
return ajax(`/admin/users/${this.id}/merge.json`, {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: formData,
|
data: formData,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
loadDetails() {
|
loadDetails() {
|
||||||
if (this.loadedDetails) {
|
if (this.loadedDetails) {
|
||||||
@ -313,23 +320,29 @@ const AdminUser = User.extend({
|
|||||||
const userProperties = Object.assign(result, { loadedDetails: true });
|
const userProperties = Object.assign(result, { loadedDetails: true });
|
||||||
this.setProperties(userProperties);
|
this.setProperties(userProperties);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("tl3_requirements")
|
@discourseComputed("tl3_requirements")
|
||||||
tl3Requirements(requirements) {
|
tl3Requirements(requirements) {
|
||||||
if (requirements) {
|
if (requirements) {
|
||||||
return this.store.createRecord("tl3Requirements", requirements);
|
return this.store.createRecord("tl3Requirements", requirements);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("suspended_by")
|
@discourseComputed("suspended_by")
|
||||||
suspendedBy: wrapAdmin,
|
suspendedBy(user) {
|
||||||
|
return user ? AdminUser.create(user) : null;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("silenced_by")
|
@discourseComputed("silenced_by")
|
||||||
silencedBy: wrapAdmin,
|
silencedBy(user) {
|
||||||
|
return user ? AdminUser.create(user) : null;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("approved_by")
|
@discourseComputed("approved_by")
|
||||||
approvedBy: wrapAdmin,
|
approvedBy(user) {
|
||||||
|
return user ? AdminUser.create(user) : null;
|
||||||
|
}
|
||||||
|
|
||||||
deleteSSORecord() {
|
deleteSSORecord() {
|
||||||
return ajax(`/admin/users/${this.id}/sso_record.json`, {
|
return ajax(`/admin/users/${this.id}/sso_record.json`, {
|
||||||
@ -339,22 +352,5 @@ const AdminUser = User.extend({
|
|||||||
this.set("single_sign_on_record", null);
|
this.set("single_sign_on_record", null);
|
||||||
})
|
})
|
||||||
.catch(popupAjaxError);
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
AdminUser.reopenClass({
|
|
||||||
find(user_id) {
|
|
||||||
return ajax(`/admin/users/${user_id}.json`).then((result) => {
|
|
||||||
result.loadedDetails = true;
|
|
||||||
return AdminUser.create(result);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
findAll(query, userFilter) {
|
|
||||||
return ajax(`/admin/users/list/${query}.json`, {
|
|
||||||
data: userFilter,
|
|
||||||
}).then((users) => users.map((u) => AdminUser.create(u)));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default AdminUser;
|
|
||||||
|
|||||||
@ -1,24 +1,26 @@
|
|||||||
|
import { computed } from "@ember/object";
|
||||||
import AdminUser from "admin/models/admin-user";
|
import AdminUser from "admin/models/admin-user";
|
||||||
import RestModel from "discourse/models/rest";
|
import RestModel from "discourse/models/rest";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { fmt } from "discourse/lib/computed";
|
import { fmt } from "discourse/lib/computed";
|
||||||
|
|
||||||
const ApiKey = RestModel.extend({
|
export default class ApiKey extends RestModel {
|
||||||
user: computed("_user", {
|
@fmt("truncated_key", "%@...") truncatedKey;
|
||||||
get() {
|
|
||||||
return this._user;
|
@computed("_user")
|
||||||
},
|
get user() {
|
||||||
set(key, value) {
|
return this._user;
|
||||||
if (value && !(value instanceof AdminUser)) {
|
}
|
||||||
this.set("_user", AdminUser.create(value));
|
|
||||||
} else {
|
set user(value) {
|
||||||
this.set("_user", value);
|
if (value && !(value instanceof AdminUser)) {
|
||||||
}
|
this.set("_user", AdminUser.create(value));
|
||||||
return this._user;
|
} else {
|
||||||
},
|
this.set("_user", value);
|
||||||
}),
|
}
|
||||||
|
return this._user;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("description")
|
@discourseComputed("description")
|
||||||
shortDescription(description) {
|
shortDescription(description) {
|
||||||
@ -26,32 +28,28 @@ const ApiKey = RestModel.extend({
|
|||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
return `${description.substring(0, 40)}...`;
|
return `${description.substring(0, 40)}...`;
|
||||||
},
|
}
|
||||||
|
|
||||||
truncatedKey: fmt("truncated_key", "%@..."),
|
|
||||||
|
|
||||||
revoke() {
|
revoke() {
|
||||||
return ajax(`${this.basePath}/revoke`, {
|
return ajax(`${this.basePath}/revoke`, {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
}).then((result) => this.setProperties(result.api_key));
|
}).then((result) => this.setProperties(result.api_key));
|
||||||
},
|
}
|
||||||
|
|
||||||
undoRevoke() {
|
undoRevoke() {
|
||||||
return ajax(`${this.basePath}/undo-revoke`, {
|
return ajax(`${this.basePath}/undo-revoke`, {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
}).then((result) => this.setProperties(result.api_key));
|
}).then((result) => this.setProperties(result.api_key));
|
||||||
},
|
}
|
||||||
|
|
||||||
createProperties() {
|
createProperties() {
|
||||||
return this.getProperties("description", "username", "scopes");
|
return this.getProperties("description", "username", "scopes");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
basePath() {
|
basePath() {
|
||||||
return this.store
|
return this.store
|
||||||
.adapterFor("api-key")
|
.adapterFor("api-key")
|
||||||
.pathFor(this.store, "api-key", this.id);
|
.pathFor(this.store, "api-key", this.id);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default ApiKey;
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
|
import { not } from "@ember/object/computed";
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { not } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default EmberObject.extend({
|
export default class BackupStatus extends EmberObject {
|
||||||
restoreDisabled: not("restoreEnabled"),
|
@not("restoreEnabled") restoreDisabled;
|
||||||
|
|
||||||
@discourseComputed("allowRestore", "isOperationRunning")
|
@discourseComputed("allowRestore", "isOperationRunning")
|
||||||
restoreEnabled(allowRestore, isOperationRunning) {
|
restoreEnabled(allowRestore, isOperationRunning) {
|
||||||
return allowRestore && !isOperationRunning;
|
return allowRestore && !isOperationRunning;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,25 +2,12 @@ import EmberObject from "@ember/object";
|
|||||||
import MessageBus from "message-bus-client";
|
import MessageBus from "message-bus-client";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
const Backup = EmberObject.extend({
|
export default class Backup extends EmberObject {
|
||||||
destroy() {
|
static find() {
|
||||||
return ajax("/admin/backups/" + this.filename, { type: "DELETE" });
|
|
||||||
},
|
|
||||||
|
|
||||||
restore() {
|
|
||||||
return ajax("/admin/backups/" + this.filename + "/restore", {
|
|
||||||
type: "POST",
|
|
||||||
data: { client_id: MessageBus.clientId },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Backup.reopenClass({
|
|
||||||
find() {
|
|
||||||
return ajax("/admin/backups.json");
|
return ajax("/admin/backups.json");
|
||||||
},
|
}
|
||||||
|
|
||||||
start(withUploads) {
|
static start(withUploads) {
|
||||||
if (withUploads === undefined) {
|
if (withUploads === undefined) {
|
||||||
withUploads = true;
|
withUploads = true;
|
||||||
}
|
}
|
||||||
@ -31,19 +18,28 @@ Backup.reopenClass({
|
|||||||
client_id: MessageBus.clientId,
|
client_id: MessageBus.clientId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
cancel() {
|
static cancel() {
|
||||||
return ajax("/admin/backups/cancel.json", {
|
return ajax("/admin/backups/cancel.json", {
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
rollback() {
|
static rollback() {
|
||||||
return ajax("/admin/backups/rollback.json", {
|
return ajax("/admin/backups/rollback.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
||||||
export default Backup;
|
destroy() {
|
||||||
|
return ajax("/admin/backups/" + this.filename, { type: "DELETE" });
|
||||||
|
}
|
||||||
|
|
||||||
|
restore() {
|
||||||
|
return ajax("/admin/backups/" + this.filename + "/restore", {
|
||||||
|
type: "POST",
|
||||||
|
data: { client_id: MessageBus.clientId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import discourseComputed, {
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
observes,
|
import { observes, on } from "@ember-decorators/object";
|
||||||
on,
|
|
||||||
} from "discourse-common/utils/decorators";
|
|
||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { propertyNotEqual } from "discourse/lib/computed";
|
import { propertyNotEqual } from "discourse/lib/computed";
|
||||||
|
|
||||||
const ColorSchemeColor = EmberObject.extend({
|
export default class ColorSchemeColor extends EmberObject {
|
||||||
|
// Whether the current value is different than Discourse's default color scheme.
|
||||||
|
@propertyNotEqual("hex", "default_hex") overridden;
|
||||||
@on("init")
|
@on("init")
|
||||||
startTrackingChanges() {
|
startTrackingChanges() {
|
||||||
this.set("originals", { hex: this.hex || "FFFFFF" });
|
this.set("originals", { hex: this.hex || "FFFFFF" });
|
||||||
|
|
||||||
// force changed property to be recalculated
|
// force changed property to be recalculated
|
||||||
this.notifyPropertyChange("hex");
|
this.notifyPropertyChange("hex");
|
||||||
},
|
}
|
||||||
|
|
||||||
// Whether value has changed since it was last saved.
|
// Whether value has changed since it was last saved.
|
||||||
@discourseComputed("hex")
|
@discourseComputed("hex")
|
||||||
@ -26,26 +26,23 @@ const ColorSchemeColor = EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
// Whether the current value is different than Discourse's default color scheme.
|
|
||||||
overridden: propertyNotEqual("hex", "default_hex"),
|
|
||||||
|
|
||||||
// Whether the saved value is different than Discourse's default color scheme.
|
// Whether the saved value is different than Discourse's default color scheme.
|
||||||
@discourseComputed("default_hex", "hex")
|
@discourseComputed("default_hex", "hex")
|
||||||
savedIsOverriden(defaultHex) {
|
savedIsOverriden(defaultHex) {
|
||||||
return this.originals.hex !== defaultHex;
|
return this.originals.hex !== defaultHex;
|
||||||
},
|
}
|
||||||
|
|
||||||
revert() {
|
revert() {
|
||||||
this.set("hex", this.default_hex);
|
this.set("hex", this.default_hex);
|
||||||
},
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
if (this.originals) {
|
if (this.originals) {
|
||||||
this.set("hex", this.originals.hex);
|
this.set("hex", this.originals.hex);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("name")
|
@discourseComputed("name")
|
||||||
translatedName(name) {
|
translatedName(name) {
|
||||||
@ -54,7 +51,7 @@ const ColorSchemeColor = EmberObject.extend({
|
|||||||
} else {
|
} else {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("name")
|
@discourseComputed("name")
|
||||||
description(name) {
|
description(name) {
|
||||||
@ -63,7 +60,7 @@ const ColorSchemeColor = EmberObject.extend({
|
|||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
brightness returns a number between 0 (darkest) to 255 (brightest).
|
brightness returns a number between 0 (darkest) to 255 (brightest).
|
||||||
@ -90,19 +87,17 @@ const ColorSchemeColor = EmberObject.extend({
|
|||||||
1000
|
1000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("hex")
|
@observes("hex")
|
||||||
hexValueChanged() {
|
hexValueChanged() {
|
||||||
if (this.hex) {
|
if (this.hex) {
|
||||||
this.set("hex", this.hex.toString().replace(/[^0-9a-fA-F]/g, ""));
|
this.set("hex", this.hex.toString().replace(/[^0-9a-fA-F]/g, ""));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("hex")
|
@discourseComputed("hex")
|
||||||
valid(hex) {
|
valid(hex) {
|
||||||
return hex.match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== null;
|
return hex.match(/^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/) !== null;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default ColorSchemeColor;
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { not } from "@ember/object/computed";
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
import ArrayProxy from "@ember/array/proxy";
|
import ArrayProxy from "@ember/array/proxy";
|
||||||
import ColorSchemeColor from "admin/models/color-scheme-color";
|
import ColorSchemeColor from "admin/models/color-scheme-color";
|
||||||
@ -5,26 +6,56 @@ import EmberObject from "@ember/object";
|
|||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { not } from "@ember/object/computed";
|
|
||||||
|
|
||||||
const ColorScheme = EmberObject.extend({
|
class ColorSchemes extends ArrayProxy {}
|
||||||
|
|
||||||
|
export default class ColorScheme extends EmberObject {
|
||||||
|
static findAll() {
|
||||||
|
const colorSchemes = ColorSchemes.create({ content: [], loading: true });
|
||||||
|
return ajax("/admin/color_schemes").then((all) => {
|
||||||
|
all.forEach((colorScheme) => {
|
||||||
|
colorSchemes.pushObject(
|
||||||
|
ColorScheme.create({
|
||||||
|
id: colorScheme.id,
|
||||||
|
name: colorScheme.name,
|
||||||
|
is_base: colorScheme.is_base,
|
||||||
|
theme_id: colorScheme.theme_id,
|
||||||
|
theme_name: colorScheme.theme_name,
|
||||||
|
base_scheme_id: colorScheme.base_scheme_id,
|
||||||
|
user_selectable: colorScheme.user_selectable,
|
||||||
|
colors: colorScheme.colors.map((c) => {
|
||||||
|
return ColorSchemeColor.create({
|
||||||
|
name: c.name,
|
||||||
|
hex: c.hex,
|
||||||
|
default_hex: c.default_hex,
|
||||||
|
is_advanced: c.is_advanced,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return colorSchemes;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@not("id") newRecord;
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
this.startTrackingChanges();
|
this.startTrackingChanges();
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
description() {
|
description() {
|
||||||
return "" + this.name;
|
return "" + this.name;
|
||||||
},
|
}
|
||||||
|
|
||||||
startTrackingChanges() {
|
startTrackingChanges() {
|
||||||
this.set("originals", {
|
this.set("originals", {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
user_selectable: this.user_selectable,
|
user_selectable: this.user_selectable,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
schemeJson() {
|
schemeJson() {
|
||||||
const buffer = [];
|
const buffer = [];
|
||||||
@ -33,7 +64,7 @@ const ColorScheme = EmberObject.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return [`"${this.name}": {`, buffer.join(",\n"), "}"].join("\n");
|
return [`"${this.name}": {`, buffer.join(",\n"), "}"].join("\n");
|
||||||
},
|
}
|
||||||
|
|
||||||
copy() {
|
copy() {
|
||||||
const newScheme = ColorScheme.create({
|
const newScheme = ColorScheme.create({
|
||||||
@ -47,7 +78,7 @@ const ColorScheme = EmberObject.extend({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
return newScheme;
|
return newScheme;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"name",
|
"name",
|
||||||
@ -70,7 +101,7 @@ const ColorScheme = EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("changed")
|
@discourseComputed("changed")
|
||||||
disableSave(changed) {
|
disableSave(changed) {
|
||||||
@ -79,9 +110,7 @@ const ColorScheme = EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return !changed || this.saving || this.colors.any((c) => !c.get("valid"));
|
return !changed || this.saving || this.colors.any((c) => !c.get("valid"));
|
||||||
},
|
}
|
||||||
|
|
||||||
newRecord: not("id"),
|
|
||||||
|
|
||||||
save(opts) {
|
save(opts) {
|
||||||
if (this.is_base || this.disableSave) {
|
if (this.is_base || this.disableSave) {
|
||||||
@ -124,7 +153,7 @@ const ColorScheme = EmberObject.extend({
|
|||||||
this.setProperties({ savingStatus: I18n.t("saved"), saving: false });
|
this.setProperties({ savingStatus: I18n.t("saved"), saving: false });
|
||||||
this.notifyPropertyChange("description");
|
this.notifyPropertyChange("description");
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
updateUserSelectable(value) {
|
updateUserSelectable(value) {
|
||||||
if (!this.id) {
|
if (!this.id) {
|
||||||
@ -137,45 +166,11 @@ const ColorScheme = EmberObject.extend({
|
|||||||
dataType: "json",
|
dataType: "json",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
return ajax(`/admin/color_schemes/${this.id}`, { type: "DELETE" });
|
return ajax(`/admin/color_schemes/${this.id}`, { type: "DELETE" });
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
const ColorSchemes = ArrayProxy.extend({});
|
|
||||||
|
|
||||||
ColorScheme.reopenClass({
|
|
||||||
findAll() {
|
|
||||||
const colorSchemes = ColorSchemes.create({ content: [], loading: true });
|
|
||||||
return ajax("/admin/color_schemes").then((all) => {
|
|
||||||
all.forEach((colorScheme) => {
|
|
||||||
colorSchemes.pushObject(
|
|
||||||
ColorScheme.create({
|
|
||||||
id: colorScheme.id,
|
|
||||||
name: colorScheme.name,
|
|
||||||
is_base: colorScheme.is_base,
|
|
||||||
theme_id: colorScheme.theme_id,
|
|
||||||
theme_name: colorScheme.theme_name,
|
|
||||||
base_scheme_id: colorScheme.base_scheme_id,
|
|
||||||
user_selectable: colorScheme.user_selectable,
|
|
||||||
colors: colorScheme.colors.map((c) => {
|
|
||||||
return ColorSchemeColor.create({
|
|
||||||
name: c.name,
|
|
||||||
hex: c.hex,
|
|
||||||
default_hex: c.default_hex,
|
|
||||||
is_advanced: c.is_advanced,
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return colorSchemes;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ColorScheme;
|
|
||||||
|
|||||||
@ -3,10 +3,8 @@ import EmberObject from "@ember/object";
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
|
|
||||||
const EmailLog = EmberObject.extend({});
|
export default class EmailLog extends EmberObject {
|
||||||
|
static create(attrs) {
|
||||||
EmailLog.reopenClass({
|
|
||||||
create(attrs) {
|
|
||||||
attrs = attrs || {};
|
attrs = attrs || {};
|
||||||
|
|
||||||
if (attrs.user) {
|
if (attrs.user) {
|
||||||
@ -17,10 +15,10 @@ EmailLog.reopenClass({
|
|||||||
attrs.post_url = getURL(attrs.post_url);
|
attrs.post_url = getURL(attrs.post_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._super(attrs);
|
return super.create(attrs);
|
||||||
},
|
}
|
||||||
|
|
||||||
findAll(filter, offset) {
|
static findAll(filter, offset) {
|
||||||
filter = filter || {};
|
filter = filter || {};
|
||||||
offset = offset || 0;
|
offset = offset || 0;
|
||||||
|
|
||||||
@ -30,7 +28,5 @@ EmailLog.reopenClass({
|
|||||||
return ajax(`/admin/email/${status}.json?offset=${offset}`, {
|
return ajax(`/admin/email/${status}.json?offset=${offset}`, {
|
||||||
data: filter,
|
data: filter,
|
||||||
}).then((logs) => logs.map((log) => EmailLog.create(log)));
|
}).then((logs) => logs.map((log) => EmailLog.create(log)));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default EmailLog;
|
|
||||||
|
|||||||
@ -1,25 +1,21 @@
|
|||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
const EmailPreview = EmberObject.extend({});
|
export default class EmailPreview extends EmberObject {
|
||||||
|
static findDigest(username, lastSeenAt) {
|
||||||
export function oneWeekAgo() {
|
|
||||||
return moment().locale("en").subtract(7, "days").format("YYYY-MM-DD");
|
|
||||||
}
|
|
||||||
|
|
||||||
EmailPreview.reopenClass({
|
|
||||||
findDigest(username, lastSeenAt) {
|
|
||||||
return ajax("/admin/email/preview-digest.json", {
|
return ajax("/admin/email/preview-digest.json", {
|
||||||
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username },
|
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username },
|
||||||
}).then((result) => EmailPreview.create(result));
|
}).then((result) => EmailPreview.create(result));
|
||||||
},
|
}
|
||||||
|
|
||||||
sendDigest(username, lastSeenAt, email) {
|
static sendDigest(username, lastSeenAt, email) {
|
||||||
return ajax("/admin/email/send-digest.json", {
|
return ajax("/admin/email/send-digest.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email },
|
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default EmailPreview;
|
export function oneWeekAgo() {
|
||||||
|
return moment().locale("en").subtract(7, "days").format("YYYY-MM-DD");
|
||||||
|
}
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
import EmberObject from "@ember/object";
|
import EmberObject from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
const EmailSettings = EmberObject.extend({});
|
export default class EmailSettings extends EmberObject {
|
||||||
|
static find() {
|
||||||
EmailSettings.reopenClass({
|
|
||||||
find() {
|
|
||||||
return ajax("/admin/email.json").then(function (settings) {
|
return ajax("/admin/email.json").then(function (settings) {
|
||||||
return EmailSettings.create(settings);
|
return EmailSettings.create(settings);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default EmailSettings;
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import RestModel from "discourse/models/rest";
|
import RestModel from "discourse/models/rest";
|
||||||
|
|
||||||
export default RestModel.extend({
|
export default class EmailStyle extends RestModel {
|
||||||
changed: false,
|
changed = false;
|
||||||
|
|
||||||
setField(fieldName, value) {
|
setField(fieldName, value) {
|
||||||
this.set(`${fieldName}`, value);
|
this.set(`${fieldName}`, value);
|
||||||
this.set("changed", true);
|
this.set("changed", true);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user