Compare commits
270 Commits
fix-vb5-sc
...
main
| 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 | ||
|
|
607c123d90 | ||
|
|
79db4a2de0 | ||
|
|
82a84241ca | ||
|
|
e195e6f614 | ||
|
|
bb0ef4c7b4 | ||
|
|
666b4a7e6b | ||
|
|
8b67a534a0 | ||
|
|
7c74e4882a | ||
|
|
ddbe6cf3b5 | ||
|
|
a0fb2f45a2 | ||
|
|
007cce62e6 | ||
|
|
3dbaaf1268 | ||
|
|
71be74ffd3 | ||
|
|
8a2995f719 | ||
|
|
44b7706a2b | ||
|
|
d3a1b09361 | ||
|
|
c051992098 | ||
|
|
8fec1a412b | ||
|
|
24188beaaf | ||
|
|
5be13f5002 | ||
|
|
e5d756d7de | ||
|
|
654959faa4 | ||
|
|
def4133d59 | ||
|
|
366f5e08d7 | ||
|
|
5138caf525 | ||
|
|
0fbe26c15f | ||
|
|
ccb345bd88 | ||
|
|
4855a2879c | ||
|
|
42b451ef8a | ||
|
|
451ee71930 | ||
|
|
c81d4f60af | ||
|
|
6a86288c5e | ||
|
|
116781c748 | ||
|
|
f63d18d6ca | ||
|
|
bc4e016b49 | ||
|
|
a509441148 | ||
|
|
badd40090f | ||
|
|
69c7df2e56 | ||
|
|
e82b8c2b06 | ||
|
|
b12e51d309 | ||
|
|
6e9b4e8147 | ||
|
|
c9e6efffe3 | ||
|
|
486797bbfc | ||
|
|
d0237f63ce | ||
|
|
d92fd30d23 | ||
|
|
52d4de7b45 | ||
|
|
9c669f3bdc | ||
|
|
720cf7c424 | ||
|
|
90ed30b3ff | ||
|
|
d3983d94a3 | ||
|
|
435ba4d03d | ||
|
|
5a384e60ac | ||
|
|
d5cf128dbd | ||
|
|
04659b0e41 | ||
|
|
1dca7b8b0a | ||
|
|
4cadad9a53 | ||
|
|
ba5e0924db | ||
|
|
f9150bc701 | ||
|
|
b50b63808c | ||
|
|
9fb5bfd93d | ||
|
|
ad0fd9919b | ||
|
|
c052df412a | ||
|
|
6108eee31d | ||
|
|
a9f2c6db64 | ||
|
|
5dbdcb3f23 | ||
|
|
a433b30650 | ||
|
|
a0ca10fa17 | ||
|
|
b8762172e4 | ||
|
|
925a7bd48b | ||
|
|
da43b60510 | ||
|
|
0a619d8c88 | ||
|
|
576745637e | ||
|
|
ab46a05d77 | ||
|
|
64d1192bff | ||
|
|
f03186dc79 | ||
|
|
4ab1f76499 | ||
|
|
1a0174b38d | ||
|
|
c3ae555ac2 | ||
|
|
51a7cd899e |
24
.github/workflows/tests.yml
vendored
24
.github/workflows/tests.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')"
|
if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')"
|
||||||
name: ${{ matrix.target }} ${{ matrix.build_type }} ${{ matrix.ruby }}
|
name: ${{ matrix.target }} ${{ matrix.build_type }} ${{ matrix.ruby }}
|
||||||
runs-on: ${{ (matrix.build_type == 'annotations') && 'ubuntu-latest' || 'ubuntu-20.04-8core' }}
|
runs-on: ${{ (matrix.build_type == 'annotations') && 'ubuntu-latest' || 'ubuntu-20.04-8core' }}
|
||||||
container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}${{ (matrix.ruby == '3.2') && '-ruby-3.2.0' || '' }}
|
container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}${{ (matrix.ruby == '3.1') && '-ruby-3.1.0' || '' }}
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@ -38,7 +38,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
build_type: [backend, frontend, system, annotations]
|
build_type: [backend, frontend, system, annotations]
|
||||||
target: [core, plugins]
|
target: [core, plugins]
|
||||||
ruby: ['3.1']
|
ruby: ['3.2']
|
||||||
exclude:
|
exclude:
|
||||||
- build_type: annotations
|
- build_type: annotations
|
||||||
target: plugins
|
target: plugins
|
||||||
@ -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
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
3.1.3
|
3.2.1
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
115
Gemfile.lock
115
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)
|
||||||
@ -110,7 +110,7 @@ GEM
|
|||||||
chunky_png (1.4.0)
|
chunky_png (1.4.0)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
colored2 (3.1.2)
|
colored2 (3.1.2)
|
||||||
concurrent-ruby (1.2.0)
|
concurrent-ruby (1.2.2)
|
||||||
connection_pool (2.3.0)
|
connection_pool (2.3.0)
|
||||||
cose (1.3.0)
|
cose (1.3.0)
|
||||||
cbor (~> 0.5.9)
|
cbor (~> 0.5.9)
|
||||||
@ -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.5)
|
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)
|
||||||
@ -325,15 +326,15 @@ GEM
|
|||||||
pry-rails (0.3.9)
|
pry-rails (0.3.9)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.10.4)
|
||||||
public_suffix (5.0.1)
|
public_suffix (5.0.1)
|
||||||
puma (6.1.0)
|
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,15 +348,15 @@ 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)
|
||||||
zeitwerk (~> 2.5)
|
zeitwerk (~> 2.5)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
raindrops (0.20.0)
|
raindrops (0.20.1)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
rb-fsevent (0.11.2)
|
rb-fsevent (0.11.2)
|
||||||
rb-inotify (0.10.1)
|
rb-inotify (0.10.1)
|
||||||
@ -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,28 +412,28 @@ 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.45.1)
|
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)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 1.8, < 3.0)
|
||||||
rexml (>= 3.2.5, < 4.0)
|
rexml (>= 3.2.5, < 4.0)
|
||||||
rubocop-ast (>= 1.24.1, < 2.0)
|
rubocop-ast (>= 1.26.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 3.0)
|
unicode-display_width (>= 2.4.0, < 3.0)
|
||||||
rubocop-ast (1.26.0)
|
rubocop-ast (1.27.0)
|
||||||
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.11.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.0)
|
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
|
||||||
|
|||||||
@ -30,7 +30,7 @@ To get your environment setup, follow the community setup guide for your operati
|
|||||||
|
|
||||||
If you're familiar with how Rails works and are comfortable setting up your own environment, you can also try out the [**Discourse Advanced Developer Guide**](docs/DEVELOPER-ADVANCED.md), which is aimed primarily at Ubuntu and macOS environments.
|
If you're familiar with how Rails works and are comfortable setting up your own environment, you can also try out the [**Discourse Advanced Developer Guide**](docs/DEVELOPER-ADVANCED.md), which is aimed primarily at Ubuntu and macOS environments.
|
||||||
|
|
||||||
Before you get started, ensure you have the following minimum versions: [Ruby 3.1+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 13](https://www.postgresql.org/download/), [Redis 7](https://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
Before you get started, ensure you have the following minimum versions: [Ruby 3.2+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 13](https://www.postgresql.org/download/), [Redis 7](https://redis.io/download). If you're having trouble, please see our [**TROUBLESHOOTING GUIDE**](docs/TROUBLESHOOTING.md) first!
|
||||||
|
|
||||||
## Setting up Discourse
|
## Setting up Discourse
|
||||||
|
|
||||||
|
|||||||
@ -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/";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,31 +1,33 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { observes, on } from "@ember-decorators/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import getURL from "discourse-common/lib/get-url";
|
import getURL from "discourse-common/lib/get-url";
|
||||||
import loadScript from "discourse/lib/load-script";
|
import loadScript from "discourse/lib/load-script";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { bind, observes } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import { on } from "@ember/object/evented";
|
|
||||||
|
|
||||||
const COLOR_VARS_REGEX =
|
const COLOR_VARS_REGEX =
|
||||||
/\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
|
/\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("ace-wrapper")
|
||||||
mode: "css",
|
export default class AceEditor extends Component {
|
||||||
classNames: ["ace-wrapper"],
|
mode = "css";
|
||||||
_editor: null,
|
disabled = false;
|
||||||
_skipContentChangeEvent: null,
|
htmlPlaceholder = false;
|
||||||
disabled: false,
|
_editor = null;
|
||||||
htmlPlaceholder: false,
|
_skipContentChangeEvent = null;
|
||||||
|
|
||||||
@observes("editorId")
|
@observes("editorId")
|
||||||
editorIdChanged() {
|
editorIdChanged() {
|
||||||
if (this.autofocus) {
|
if (this.autofocus) {
|
||||||
this.send("focus");
|
this.send("focus");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
didRender() {
|
didRender() {
|
||||||
this._skipContentChangeEvent = false;
|
this._skipContentChangeEvent = false;
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("content")
|
@observes("content")
|
||||||
contentChanged() {
|
contentChanged() {
|
||||||
@ -33,14 +35,14 @@ export default Component.extend({
|
|||||||
if (this._editor && !this._skipContentChangeEvent) {
|
if (this._editor && !this._skipContentChangeEvent) {
|
||||||
this._editor.getSession().setValue(content);
|
this._editor.getSession().setValue(content);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("mode")
|
@observes("mode")
|
||||||
modeChanged() {
|
modeChanged() {
|
||||||
if (this._editor && !this._skipContentChangeEvent) {
|
if (this._editor && !this._skipContentChangeEvent) {
|
||||||
this._editor.getSession().setMode("ace/mode/" + this.mode);
|
this._editor.getSession().setMode("ace/mode/" + this.mode);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("placeholder")
|
@observes("placeholder")
|
||||||
placeholderChanged() {
|
placeholderChanged() {
|
||||||
@ -49,12 +51,12 @@ export default Component.extend({
|
|||||||
placeholder: this.placeholder,
|
placeholder: this.placeholder,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("disabled")
|
@observes("disabled")
|
||||||
disabledStateChanged() {
|
disabledStateChanged() {
|
||||||
this.changeDisabledState();
|
this.changeDisabledState();
|
||||||
},
|
}
|
||||||
|
|
||||||
changeDisabledState() {
|
changeDisabledState() {
|
||||||
const editor = this._editor;
|
const editor = this._editor;
|
||||||
@ -67,9 +69,10 @@ export default Component.extend({
|
|||||||
});
|
});
|
||||||
editor.container.parentNode.setAttribute("data-disabled", disabled);
|
editor.container.parentNode.setAttribute("data-disabled", disabled);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_destroyEditor: on("willDestroyElement", function () {
|
@on("willDestroyElement")
|
||||||
|
_destroyEditor() {
|
||||||
if (this._editor) {
|
if (this._editor) {
|
||||||
this._editor.destroy();
|
this._editor.destroy();
|
||||||
this._editor = null;
|
this._editor = null;
|
||||||
@ -80,16 +83,16 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(window).off("ace:resize");
|
$(window).off("ace:resize");
|
||||||
}),
|
}
|
||||||
|
|
||||||
resize() {
|
resize() {
|
||||||
if (this._editor) {
|
if (this._editor) {
|
||||||
this._editor.resize();
|
this._editor.resize();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
super.didInsertElement(...arguments);
|
||||||
loadScript("/javascripts/ace/ace.js").then(() => {
|
loadScript("/javascripts/ace/ace.js").then(() => {
|
||||||
window.ace.require(["ace/ace"], (loadedAce) => {
|
window.ace.require(["ace/ace"], (loadedAce) => {
|
||||||
loadedAce.config.set("loadWorkerFromBlob", false);
|
loadedAce.config.set("loadWorkerFromBlob", false);
|
||||||
@ -153,13 +156,13 @@ export default Component.extend({
|
|||||||
this._darkModeListener.addListener(this.setAceTheme);
|
this._darkModeListener.addListener(this.setAceTheme);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
if (this._darkModeListener) {
|
if (this._darkModeListener) {
|
||||||
this._darkModeListener.removeListener(this.setAceTheme);
|
this._darkModeListener.removeListener(this.setAceTheme);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
setAceTheme() {
|
setAceTheme() {
|
||||||
@ -170,7 +173,7 @@ export default Component.extend({
|
|||||||
this._editor.setTheme(
|
this._editor.setTheme(
|
||||||
`ace/theme/${schemeType === "dark" ? "chaos" : "chrome"}`
|
`ace/theme/${schemeType === "dark" ? "chaos" : "chrome"}`
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
warnSCSSDeprecations() {
|
warnSCSSDeprecations() {
|
||||||
if (
|
if (
|
||||||
@ -197,21 +200,20 @@ export default Component.extend({
|
|||||||
|
|
||||||
this._editor.getSession().setAnnotations(warnings);
|
this._editor.getSession().setAnnotations(warnings);
|
||||||
|
|
||||||
this.setWarning(
|
this.setWarning?.(
|
||||||
warnings.length
|
warnings.length
|
||||||
? I18n.t("admin.customize.theme.scss_color_variables_warning")
|
? I18n.t("admin.customize.theme.scss_color_variables_warning")
|
||||||
: false
|
: false
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
focus() {
|
focus() {
|
||||||
if (this._editor) {
|
if (this._editor) {
|
||||||
this._editor.focus();
|
this._editor.focus();
|
||||||
this._editor.navigateFileEnd();
|
this._editor.navigateFileEnd();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_overridePlaceholder(loadedAce) {
|
_overridePlaceholder(loadedAce) {
|
||||||
const originalPlaceholderSetter =
|
const originalPlaceholderSetter =
|
||||||
@ -239,5 +241,5 @@ export default Component.extend({
|
|||||||
|
|
||||||
this.$updatePlaceholder();
|
this.$updatePlaceholder();
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,28 +1,26 @@
|
|||||||
import { observes, on } from "discourse-common/utils/decorators";
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { observes, on } from "@ember-decorators/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
import { scheduleOnce } from "@ember/runloop";
|
import { scheduleOnce } from "@ember/runloop";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("admin-backups-logs")
|
||||||
classNames: ["admin-backups-logs"],
|
export default class AdminBackupsLogs extends Component {
|
||||||
showLoadingSpinner: false,
|
showLoadingSpinner = false;
|
||||||
hasFormattedLogs: false,
|
hasFormattedLogs = false;
|
||||||
noLogsMessage: I18n.t("admin.backups.logs.none"),
|
noLogsMessage = I18n.t("admin.backups.logs.none");
|
||||||
|
formattedLogs = "";
|
||||||
init() {
|
index = 0;
|
||||||
this._super(...arguments);
|
|
||||||
this._reset();
|
|
||||||
},
|
|
||||||
|
|
||||||
_reset() {
|
_reset() {
|
||||||
this.setProperties({ formattedLogs: "", index: 0 });
|
this.setProperties({ formattedLogs: "", index: 0 });
|
||||||
},
|
}
|
||||||
|
|
||||||
_scrollDown() {
|
_scrollDown() {
|
||||||
const div = this.element;
|
const div = this.element;
|
||||||
div.scrollTop = div.scrollHeight;
|
div.scrollTop = div.scrollHeight;
|
||||||
},
|
}
|
||||||
|
|
||||||
@on("init")
|
@on("init")
|
||||||
@observes("logs.[]")
|
@observes("logs.[]")
|
||||||
@ -31,7 +29,7 @@ export default Component.extend({
|
|||||||
this._reset(); // reset the cached logs whenever the model is reset
|
this._reset(); // reset the cached logs whenever the model is reset
|
||||||
this.renderLogs();
|
this.renderLogs();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_updateFormattedLogsFunc() {
|
_updateFormattedLogsFunc() {
|
||||||
const logs = this.logs;
|
const logs = this.logs;
|
||||||
@ -55,13 +53,13 @@ export default Component.extend({
|
|||||||
this.renderLogs();
|
this.renderLogs();
|
||||||
|
|
||||||
scheduleOnce("afterRender", this, this._scrollDown);
|
scheduleOnce("afterRender", this, this._scrollDown);
|
||||||
},
|
}
|
||||||
|
|
||||||
@on("init")
|
@on("init")
|
||||||
@observes("logs.[]")
|
@observes("logs.[]")
|
||||||
_updateFormattedLogs() {
|
_updateFormattedLogs() {
|
||||||
discourseDebounce(this, this._updateFormattedLogsFunc, 150);
|
discourseDebounce(this, this._updateFormattedLogsFunc, 150);
|
||||||
},
|
}
|
||||||
|
|
||||||
renderLogs() {
|
renderLogs() {
|
||||||
const formattedLogs = this.formattedLogs;
|
const formattedLogs = this.formattedLogs;
|
||||||
@ -76,5 +74,5 @@ export default Component.extend({
|
|||||||
} else {
|
} else {
|
||||||
this.set("showLoadingSpinner", false);
|
this.set("showLoadingSpinner", false);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,28 +1,22 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("")
|
||||||
tagName: "",
|
export default class AdminEditableField extends Component {
|
||||||
|
buffer = "";
|
||||||
buffer: "",
|
editing = false;
|
||||||
editing: false,
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.set("editing", false);
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
edit(event) {
|
edit(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.set("buffer", this.value);
|
this.set("buffer", this.value);
|
||||||
this.toggleProperty("editing");
|
this.toggleProperty("editing");
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
save() {
|
save() {
|
||||||
// Action has to toggle 'editing' property.
|
// Action has to toggle 'editing' property.
|
||||||
this.action(this.buffer);
|
this.action(this.buffer);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
classNames: ["row"],
|
@classNames("row")
|
||||||
});
|
export default class AdminFormRow extends Component {}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import loadScript from "discourse/lib/load-script";
|
import loadScript from "discourse/lib/load-script";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("canvas")
|
||||||
tagName: "canvas",
|
export default class AdminGraph extends Component {
|
||||||
type: "line",
|
type = "line";
|
||||||
|
|
||||||
refreshChart() {
|
refreshChart() {
|
||||||
const ctx = this.element.getContext("2d");
|
const ctx = this.element.getContext("2d");
|
||||||
@ -49,11 +50,11 @@ export default Component.extend({
|
|||||||
};
|
};
|
||||||
|
|
||||||
this._chart = new window.Chart(ctx, config);
|
this._chart = new window.Chart(ctx, config);
|
||||||
},
|
}
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
loadScript("/javascripts/Chart.min.js").then(() =>
|
loadScript("/javascripts/Chart.min.js").then(() =>
|
||||||
this.refreshChart.apply(this)
|
this.refreshChart.apply(this)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "",
|
@tagName("")
|
||||||
});
|
export default class AdminNav extends Component {}
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("penalty-history")
|
||||||
classNames: ["penalty-history"],
|
export default class AdminPenaltyHistory extends Component {
|
||||||
|
|
||||||
@discourseComputed("user.penalty_counts.suspended")
|
@discourseComputed("user.penalty_counts.suspended")
|
||||||
suspendedCountClass(count) {
|
suspendedCountClass(count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
return "danger";
|
return "danger";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("user.penalty_counts.silenced")
|
@discourseComputed("user.penalty_counts.silenced")
|
||||||
silencedCountClass(count) {
|
silencedCountClass(count) {
|
||||||
@ -18,5 +18,5 @@ export default Component.extend({
|
|||||||
return "danger";
|
return "danger";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import Component from "@ember/component";
|
import { action } from "@ember/object";
|
||||||
import { equal } from "@ember/object/computed";
|
import { equal } from "@ember/object/computed";
|
||||||
|
import Component from "@ember/component";
|
||||||
import discourseComputed, {
|
import discourseComputed, {
|
||||||
afterRender,
|
afterRender,
|
||||||
} from "discourse-common/utils/decorators";
|
} from "discourse-common/utils/decorators";
|
||||||
@ -7,30 +8,28 @@ import I18n from "I18n";
|
|||||||
|
|
||||||
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
||||||
|
|
||||||
export default Component.extend({
|
export default class AdminPenaltyPostAction extends Component {
|
||||||
postId: null,
|
postId = null;
|
||||||
postAction: null,
|
postAction = null;
|
||||||
postEdit: null,
|
postEdit = null;
|
||||||
|
|
||||||
|
@equal("postAction", "edit") editing;
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
penaltyActions() {
|
penaltyActions() {
|
||||||
return ACTIONS.map((id) => {
|
return ACTIONS.map((id) => {
|
||||||
return { id, name: I18n.t(`admin.user.penalty_post_${id}`) };
|
return { id, name: I18n.t(`admin.user.penalty_post_${id}`) };
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
editing: equal("postAction", "edit"),
|
@action
|
||||||
|
penaltyChanged(postAction) {
|
||||||
|
this.set("postAction", postAction);
|
||||||
|
|
||||||
actions: {
|
// If we switch to edit mode, jump to the edit textarea
|
||||||
penaltyChanged(postAction) {
|
if (postAction === "edit") {
|
||||||
this.set("postAction", postAction);
|
this._focusEditTextarea();
|
||||||
|
}
|
||||||
// If we switch to edit mode, jump to the edit textarea
|
}
|
||||||
if (postAction === "edit") {
|
|
||||||
this._focusEditTextarea();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
@afterRender
|
@afterRender
|
||||||
_focusEditTextarea() {
|
_focusEditTextarea() {
|
||||||
@ -38,5 +37,5 @@ export default Component.extend({
|
|||||||
const body = elem.closest(".modal-body");
|
const body = elem.closest(".modal-body");
|
||||||
body.scrollTo(0, body.clientHeight);
|
body.scrollTo(0, body.clientHeight);
|
||||||
elem.querySelector(".post-editor").focus();
|
elem.querySelector(".post-editor").focus();
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,43 +1,46 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
|
import { equal } from "@ember/object/computed";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { equal } from "@ember/object/computed";
|
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
const CUSTOM_REASON_KEY = "custom";
|
const CUSTOM_REASON_KEY = "custom";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("")
|
||||||
tagName: "",
|
export default class AdminPenaltyReason extends Component {
|
||||||
selectedReason: CUSTOM_REASON_KEY,
|
selectedReason = CUSTOM_REASON_KEY;
|
||||||
customReason: "",
|
customReason = "";
|
||||||
reasonKeys: [
|
|
||||||
|
reasonKeys = [
|
||||||
"not_listening_to_staff",
|
"not_listening_to_staff",
|
||||||
"consuming_staff_time",
|
"consuming_staff_time",
|
||||||
"combative",
|
"combative",
|
||||||
"in_wrong_place",
|
"in_wrong_place",
|
||||||
"no_constructive_purpose",
|
"no_constructive_purpose",
|
||||||
CUSTOM_REASON_KEY,
|
CUSTOM_REASON_KEY,
|
||||||
],
|
];
|
||||||
isCustomReason: equal("selectedReason", CUSTOM_REASON_KEY),
|
|
||||||
|
@equal("selectedReason", CUSTOM_REASON_KEY) isCustomReason;
|
||||||
|
|
||||||
@discourseComputed("reasonKeys")
|
@discourseComputed("reasonKeys")
|
||||||
reasons(keys) {
|
reasons(keys) {
|
||||||
return keys.map((key) => {
|
return keys.map((key) => {
|
||||||
return { id: key, name: I18n.t(`admin.user.suspend_reasons.${key}`) };
|
return { id: key, name: I18n.t(`admin.user.suspend_reasons.${key}`) };
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
setSelectedReason(value) {
|
setSelectedReason(value) {
|
||||||
this.set("selectedReason", value);
|
this.set("selectedReason", value);
|
||||||
this.setReason();
|
this.setReason();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
setCustomReason(value) {
|
setCustomReason(value) {
|
||||||
this.set("customReason", value);
|
this.set("customReason", value);
|
||||||
this.setReason();
|
this.setReason();
|
||||||
},
|
}
|
||||||
|
|
||||||
setReason() {
|
setReason() {
|
||||||
if (this.isCustomReason) {
|
if (this.isCustomReason) {
|
||||||
@ -48,5 +51,5 @@ export default Component.extend({
|
|||||||
I18n.t(`admin.user.suspend_reasons.${this.selectedReason}`)
|
I18n.t(`admin.user.suspend_reasons.${this.selectedReason}`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("")
|
||||||
tagName: "",
|
export default class AdminPenaltySimilarUsers extends Component {
|
||||||
|
|
||||||
@discourseComputed("penaltyType")
|
@discourseComputed("penaltyType")
|
||||||
penaltyField(penaltyType) {
|
penaltyField(penaltyType) {
|
||||||
if (penaltyType === "suspend") {
|
if (penaltyType === "suspend") {
|
||||||
@ -12,7 +12,7 @@ export default Component.extend({
|
|||||||
} else if (penaltyType === "silence") {
|
} else if (penaltyType === "silence") {
|
||||||
return "can_be_silenced";
|
return "can_be_silenced";
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
selectUserId(userId, event) {
|
selectUserId(userId, event) {
|
||||||
@ -25,5 +25,5 @@ export default Component.extend({
|
|||||||
} else {
|
} else {
|
||||||
this.selectedUserIds.removeObject(userId);
|
this.selectedUserIds.removeObject(userId);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Report from "admin/models/report";
|
import Report from "admin/models/report";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
@ -7,31 +8,31 @@ import { number } from "discourse/lib/formatter";
|
|||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("admin-report-chart")
|
||||||
classNames: ["admin-report-chart"],
|
export default class AdminReportChart extends Component {
|
||||||
limit: 8,
|
limit = 8;
|
||||||
total: 0,
|
total = 0;
|
||||||
options: null,
|
options = null;
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
super.didInsertElement(...arguments);
|
||||||
|
|
||||||
window.addEventListener("resize", this._resizeHandler);
|
window.addEventListener("resize", this._resizeHandler);
|
||||||
},
|
}
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
super.willDestroyElement(...arguments);
|
||||||
|
|
||||||
window.removeEventListener("resize", this._resizeHandler);
|
window.removeEventListener("resize", this._resizeHandler);
|
||||||
|
|
||||||
this._resetChart();
|
this._resetChart();
|
||||||
},
|
}
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
super.didReceiveAttrs(...arguments);
|
||||||
|
|
||||||
discourseDebounce(this, this._scheduleChartRendering, 100);
|
discourseDebounce(this, this._scheduleChartRendering, 100);
|
||||||
},
|
}
|
||||||
|
|
||||||
_scheduleChartRendering() {
|
_scheduleChartRendering() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
@ -40,7 +41,7 @@ export default Component.extend({
|
|||||||
this.element && this.element.querySelector(".chart-canvas")
|
this.element && this.element.querySelector(".chart-canvas")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_renderChart(model, chartCanvas) {
|
_renderChart(model, chartCanvas) {
|
||||||
if (!chartCanvas) {
|
if (!chartCanvas) {
|
||||||
@ -99,7 +100,7 @@ export default Component.extend({
|
|||||||
this._buildChartConfig(data, this.options)
|
this._buildChartConfig(data, this.options)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_buildChartConfig(data, options) {
|
_buildChartConfig(data, options) {
|
||||||
return {
|
return {
|
||||||
@ -161,21 +162,21 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
_resetChart() {
|
_resetChart() {
|
||||||
if (this._chart) {
|
if (this._chart) {
|
||||||
this._chart.destroy();
|
this._chart.destroy();
|
||||||
this._chart = null;
|
this._chart = null;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_applyChartGrouping(model, data, options) {
|
_applyChartGrouping(model, data, options) {
|
||||||
return Report.collapse(model, data, options.chartGrouping);
|
return Report.collapse(model, data, options.chartGrouping);
|
||||||
},
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
_resizeHandler() {
|
_resizeHandler() {
|
||||||
discourseDebounce(this, this._scheduleChartRendering, 500);
|
discourseDebounce(this, this._scheduleChartRendering, 500);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
import { attributeBindings, classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
classNames: ["admin-report-counters"],
|
|
||||||
|
|
||||||
attributeBindings: ["model.description:title"],
|
@classNames("admin-report-counters")
|
||||||
});
|
@attributeBindings("model.description:title")
|
||||||
|
export default class AdminReportCounters extends Component {}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import Component from "@ember/component";
|
import { classNameBindings, tagName } from "@ember-decorators/component";
|
||||||
import { match } from "@ember/object/computed";
|
import { match } from "@ember/object/computed";
|
||||||
export default Component.extend({
|
import Component from "@ember/component";
|
||||||
allTime: true,
|
|
||||||
tagName: "tr",
|
@tagName("tr")
|
||||||
reverseColors: match(
|
@classNameBindings("reverseColors")
|
||||||
"report.type",
|
export default class AdminReportCounts extends Component {
|
||||||
/^(time_to_first_response|topics_with_no_response)$/
|
allTime = true;
|
||||||
),
|
|
||||||
classNameBindings: ["reverseColors"],
|
@match("report.type", /^(time_to_first_response|topics_with_no_response)$/)
|
||||||
});
|
reverseColors;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
classNames: ["admin-report-inline-table"],
|
@classNames("admin-report-inline-table")
|
||||||
});
|
export default class AdminReportInlineTable extends Component {}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "tr",
|
@tagName("tr")
|
||||||
});
|
export default class AdminReportPerDayCounts extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Report from "admin/models/report";
|
import Report from "admin/models/report";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseDebounce from "discourse-common/lib/debounce";
|
import discourseDebounce from "discourse-common/lib/debounce";
|
||||||
@ -7,32 +8,31 @@ import { number } from "discourse/lib/formatter";
|
|||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("admin-report-chart", "admin-report-stacked-chart")
|
||||||
classNames: ["admin-report-chart", "admin-report-stacked-chart"],
|
export default class AdminReportStackedChart extends Component {
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
super.didInsertElement(...arguments);
|
||||||
|
|
||||||
window.addEventListener("resize", this._resizeHandler);
|
window.addEventListener("resize", this._resizeHandler);
|
||||||
},
|
}
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
super.willDestroyElement(...arguments);
|
||||||
|
|
||||||
window.removeEventListener("resize", this._resizeHandler);
|
window.removeEventListener("resize", this._resizeHandler);
|
||||||
this._resetChart();
|
this._resetChart();
|
||||||
},
|
}
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
super.didReceiveAttrs(...arguments);
|
||||||
|
|
||||||
discourseDebounce(this, this._scheduleChartRendering, 100);
|
discourseDebounce(this, this._scheduleChartRendering, 100);
|
||||||
},
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
_resizeHandler() {
|
_resizeHandler() {
|
||||||
discourseDebounce(this, this._scheduleChartRendering, 500);
|
discourseDebounce(this, this._scheduleChartRendering, 500);
|
||||||
},
|
}
|
||||||
|
|
||||||
_scheduleChartRendering() {
|
_scheduleChartRendering() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
@ -45,7 +45,7 @@ export default Component.extend({
|
|||||||
this.element.querySelector(".chart-canvas")
|
this.element.querySelector(".chart-canvas")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_renderChart(model, chartCanvas) {
|
_renderChart(model, chartCanvas) {
|
||||||
if (!chartCanvas) {
|
if (!chartCanvas) {
|
||||||
@ -79,7 +79,7 @@ export default Component.extend({
|
|||||||
|
|
||||||
this._chart = new window.Chart(context, this._buildChartConfig(data));
|
this._chart = new window.Chart(context, this._buildChartConfig(data));
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_buildChartConfig(data) {
|
_buildChartConfig(data) {
|
||||||
return {
|
return {
|
||||||
@ -150,10 +150,10 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
_resetChart() {
|
_resetChart() {
|
||||||
this._chart?.destroy();
|
this._chart?.destroy();
|
||||||
this._chart = null;
|
this._chart = null;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,43 +1,45 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { alias } from "@ember/object/computed";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
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 { setting } from "discourse/lib/computed";
|
import { setting } from "discourse/lib/computed";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("admin-report-storage-stats")
|
||||||
classNames: ["admin-report-storage-stats"],
|
export default class AdminReportStorageStats extends Component {
|
||||||
|
@setting("backup_location") backupLocation;
|
||||||
|
|
||||||
backupLocation: setting("backup_location"),
|
@alias("model.data.backups") backupStats;
|
||||||
backupStats: alias("model.data.backups"),
|
|
||||||
uploadStats: alias("model.data.uploads"),
|
@alias("model.data.uploads") uploadStats;
|
||||||
|
|
||||||
@discourseComputed("backupStats")
|
@discourseComputed("backupStats")
|
||||||
showBackupStats(stats) {
|
showBackupStats(stats) {
|
||||||
return stats && this.currentUser.admin;
|
return stats && this.currentUser.admin;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("backupLocation")
|
@discourseComputed("backupLocation")
|
||||||
backupLocationName(backupLocation) {
|
backupLocationName(backupLocation) {
|
||||||
return I18n.t(`admin.backups.location.${backupLocation}`);
|
return I18n.t(`admin.backups.location.${backupLocation}`);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("backupStats.used_bytes")
|
@discourseComputed("backupStats.used_bytes")
|
||||||
usedBackupSpace(bytes) {
|
usedBackupSpace(bytes) {
|
||||||
return I18n.toHumanSize(bytes);
|
return I18n.toHumanSize(bytes);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("backupStats.free_bytes")
|
@discourseComputed("backupStats.free_bytes")
|
||||||
freeBackupSpace(bytes) {
|
freeBackupSpace(bytes) {
|
||||||
return I18n.toHumanSize(bytes);
|
return I18n.toHumanSize(bytes);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("uploadStats.used_bytes")
|
@discourseComputed("uploadStats.used_bytes")
|
||||||
usedUploadSpace(bytes) {
|
usedUploadSpace(bytes) {
|
||||||
return I18n.toHumanSize(bytes);
|
return I18n.toHumanSize(bytes);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("uploadStats.free_bytes")
|
@discourseComputed("uploadStats.free_bytes")
|
||||||
freeUploadSpace(bytes) {
|
freeUploadSpace(bytes) {
|
||||||
return I18n.toHumanSize(bytes);
|
return I18n.toHumanSize(bytes);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,21 +1,27 @@
|
|||||||
import Component from "@ember/component";
|
import {
|
||||||
|
attributeBindings,
|
||||||
|
classNameBindings,
|
||||||
|
classNames,
|
||||||
|
tagName,
|
||||||
|
} from "@ember-decorators/component";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("td")
|
||||||
tagName: "td",
|
@classNames("admin-report-table-cell")
|
||||||
classNames: ["admin-report-table-cell"],
|
@classNameBindings("type", "property")
|
||||||
classNameBindings: ["type", "property"],
|
@attributeBindings("value:title")
|
||||||
attributeBindings: ["value:title"],
|
export default class AdminReportTableCell extends Component {
|
||||||
options: null,
|
options = null;
|
||||||
|
|
||||||
|
@alias("label.type") type;
|
||||||
|
@alias("label.mainProperty") property;
|
||||||
|
@alias("computedLabel.formattedValue") formattedValue;
|
||||||
|
@alias("computedLabel.value") value;
|
||||||
|
|
||||||
@discourseComputed("label", "data", "options")
|
@discourseComputed("label", "data", "options")
|
||||||
computedLabel(label, data, options) {
|
computedLabel(label, data, options) {
|
||||||
return label.compute(data, options || {});
|
return label.compute(data, options || {});
|
||||||
},
|
}
|
||||||
|
}
|
||||||
type: alias("label.type"),
|
|
||||||
property: alias("label.mainProperty"),
|
|
||||||
formattedValue: alias("computedLabel.formattedValue"),
|
|
||||||
value: alias("computedLabel.value"),
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,19 +1,24 @@
|
|||||||
|
import {
|
||||||
|
attributeBindings,
|
||||||
|
classNameBindings,
|
||||||
|
classNames,
|
||||||
|
tagName,
|
||||||
|
} from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("th")
|
||||||
tagName: "th",
|
@classNames("admin-report-table-header")
|
||||||
classNames: ["admin-report-table-header"],
|
@classNameBindings("label.mainProperty", "label.type", "isCurrentSort")
|
||||||
classNameBindings: ["label.mainProperty", "label.type", "isCurrentSort"],
|
@attributeBindings("label.title:title")
|
||||||
attributeBindings: ["label.title:title"],
|
export default class AdminReportTableHeader extends Component {
|
||||||
|
|
||||||
@discourseComputed("currentSortLabel.sortProperty", "label.sortProperty")
|
@discourseComputed("currentSortLabel.sortProperty", "label.sortProperty")
|
||||||
isCurrentSort(currentSortField, labelSortField) {
|
isCurrentSort(currentSortField, labelSortField) {
|
||||||
return currentSortField === labelSortField;
|
return currentSortField === labelSortField;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentSortDirection")
|
@discourseComputed("currentSortDirection")
|
||||||
sortIcon(currentSortDirection) {
|
sortIcon(currentSortDirection) {
|
||||||
return currentSortDirection === 1 ? "caret-up" : "caret-down";
|
return currentSortDirection === 1 ? "caret-up" : "caret-down";
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { classNames, tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "tr",
|
@tagName("tr")
|
||||||
classNames: ["admin-report-table-row"],
|
@classNames("admin-report-table-row")
|
||||||
options: null,
|
export default class AdminReportTableRow extends Component {
|
||||||
});
|
options = null;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,22 +1,26 @@
|
|||||||
import Component from "@ember/component";
|
import { action } from "@ember/object";
|
||||||
|
import { classNameBindings, classNames } from "@ember-decorators/component";
|
||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { makeArray } from "discourse-common/lib/helpers";
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
const PAGES_LIMIT = 8;
|
const PAGES_LIMIT = 8;
|
||||||
|
|
||||||
export default Component.extend({
|
@classNameBindings("sortable", "twoColumns")
|
||||||
classNameBindings: ["sortable", "twoColumns"],
|
@classNames("admin-report-table")
|
||||||
classNames: ["admin-report-table"],
|
export default class AdminReportTable extends Component {
|
||||||
sortable: false,
|
sortable = false;
|
||||||
sortDirection: 1,
|
sortDirection = 1;
|
||||||
perPage: alias("options.perPage"),
|
|
||||||
page: 0,
|
@alias("options.perPage") perPage;
|
||||||
|
|
||||||
|
page = 0;
|
||||||
|
|
||||||
@discourseComputed("model.computedLabels.length")
|
@discourseComputed("model.computedLabels.length")
|
||||||
twoColumns(labelsLength) {
|
twoColumns(labelsLength) {
|
||||||
return labelsLength === 2;
|
return labelsLength === 2;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"totalsForSample",
|
"totalsForSample",
|
||||||
@ -31,12 +35,12 @@ export default Component.extend({
|
|||||||
.reduce((s, v) => s + v, 0);
|
.reduce((s, v) => s + v, 0);
|
||||||
|
|
||||||
return sum >= 1 && total && datesFiltering;
|
return sum >= 1 && total && datesFiltering;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.total", "options.total", "twoColumns")
|
@discourseComputed("model.total", "options.total", "twoColumns")
|
||||||
showTotal(reportTotal, total, twoColumns) {
|
showTotal(reportTotal, total, twoColumns) {
|
||||||
return reportTotal && total && twoColumns;
|
return reportTotal && total && twoColumns;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"model.{average,data}",
|
"model.{average,data}",
|
||||||
@ -50,17 +54,17 @@ export default Component.extend({
|
|||||||
sampleTotalValue &&
|
sampleTotalValue &&
|
||||||
hasTwoColumns
|
hasTwoColumns
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("totalsForSample.1.value", "model.data.length")
|
@discourseComputed("totalsForSample.1.value", "model.data.length")
|
||||||
averageForSample(totals, count) {
|
averageForSample(totals, count) {
|
||||||
return (totals / count).toFixed(0);
|
return (totals / count).toFixed(0);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.data.length")
|
@discourseComputed("model.data.length")
|
||||||
showSortingUI(dataLength) {
|
showSortingUI(dataLength) {
|
||||||
return dataLength >= 5;
|
return dataLength >= 5;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("totalsForSampleRow", "model.computedLabels")
|
@discourseComputed("totalsForSampleRow", "model.computedLabels")
|
||||||
totalsForSample(row, labels) {
|
totalsForSample(row, labels) {
|
||||||
@ -70,7 +74,7 @@ export default Component.extend({
|
|||||||
computedLabel.property = label.mainProperty;
|
computedLabel.property = label.mainProperty;
|
||||||
return computedLabel;
|
return computedLabel;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.data", "model.computedLabels")
|
@discourseComputed("model.data", "model.computedLabels")
|
||||||
totalsForSampleRow(rows, labels) {
|
totalsForSampleRow(rows, labels) {
|
||||||
@ -98,7 +102,7 @@ export default Component.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return totalsRow;
|
return totalsRow;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("sortLabel", "sortDirection", "model.data.[]")
|
@discourseComputed("sortLabel", "sortDirection", "model.data.[]")
|
||||||
sortedData(sortLabel, sortDirection, data) {
|
sortedData(sortLabel, sortDirection, data) {
|
||||||
@ -118,7 +122,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("sortedData.[]", "perPage", "page")
|
@discourseComputed("sortedData.[]", "perPage", "page")
|
||||||
paginatedData(data, perPage, page) {
|
paginatedData(data, perPage, page) {
|
||||||
@ -128,7 +132,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("model.data", "perPage", "page")
|
@discourseComputed("model.data", "perPage", "page")
|
||||||
pages(data, perPage, page) {
|
pages(data, perPage, page) {
|
||||||
@ -156,19 +160,19 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
changePage(page) {
|
changePage(page) {
|
||||||
this.set("page", page);
|
this.set("page", page);
|
||||||
},
|
}
|
||||||
|
|
||||||
sortByLabel(label) {
|
@action
|
||||||
if (this.sortLabel === label) {
|
sortByLabel(label) {
|
||||||
this.set("sortDirection", this.sortDirection === 1 ? -1 : 1);
|
if (this.sortLabel === label) {
|
||||||
} else {
|
this.set("sortDirection", this.sortDirection === 1 ? -1 : 1);
|
||||||
this.set("sortLabel", label);
|
} else {
|
||||||
}
|
this.set("sortLabel", label);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "tr",
|
@tagName("tr")
|
||||||
});
|
export default class AdminReportTrustLevelCounts extends Component {}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
import { classNameBindings, classNames } from "@ember-decorators/component";
|
||||||
|
import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
|
||||||
import EmberObject, { action, computed } from "@ember/object";
|
import EmberObject, { action, computed } from "@ember/object";
|
||||||
import Report, { DAILY_LIMIT_DAYS, SCHEMA_VERSION } from "admin/models/report";
|
import Report, { DAILY_LIMIT_DAYS, SCHEMA_VERSION } from "admin/models/report";
|
||||||
import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
|
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ReportLoader from "discourse/lib/reports-loader";
|
import ReportLoader from "discourse/lib/reports-loader";
|
||||||
@ -21,51 +22,58 @@ const TABLE_OPTIONS = {
|
|||||||
|
|
||||||
const CHART_OPTIONS = {};
|
const CHART_OPTIONS = {};
|
||||||
|
|
||||||
export default Component.extend({
|
@classNameBindings(
|
||||||
classNameBindings: [
|
"isHidden:hidden",
|
||||||
"isHidden:hidden",
|
"isHidden::is-visible",
|
||||||
"isHidden::is-visible",
|
"isEnabled",
|
||||||
"isEnabled",
|
"isLoading",
|
||||||
"isLoading",
|
"dasherizedDataSourceName"
|
||||||
"dasherizedDataSourceName",
|
)
|
||||||
],
|
@classNames("admin-report")
|
||||||
classNames: ["admin-report"],
|
export default class AdminReport extends Component {
|
||||||
isEnabled: true,
|
isEnabled = true;
|
||||||
disabledLabel: I18n.t("admin.dashboard.disabled"),
|
disabledLabel = I18n.t("admin.dashboard.disabled");
|
||||||
isLoading: false,
|
isLoading = false;
|
||||||
rateLimitationString: null,
|
rateLimitationString = null;
|
||||||
dataSourceName: null,
|
dataSourceName = null;
|
||||||
report: null,
|
report = null;
|
||||||
model: null,
|
model = null;
|
||||||
reportOptions: null,
|
reportOptions = null;
|
||||||
forcedModes: null,
|
forcedModes = null;
|
||||||
showAllReportsLink: false,
|
showAllReportsLink = false;
|
||||||
filters: null,
|
filters = null;
|
||||||
showTrend: false,
|
showTrend = false;
|
||||||
showHeader: true,
|
showHeader = true;
|
||||||
showTitle: true,
|
showTitle = true;
|
||||||
showFilteringUI: false,
|
showFilteringUI = false;
|
||||||
showDatesOptions: alias("model.dates_filtering"),
|
|
||||||
showRefresh: or("showDatesOptions", "model.available_filters.length"),
|
|
||||||
shouldDisplayTrend: and("showTrend", "model.prev_period"),
|
|
||||||
endDate: null,
|
|
||||||
startDate: null,
|
|
||||||
|
|
||||||
init() {
|
@alias("model.dates_filtering") showDatesOptions;
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this._reports = [];
|
@or("showDatesOptions", "model.available_filters.length") showRefresh;
|
||||||
},
|
|
||||||
|
|
||||||
isHidden: computed("siteSettings.dashboard_hidden_reports", function () {
|
@and("showTrend", "model.prev_period") shouldDisplayTrend;
|
||||||
|
|
||||||
|
endDate = null;
|
||||||
|
startDate = null;
|
||||||
|
|
||||||
|
@or("showTimeoutError", "showExceptionError", "showNotFoundError") showError;
|
||||||
|
@equal("model.error", "not_found") showNotFoundError;
|
||||||
|
@equal("model.error", "timeout") showTimeoutError;
|
||||||
|
@equal("model.error", "exception") showExceptionError;
|
||||||
|
@notEmpty("model.data") hasData;
|
||||||
|
|
||||||
|
_reports = [];
|
||||||
|
|
||||||
|
@computed("siteSettings.dashboard_hidden_reports")
|
||||||
|
get isHidden() {
|
||||||
return (this.siteSettings.dashboard_hidden_reports || "")
|
return (this.siteSettings.dashboard_hidden_reports || "")
|
||||||
.split("|")
|
.split("|")
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.includes(this.dataSourceName);
|
.includes(this.dataSourceName);
|
||||||
}),
|
}
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
super.didReceiveAttrs(...arguments);
|
||||||
|
|
||||||
let startDate = moment();
|
let startDate = moment();
|
||||||
if (this.filters && isPresent(this.filters.startDate)) {
|
if (this.filters && isPresent(this.filters.startDate)) {
|
||||||
@ -88,42 +96,35 @@ export default Component.extend({
|
|||||||
} else if (this.dataSourceName) {
|
} else if (this.dataSourceName) {
|
||||||
this._fetchReport();
|
this._fetchReport();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
showError: or("showTimeoutError", "showExceptionError", "showNotFoundError"),
|
|
||||||
showNotFoundError: equal("model.error", "not_found"),
|
|
||||||
showTimeoutError: equal("model.error", "timeout"),
|
|
||||||
showExceptionError: equal("model.error", "exception"),
|
|
||||||
|
|
||||||
hasData: notEmpty("model.data"),
|
|
||||||
|
|
||||||
@discourseComputed("dataSourceName", "model.type")
|
@discourseComputed("dataSourceName", "model.type")
|
||||||
dasherizedDataSourceName(dataSourceName, type) {
|
dasherizedDataSourceName(dataSourceName, type) {
|
||||||
return (dataSourceName || type || "undefined").replace(/_/g, "-");
|
return (dataSourceName || type || "undefined").replace(/_/g, "-");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("dataSourceName", "model.type")
|
@discourseComputed("dataSourceName", "model.type")
|
||||||
dataSource(dataSourceName, type) {
|
dataSource(dataSourceName, type) {
|
||||||
dataSourceName = dataSourceName || type;
|
dataSourceName = dataSourceName || type;
|
||||||
return `/admin/reports/${dataSourceName}`;
|
return `/admin/reports/${dataSourceName}`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("displayedModes.length")
|
@discourseComputed("displayedModes.length")
|
||||||
showModes(displayedModesLength) {
|
showModes(displayedModesLength) {
|
||||||
return displayedModesLength > 1;
|
return displayedModesLength > 1;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentMode")
|
@discourseComputed("currentMode")
|
||||||
isChartMode(currentMode) {
|
isChartMode(currentMode) {
|
||||||
return currentMode === "chart";
|
return currentMode === "chart";
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeGrouping(grouping) {
|
changeGrouping(grouping) {
|
||||||
this.send("refreshReport", {
|
this.send("refreshReport", {
|
||||||
chartGrouping: grouping,
|
chartGrouping: grouping,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentMode", "model.modes", "forcedModes")
|
@discourseComputed("currentMode", "model.modes", "forcedModes")
|
||||||
displayedModes(currentMode, reportModes, forcedModes) {
|
displayedModes(currentMode, reportModes, forcedModes) {
|
||||||
@ -139,12 +140,12 @@ export default Component.extend({
|
|||||||
icon: mode === "table" ? "table" : "signal",
|
icon: mode === "table" ? "table" : "signal",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentMode")
|
@discourseComputed("currentMode")
|
||||||
modeComponent(currentMode) {
|
modeComponent(currentMode) {
|
||||||
return `admin-report-${currentMode.replace(/_/g, "-")}`;
|
return `admin-report-${currentMode.replace(/_/g, "-")}`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"dataSourceName",
|
"dataSourceName",
|
||||||
@ -178,7 +179,7 @@ export default Component.extend({
|
|||||||
.join(":");
|
.join(":");
|
||||||
|
|
||||||
return reportKey;
|
return reportKey;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("options.chartGrouping", "model.chartData.length")
|
@discourseComputed("options.chartGrouping", "model.chartData.length")
|
||||||
chartGroupings(grouping, count) {
|
chartGroupings(grouping, count) {
|
||||||
@ -192,7 +193,7 @@ export default Component.extend({
|
|||||||
class: `chart-grouping ${grouping === id ? "active" : "inactive"}`,
|
class: `chart-grouping ${grouping === id ? "active" : "inactive"}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChangeDateRange(range) {
|
onChangeDateRange(range) {
|
||||||
@ -200,7 +201,7 @@ export default Component.extend({
|
|||||||
startDate: range.from,
|
startDate: range.from,
|
||||||
endDate: range.to,
|
endDate: range.to,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
applyFilter(id, value) {
|
applyFilter(id, value) {
|
||||||
@ -215,7 +216,7 @@ export default Component.extend({
|
|||||||
this.send("refreshReport", {
|
this.send("refreshReport", {
|
||||||
filters: customFilters,
|
filters: customFilters,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
refreshReport(options = {}) {
|
refreshReport(options = {}) {
|
||||||
@ -238,7 +239,7 @@ export default Component.extend({
|
|||||||
? this.get("filters.customFilters")
|
? this.get("filters.customFilters")
|
||||||
: options.filters,
|
: options.filters,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
exportCsv() {
|
exportCsv() {
|
||||||
@ -254,7 +255,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
exportEntity("report", args).then(outputExportResult);
|
exportEntity("report", args).then(outputExportResult);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChangeMode(mode) {
|
onChangeMode(mode) {
|
||||||
@ -263,7 +264,7 @@ export default Component.extend({
|
|||||||
this.send("refreshReport", {
|
this.send("refreshReport", {
|
||||||
chartGrouping: null,
|
chartGrouping: null,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_computeReport() {
|
_computeReport() {
|
||||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||||
@ -306,7 +307,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._renderReport(report, this.forcedModes, this.currentMode);
|
this._renderReport(report, this.forcedModes, this.currentMode);
|
||||||
},
|
}
|
||||||
|
|
||||||
_renderReport(report, forcedModes, currentMode) {
|
_renderReport(report, forcedModes, currentMode) {
|
||||||
const modes = forcedModes ? forcedModes.split(",") : report.modes;
|
const modes = forcedModes ? forcedModes.split(",") : report.modes;
|
||||||
@ -317,11 +318,9 @@ export default Component.extend({
|
|||||||
currentMode,
|
currentMode,
|
||||||
options: this._buildOptions(currentMode, report),
|
options: this._buildOptions(currentMode, report),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_fetchReport() {
|
_fetchReport() {
|
||||||
this._super(...arguments);
|
|
||||||
|
|
||||||
this.setProperties({ isLoading: true, rateLimitationString: null });
|
this.setProperties({ isLoading: true, rateLimitationString: null });
|
||||||
|
|
||||||
next(() => {
|
next(() => {
|
||||||
@ -349,7 +348,7 @@ export default Component.extend({
|
|||||||
|
|
||||||
ReportLoader.enqueue(this.dataSourceName, payload.data, callback);
|
ReportLoader.enqueue(this.dataSourceName, payload.data, callback);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
_buildPayload(facets) {
|
_buildPayload(facets) {
|
||||||
let payload = { data: { facets } };
|
let payload = { data: { facets } };
|
||||||
@ -375,7 +374,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
},
|
}
|
||||||
|
|
||||||
_buildOptions(mode, report) {
|
_buildOptions(mode, report) {
|
||||||
if (mode === "table") {
|
if (mode === "table") {
|
||||||
@ -393,7 +392,7 @@ export default Component.extend({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_loadReport(jsonReport) {
|
_loadReport(jsonReport) {
|
||||||
Report.fillMissingDates(jsonReport, { filledField: "chartData" });
|
Report.fillMissingDates(jsonReport, { filledField: "chartData" });
|
||||||
@ -423,5 +422,5 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Report.create(jsonReport);
|
return Report.create(jsonReport);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
@checked={{this.onlyOverridden}}
|
@checked={{this.onlyOverridden}}
|
||||||
{{on
|
{{on
|
||||||
"click"
|
"click"
|
||||||
(action "onlyOverriddenChanged" value="target.checked")
|
(action this.onlyOverriddenChanged value="target.checked")
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{{i18n "admin.customize.theme.hide_unused_fields"}}
|
{{i18n "admin.customize.theme.hide_unused_fields"}}
|
||||||
@ -125,6 +125,6 @@
|
|||||||
@autofocus="true"
|
@autofocus="true"
|
||||||
@placeholder={{this.placeholder}}
|
@placeholder={{this.placeholder}}
|
||||||
@htmlPlaceholder={{true}}
|
@htmlPlaceholder={{true}}
|
||||||
@save={{action "save"}}
|
@save={{this.save}}
|
||||||
@setWarning={{action "setWarning"}}
|
@setWarning={{action "setWarning"}}
|
||||||
/>
|
/>
|
||||||
@ -3,11 +3,13 @@ import I18n from "I18n";
|
|||||||
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 { isDocumentRTL } from "discourse/lib/text-direction";
|
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||||
import { action } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
import { next } from "@ember/runloop";
|
import { next } from "@ember/runloop";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class AdminThemeEditor extends Component {
|
||||||
warning: null,
|
warning = null;
|
||||||
|
|
||||||
|
@fmt("fieldName", "currentTargetName", "%@|%@") editorId;
|
||||||
|
|
||||||
@discourseComputed("theme.targets", "onlyOverridden", "showAdvanced")
|
@discourseComputed("theme.targets", "onlyOverridden", "showAdvanced")
|
||||||
visibleTargets(targets, onlyOverridden, showAdvanced) {
|
visibleTargets(targets, onlyOverridden, showAdvanced) {
|
||||||
@ -20,7 +22,7 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
return target.edited;
|
return target.edited;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentTargetName", "onlyOverridden", "theme.fields")
|
@discourseComputed("currentTargetName", "onlyOverridden", "theme.fields")
|
||||||
visibleFields(targetName, onlyOverridden, fields) {
|
visibleFields(targetName, onlyOverridden, fields) {
|
||||||
@ -29,7 +31,7 @@ export default Component.extend({
|
|||||||
fields = fields.filter((field) => field.edited);
|
fields = fields.filter((field) => field.edited);
|
||||||
}
|
}
|
||||||
return fields;
|
return fields;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentTargetName", "fieldName")
|
@discourseComputed("currentTargetName", "fieldName")
|
||||||
activeSectionMode(targetName, fieldName) {
|
activeSectionMode(targetName, fieldName) {
|
||||||
@ -43,7 +45,7 @@ export default Component.extend({
|
|||||||
return "scss";
|
return "scss";
|
||||||
}
|
}
|
||||||
return fieldName && fieldName.includes("scss") ? "scss" : "html";
|
return fieldName && fieldName.includes("scss") ? "scss" : "html";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentTargetName", "fieldName")
|
@discourseComputed("currentTargetName", "fieldName")
|
||||||
placeholder(targetName, fieldName) {
|
placeholder(targetName, fieldName) {
|
||||||
@ -58,30 +60,27 @@ export default Component.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("fieldName", "currentTargetName", "theme")
|
@computed("fieldName", "currentTargetName", "theme")
|
||||||
activeSection: {
|
get activeSection() {
|
||||||
get(fieldName, target, model) {
|
return this.theme.getField(this.currentTargetName, this.fieldName);
|
||||||
return model.getField(target, fieldName);
|
}
|
||||||
},
|
|
||||||
set(value, fieldName, target, model) {
|
|
||||||
model.setField(target, fieldName, value);
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
editorId: fmt("fieldName", "currentTargetName", "%@|%@"),
|
set activeSection(value) {
|
||||||
|
this.theme.setField(this.currentTargetName, this.fieldName, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("maximized")
|
@discourseComputed("maximized")
|
||||||
maximizeIcon(maximized) {
|
maximizeIcon(maximized) {
|
||||||
return maximized ? "discourse-compress" : "discourse-expand";
|
return maximized ? "discourse-compress" : "discourse-expand";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("currentTargetName", "theme.targets")
|
@discourseComputed("currentTargetName", "theme.targets")
|
||||||
showAddField(currentTargetName, targets) {
|
showAddField(currentTargetName, targets) {
|
||||||
return targets.find((t) => t.name === currentTargetName).customNames;
|
return targets.find((t) => t.name === currentTargetName).customNames;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"currentTargetName",
|
"currentTargetName",
|
||||||
@ -90,52 +89,45 @@ export default Component.extend({
|
|||||||
)
|
)
|
||||||
error(target, fieldName) {
|
error(target, fieldName) {
|
||||||
return this.theme.getError(target, fieldName);
|
return this.theme.getError(target, fieldName);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleShowAdvanced(event) {
|
toggleShowAdvanced(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.toggleProperty("showAdvanced");
|
this.toggleProperty("showAdvanced");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleAddField(event) {
|
toggleAddField(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.toggleProperty("addingField");
|
this.toggleProperty("addingField");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
toggleMaximize(event) {
|
toggleMaximize(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.toggleProperty("maximized");
|
this.toggleProperty("maximized");
|
||||||
next(() => this.appEvents.trigger("ace:resize"));
|
next(() => this.appEvents.trigger("ace:resize"));
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
cancelAddField() {
|
cancelAddField() {
|
||||||
this.set("addingField", false);
|
this.set("addingField", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
addField(name) {
|
@action
|
||||||
if (!name) {
|
addField(name) {
|
||||||
return;
|
if (!name) {
|
||||||
}
|
return;
|
||||||
name = name.replace(/[^a-zA-Z0-9-_/]/g, "");
|
}
|
||||||
this.theme.setField(this.currentTargetName, name, "");
|
name = name.replace(/[^a-zA-Z0-9-_/]/g, "");
|
||||||
this.setProperties({ newFieldName: "", addingField: false });
|
this.theme.setField(this.currentTargetName, name, "");
|
||||||
this.fieldAdded(this.currentTargetName, name);
|
this.setProperties({ newFieldName: "", addingField: false });
|
||||||
},
|
this.fieldAdded(this.currentTargetName, name);
|
||||||
|
}
|
||||||
|
|
||||||
onlyOverriddenChanged(value) {
|
@action
|
||||||
this.onlyOverriddenChanged(value);
|
setWarning(message) {
|
||||||
},
|
this.set("warning", message);
|
||||||
|
}
|
||||||
save() {
|
}
|
||||||
this.attrs.save();
|
|
||||||
},
|
|
||||||
|
|
||||||
setWarning(message) {
|
|
||||||
this.set("warning", message);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,23 +1,27 @@
|
|||||||
import Component from "@ember/component";
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import { alias, equal } from "@ember/object/computed";
|
import { alias, equal } from "@ember/object/computed";
|
||||||
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("watched-word")
|
||||||
classNames: ["watched-word"],
|
export default class AdminWatchedWord extends Component {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
|
|
||||||
isReplace: equal("actionKey", "replace"),
|
@equal("actionKey", "replace") isReplace;
|
||||||
isTag: equal("actionKey", "tag"),
|
|
||||||
isLink: equal("actionKey", "link"),
|
@equal("actionKey", "tag") isTag;
|
||||||
isCaseSensitive: alias("word.case_sensitive"),
|
|
||||||
|
@equal("actionKey", "link") isLink;
|
||||||
|
|
||||||
|
@alias("word.case_sensitive") isCaseSensitive;
|
||||||
|
|
||||||
@discourseComputed("word.replacement")
|
@discourseComputed("word.replacement")
|
||||||
tags(replacement) {
|
tags(replacement) {
|
||||||
return replacement.split(",");
|
return replacement.split(",");
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
deleteWord() {
|
deleteWord() {
|
||||||
@ -33,5 +37,5 @@ export default Component.extend({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
|
export default class AdminWrapper extends Component {
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
super.didInsertElement(...arguments);
|
||||||
document.querySelector("html").classList.add("admin-area");
|
document.querySelector("html").classList.add("admin-area");
|
||||||
document.querySelector("body").classList.add("admin-interface");
|
document.querySelector("body").classList.add("admin-interface");
|
||||||
},
|
}
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
super.willDestroyElement(...arguments);
|
||||||
document.querySelector("html").classList.remove("admin-area");
|
document.querySelector("html").classList.remove("admin-area");
|
||||||
document.querySelector("body").classList.remove("admin-interface");
|
document.querySelector("body").classList.remove("admin-interface");
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "",
|
@tagName("")
|
||||||
});
|
export default class CancelLink extends Component {}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import { action, computed } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { observes } from "discourse-common/utils/decorators";
|
import { observes } from "@ember-decorators/object";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An input field for a color.
|
An input field for a color.
|
||||||
@ -9,20 +10,20 @@ import { observes } from "discourse-common/utils/decorators";
|
|||||||
@param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor.
|
@param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor.
|
||||||
@params valid is a boolean indicating if the input field is a valid color.
|
@params valid is a boolean indicating if the input field is a valid color.
|
||||||
**/
|
**/
|
||||||
export default Component.extend({
|
@classNames("color-picker")
|
||||||
classNames: ["color-picker"],
|
export default class ColorInput extends Component {
|
||||||
|
onlyHex = true;
|
||||||
|
styleSelection = true;
|
||||||
|
|
||||||
onlyHex: true,
|
@computed("onlyHex")
|
||||||
|
get maxlength() {
|
||||||
styleSelection: true,
|
|
||||||
|
|
||||||
maxlength: computed("onlyHex", function () {
|
|
||||||
return this.onlyHex ? 6 : null;
|
return this.onlyHex ? 6 : null;
|
||||||
}),
|
}
|
||||||
|
|
||||||
normalizedHexValue: computed("hexValue", function () {
|
@computed("hexValue")
|
||||||
|
get normalizedHexValue() {
|
||||||
return this.normalize(this.hexValue);
|
return this.normalize(this.hexValue);
|
||||||
}),
|
}
|
||||||
|
|
||||||
normalize(color) {
|
normalize(color) {
|
||||||
if (this._valid(color)) {
|
if (this._valid(color)) {
|
||||||
@ -40,19 +41,19 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onHexInput(color) {
|
onHexInput(color) {
|
||||||
if (this.attrs.onChangeColor) {
|
if (this.attrs.onChangeColor) {
|
||||||
this.attrs.onChangeColor(this.normalize(color || ""));
|
this.attrs.onChangeColor(this.normalize(color || ""));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onPickerInput(event) {
|
onPickerInput(event) {
|
||||||
this.set("hexValue", event.target.value.replace("#", ""));
|
this.set("hexValue", event.target.value.replace("#", ""));
|
||||||
},
|
}
|
||||||
|
|
||||||
@observes("hexValue", "brightnessValue", "valid")
|
@observes("hexValue", "brightnessValue", "valid")
|
||||||
hexValueChanged() {
|
hexValueChanged() {
|
||||||
@ -65,9 +66,9 @@ export default Component.extend({
|
|||||||
if (this._valid()) {
|
if (this._valid()) {
|
||||||
this.element.querySelector(".picker").value = this.normalize(hex);
|
this.element.querySelector(".picker").value = this.normalize(hex);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_valid(color = this.hexValue) {
|
_valid(color = this.hexValue) {
|
||||||
return /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color);
|
return /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class DashboardNewFeatureItem extends Component {}
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
|
import { classNameBindings, classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action, computed } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("section", "dashboard-new-features")
|
||||||
newFeatures: null,
|
@classNameBindings("hasUnseenFeatures:ordered-first")
|
||||||
classNames: ["section", "dashboard-new-features"],
|
export default class DashboardNewFeatures extends Component {
|
||||||
classNameBindings: ["hasUnseenFeatures:ordered-first"],
|
newFeatures = null;
|
||||||
releaseNotesLink: null,
|
releaseNotesLink = null;
|
||||||
|
|
||||||
init() {
|
constructor() {
|
||||||
this._super(...arguments);
|
super(...arguments);
|
||||||
|
|
||||||
ajax("/admin/dashboard/new-features.json").then((json) => {
|
ajax("/admin/dashboard/new-features.json").then((json) => {
|
||||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
if (this.isDestroying || this.isDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,16 +23,17 @@ export default Component.extend({
|
|||||||
releaseNotesLink: json.release_notes_link,
|
releaseNotesLink: json.release_notes_link,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
columnCountClass: computed("newFeatures", function () {
|
@computed("newFeatures")
|
||||||
|
get columnCountClass() {
|
||||||
return this.newFeatures.length > 2 ? "three-or-more-items" : "";
|
return this.newFeatures.length > 2 ? "three-or-more-items" : "";
|
||||||
}),
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
dismissNewFeatures() {
|
dismissNewFeatures() {
|
||||||
ajax("/admin/dashboard/mark-new-features-as-seen.json", {
|
ajax("/admin/dashboard/mark-new-features-as-seen.json", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
}).then(() => this.set("hasUnseenFeatures", false));
|
}).then(() => this.set("hasUnseenFeatures", false));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class DashboardProblems extends Component {}
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
@content={{this.editorContents}}
|
@content={{this.editorContents}}
|
||||||
@mode={{this.currentEditorMode}}
|
@mode={{this.currentEditorMode}}
|
||||||
@editorId={{this.editorId}}
|
@editorId={{this.editorId}}
|
||||||
@save={{action "save"}}
|
@save={{@save}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="admin-footer">
|
<div class="admin-footer">
|
||||||
|
|||||||
@ -1,17 +1,19 @@
|
|||||||
|
import { action, computed } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { reads } from "@ember/object/computed";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { reads } from "@ember/object/computed";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default class EmailStylesEditor extends Component {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
editorId: reads("fieldName"),
|
|
||||||
|
@reads("fieldName") editorId;
|
||||||
|
|
||||||
@discourseComputed("fieldName")
|
@discourseComputed("fieldName")
|
||||||
currentEditorMode(fieldName) {
|
currentEditorMode(fieldName) {
|
||||||
return fieldName === "css" ? "scss" : fieldName;
|
return fieldName === "css" ? "scss" : fieldName;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("fieldName", "styles.html", "styles.css")
|
@discourseComputed("fieldName", "styles.html", "styles.css")
|
||||||
resetDisabled(fieldName) {
|
resetDisabled(fieldName) {
|
||||||
@ -19,36 +21,31 @@ export default Component.extend({
|
|||||||
this.get(`styles.${fieldName}`) ===
|
this.get(`styles.${fieldName}`) ===
|
||||||
this.get(`styles.default_${fieldName}`)
|
this.get(`styles.default_${fieldName}`)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("styles", "fieldName")
|
@computed("styles", "fieldName")
|
||||||
editorContents: {
|
get editorContents() {
|
||||||
get(styles, fieldName) {
|
return this.styles[this.fieldName];
|
||||||
return styles[fieldName];
|
}
|
||||||
},
|
|
||||||
set(value, styles, fieldName) {
|
|
||||||
styles.setField(fieldName, value);
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
set editorContents(value) {
|
||||||
reset() {
|
this.styles.setField(this.fieldName, value);
|
||||||
this.dialog.yesNoConfirm({
|
return value;
|
||||||
message: I18n.t("admin.customize.email_style.reset_confirm", {
|
}
|
||||||
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`),
|
|
||||||
}),
|
@action
|
||||||
didConfirm: () => {
|
reset() {
|
||||||
this.styles.setField(
|
this.dialog.yesNoConfirm({
|
||||||
this.fieldName,
|
message: I18n.t("admin.customize.email_style.reset_confirm", {
|
||||||
this.styles.get(`default_${this.fieldName}`)
|
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`),
|
||||||
);
|
}),
|
||||||
this.notifyPropertyChange("editorContents");
|
didConfirm: () => {
|
||||||
},
|
this.styles.setField(
|
||||||
});
|
this.fieldName,
|
||||||
},
|
this.styles.get(`default_${this.fieldName}`)
|
||||||
save() {
|
);
|
||||||
this.attrs.save();
|
this.notifyPropertyChange("editorContents");
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -9,15 +9,6 @@
|
|||||||
autofocus={{true}}
|
autofocus={{true}}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="editing-input">
|
|
||||||
<div class="label">{{i18n "admin.embedding.class_name"}}</div>
|
|
||||||
<Input
|
|
||||||
@value={{this.buffered.class_name}}
|
|
||||||
placeholder="class"
|
|
||||||
@enter={{action "save"}}
|
|
||||||
class="class-name"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td class="editing-input">
|
<td class="editing-input">
|
||||||
<div class="label">{{i18n "admin.embedding.allowed_paths"}}</div>
|
<div class="label">{{i18n "admin.embedding.allowed_paths"}}</div>
|
||||||
<Input
|
<Input
|
||||||
@ -54,12 +45,6 @@
|
|||||||
<div class="label">{{i18n "admin.embedding.host"}}</div>
|
<div class="label">{{i18n "admin.embedding.host"}}</div>
|
||||||
{{this.host.host}}
|
{{this.host.host}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
<div class="label">
|
|
||||||
{{i18n "admin.embedding.class_name"}}
|
|
||||||
</div>
|
|
||||||
{{this.host.class_name}}
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
{{i18n "admin.embedding.allowed_paths"}}
|
{{i18n "admin.embedding.allowed_paths"}}
|
||||||
|
|||||||
@ -1,85 +1,91 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { or } from "@ember/object/computed";
|
||||||
import Category from "discourse/models/category";
|
import Category from "discourse/models/category";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
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 { inject as service } from "@ember/service";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { or } from "@ember/object/computed";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Component.extend(bufferedProperty("host"), {
|
@tagName("tr")
|
||||||
editToggled: false,
|
export default class EmbeddableHost extends Component.extend(
|
||||||
tagName: "tr",
|
bufferedProperty("host")
|
||||||
categoryId: null,
|
) {
|
||||||
category: null,
|
@service dialog;
|
||||||
dialog: service(),
|
editToggled = false;
|
||||||
|
categoryId = null;
|
||||||
|
category = null;
|
||||||
|
|
||||||
editing: or("host.isNew", "editToggled"),
|
@or("host.isNew", "editToggled") editing;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
super.init(...arguments);
|
||||||
|
|
||||||
const host = this.host;
|
const host = this.host;
|
||||||
const categoryId = host.category_id || this.site.uncategorized_category_id;
|
const categoryId = host.category_id || this.site.uncategorized_category_id;
|
||||||
const category = Category.findById(categoryId);
|
const category = Category.findById(categoryId);
|
||||||
|
|
||||||
host.set("category", category);
|
host.set("category", category);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("buffered.host", "host.isSaving")
|
@discourseComputed("buffered.host", "host.isSaving")
|
||||||
cantSave(host, isSaving) {
|
cantSave(host, isSaving) {
|
||||||
return isSaving || isEmpty(host);
|
return isSaving || isEmpty(host);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
edit() {
|
edit() {
|
||||||
this.set("categoryId", this.get("host.category.id"));
|
this.set("categoryId", this.get("host.category.id"));
|
||||||
this.set("editToggled", true);
|
this.set("editToggled", true);
|
||||||
},
|
}
|
||||||
|
|
||||||
save() {
|
@action
|
||||||
if (this.cantSave) {
|
save() {
|
||||||
return;
|
if (this.cantSave) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const props = this.buffered.getProperties(
|
const props = this.buffered.getProperties(
|
||||||
"host",
|
"host",
|
||||||
"allowed_paths",
|
"allowed_paths",
|
||||||
"class_name"
|
"class_name"
|
||||||
);
|
);
|
||||||
props.category_id = this.categoryId;
|
props.category_id = this.categoryId;
|
||||||
|
|
||||||
const host = this.host;
|
const host = this.host;
|
||||||
|
|
||||||
host
|
host
|
||||||
.save(props)
|
.save(props)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
host.set("category", Category.findById(this.categoryId));
|
host.set("category", Category.findById(this.categoryId));
|
||||||
this.set("editToggled", false);
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
},
|
|
||||||
|
|
||||||
delete() {
|
|
||||||
return this.dialog.confirm({
|
|
||||||
message: I18n.t("admin.embedding.confirm_delete"),
|
|
||||||
didConfirm: () => {
|
|
||||||
return this.host.destroyRecord().then(() => {
|
|
||||||
this.deleteHost(this.host);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
const host = this.host;
|
|
||||||
if (host.get("isNew")) {
|
|
||||||
this.deleteHost(host);
|
|
||||||
} else {
|
|
||||||
this.rollbackBuffer();
|
|
||||||
this.set("editToggled", false);
|
this.set("editToggled", false);
|
||||||
}
|
})
|
||||||
},
|
.catch(popupAjaxError);
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
@action
|
||||||
|
delete() {
|
||||||
|
return this.dialog.confirm({
|
||||||
|
message: I18n.t("admin.embedding.confirm_delete"),
|
||||||
|
didConfirm: () => {
|
||||||
|
return this.host.destroyRecord().then(() => {
|
||||||
|
this.deleteHost(this.host);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancel() {
|
||||||
|
const host = this.host;
|
||||||
|
if (host.get("isNew")) {
|
||||||
|
this.deleteHost(host);
|
||||||
|
} else {
|
||||||
|
this.rollbackBuffer();
|
||||||
|
this.set("editToggled", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { computed } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("embed-setting")
|
||||||
classNames: ["embed-setting"],
|
export default class EmbeddingSetting extends Component {
|
||||||
|
|
||||||
@discourseComputed("field")
|
@discourseComputed("field")
|
||||||
inputId(field) {
|
inputId(field) {
|
||||||
return dasherize(field);
|
return dasherize(field);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("field")
|
@discourseComputed("field")
|
||||||
translationKey(field) {
|
translationKey(field) {
|
||||||
return `admin.embedding.${field}`;
|
return `admin.embedding.${field}`;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("type")
|
@discourseComputed("type")
|
||||||
isCheckbox(type) {
|
isCheckbox(type) {
|
||||||
return type === "checkbox";
|
return type === "checkbox";
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("value")
|
@computed("value")
|
||||||
checked: {
|
get checked() {
|
||||||
get(value) {
|
return !!this.value;
|
||||||
return !!value;
|
}
|
||||||
},
|
|
||||||
set(value) {
|
set(value) {
|
||||||
this.set("value", value);
|
this.set("value", value);
|
||||||
return value;
|
return value;
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { classNameBindings } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
@ -6,12 +7,12 @@ import { action, set, setProperties } from "@ember/object";
|
|||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNameBindings(":value-list", ":emoji-list")
|
||||||
classNameBindings: [":value-list", ":emoji-list"],
|
export default class EmojiValueList extends Component {
|
||||||
values: null,
|
values = null;
|
||||||
validationMessage: null,
|
validationMessage = null;
|
||||||
emojiPickerIsActive: false,
|
emojiPickerIsActive = false;
|
||||||
isEditorFocused: false,
|
isEditorFocused = false;
|
||||||
|
|
||||||
@discourseComputed("values")
|
@discourseComputed("values")
|
||||||
collection(values) {
|
collection(values) {
|
||||||
@ -28,14 +29,14 @@ export default Component.extend({
|
|||||||
emojiUrl: emojiUrlFor(value),
|
emojiUrl: emojiUrlFor(value),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
closeEmojiPicker() {
|
closeEmojiPicker() {
|
||||||
this.collection.setEach("isEditing", false);
|
this.collection.setEach("isEditing", false);
|
||||||
this.set("emojiPickerIsActive", false);
|
this.set("emojiPickerIsActive", false);
|
||||||
this.set("isEditorFocused", false);
|
this.set("isEditorFocused", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
emojiSelected(code) {
|
emojiSelected(code) {
|
||||||
@ -65,12 +66,12 @@ export default Component.extend({
|
|||||||
|
|
||||||
this.set("emojiPickerIsActive", false);
|
this.set("emojiPickerIsActive", false);
|
||||||
this.set("isEditorFocused", false);
|
this.set("isEditorFocused", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("collection")
|
@discourseComputed("collection")
|
||||||
showUpDownButtons(collection) {
|
showUpDownButtons(collection) {
|
||||||
return collection.length - 1 ? true : false;
|
return collection.length - 1 ? true : false;
|
||||||
},
|
}
|
||||||
|
|
||||||
_splitValues(values) {
|
_splitValues(values) {
|
||||||
if (values && values.length) {
|
if (values && values.length) {
|
||||||
@ -91,7 +92,7 @@ export default Component.extend({
|
|||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
editValue(index) {
|
editValue(index) {
|
||||||
@ -111,12 +112,12 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
removeValue(value) {
|
removeValue(value) {
|
||||||
this._removeValue(value);
|
this._removeValue(value);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
shift(operation, index) {
|
shift(operation, index) {
|
||||||
@ -133,7 +134,7 @@ export default Component.extend({
|
|||||||
this.collection.insertAt(futureIndex, shiftedEmoji);
|
this.collection.insertAt(futureIndex, shiftedEmoji);
|
||||||
|
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_validateInput(input) {
|
_validateInput(input) {
|
||||||
this.set("validationMessage", null);
|
this.set("validationMessage", null);
|
||||||
@ -147,12 +148,12 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
}
|
||||||
|
|
||||||
_removeValue(value) {
|
_removeValue(value) {
|
||||||
this.collection.removeObject(value);
|
this.collection.removeObject(value);
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_replaceValue(index, newValue) {
|
_replaceValue(index, newValue) {
|
||||||
const item = this.collection[index];
|
const item = this.collection[index];
|
||||||
@ -161,9 +162,9 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
set(item, "value", newValue);
|
set(item, "value", newValue);
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_saveValues() {
|
_saveValues() {
|
||||||
this.set("values", this.collection.mapBy("value").join("|"));
|
this.set("values", this.collection.mapBy("value").join("|"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
classNames: ["flag-user-lists"],
|
@classNames("flag-user-lists")
|
||||||
});
|
export default class FlagUserLists extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class FlagUser extends Component {}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<div class="form-templates--form">
|
<div class="form-templates__form">
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label for="template-name">
|
<label for="template-name">
|
||||||
{{i18n "admin.form_templates.new_template_form.name.label"}}
|
{{i18n "admin.form_templates.new_template_form.name.label"}}
|
||||||
@ -6,24 +6,38 @@
|
|||||||
<TextField
|
<TextField
|
||||||
@value={{this.templateName}}
|
@value={{this.templateName}}
|
||||||
@name="template-name"
|
@name="template-name"
|
||||||
@class="form-templates--form-name-input"
|
@class="form-templates__form-name-input"
|
||||||
@placeholderKey="admin.form_templates.new_template_form.name.placeholder"
|
@placeholderKey="admin.form_templates.new_template_form.name.placeholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="control-group form-templates__editor">
|
||||||
<div class="control-group form-templates--quick-insert-field-buttons">
|
<div class="form-templates__quick-insert-field-buttons">
|
||||||
<span>
|
<span>
|
||||||
{{I18n "admin.form_templates.quick_insert_fields.add_new_field"}}
|
{{I18n "admin.form_templates.quick_insert_fields.add_new_field"}}
|
||||||
</span>
|
</span>
|
||||||
{{#each this.quickInsertFields as |field|}}
|
{{#each this.quickInsertFields as |field|}}
|
||||||
|
<DButton
|
||||||
|
@class="btn-flat btn-icon-text quick-insert-{{field.type}}"
|
||||||
|
@icon={{field.icon}}
|
||||||
|
@label="admin.form_templates.quick_insert_fields.{{field.type}}"
|
||||||
|
@action={{this.onInsertField}}
|
||||||
|
@actionParam={{field.type}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
<DButton
|
<DButton
|
||||||
@class="btn-flat btn-icon-text quick-insert-{{field.type}}"
|
class="btn-flat btn-icon-text form-templates__validations-modal-button"
|
||||||
@icon={{field.icon}}
|
@label="admin.form_templates.validations_modal.button_title"
|
||||||
@label="admin.form_templates.quick_insert_fields.{{field.type}}"
|
@icon="check-circle"
|
||||||
@action={{this.onInsertField}}
|
@action={{this.showValidationOptionsModal}}
|
||||||
@actionParam={{field.type}}
|
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
</div>
|
||||||
|
<DButton
|
||||||
|
@class="form-templates__preview-button"
|
||||||
|
@icon="eye"
|
||||||
|
@label="admin.form_templates.new_template_form.preview"
|
||||||
|
@action={{this.showPreview}}
|
||||||
|
@disabled={{this.disablePreviewButton}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
@ -36,7 +50,7 @@
|
|||||||
@label="admin.form_templates.new_template_form.submit"
|
@label="admin.form_templates.new_template_form.submit"
|
||||||
@icon="check"
|
@icon="check"
|
||||||
@action={{this.onSubmit}}
|
@action={{this.onSubmit}}
|
||||||
@disabled={{this.formSubmitted}}
|
@disabled={{this.disableSubmitButton}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DButton
|
<DButton
|
||||||
|
|||||||
@ -6,14 +6,15 @@ import I18n from "I18n";
|
|||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import { templateFormFields } from "admin/lib/template-form-fields";
|
import { templateFormFields } from "admin/lib/template-form-fields";
|
||||||
import FormTemplate from "admin/models/form-template";
|
import FormTemplate from "admin/models/form-template";
|
||||||
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default class FormTemplateForm extends Component {
|
export default class FormTemplateForm extends Component {
|
||||||
@service router;
|
@service router;
|
||||||
@service dialog;
|
@service dialog;
|
||||||
@tracked formSubmitted = false;
|
@tracked formSubmitted = false;
|
||||||
@tracked templateContent = this.args.model?.template || "";
|
@tracked templateContent = this.args.model?.template || "";
|
||||||
|
@tracked templateName = this.args.model?.name || "";
|
||||||
isEditing = this.args.model?.id ? true : false;
|
isEditing = this.args.model?.id ? true : false;
|
||||||
templateName = this.args.model?.name;
|
|
||||||
quickInsertFields = [
|
quickInsertFields = [
|
||||||
{
|
{
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
@ -41,6 +42,17 @@ export default class FormTemplateForm extends Component {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
get disablePreviewButton() {
|
||||||
|
return Boolean(!this.templateName.length || !this.templateContent.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
get disableSubmitButton() {
|
||||||
|
return (
|
||||||
|
Boolean(!this.templateName.length || !this.templateContent.length) ||
|
||||||
|
this.formSubmitted
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
if (!this.formSubmitted) {
|
if (!this.formSubmitted) {
|
||||||
@ -54,27 +66,17 @@ export default class FormTemplateForm extends Component {
|
|||||||
|
|
||||||
if (this.isEditing) {
|
if (this.isEditing) {
|
||||||
postData["id"] = this.args.model.id;
|
postData["id"] = this.args.model.id;
|
||||||
|
|
||||||
FormTemplate.updateTemplate(this.args.model.id, postData)
|
|
||||||
.then(() => {
|
|
||||||
this.formSubmitted = false;
|
|
||||||
this.router.transitionTo("adminCustomizeFormTemplates.index");
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
popupAjaxError(e);
|
|
||||||
this.formSubmitted = false;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
FormTemplate.createTemplate(postData)
|
|
||||||
.then(() => {
|
|
||||||
this.formSubmitted = false;
|
|
||||||
this.router.transitionTo("adminCustomizeFormTemplates.index");
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
popupAjaxError(e);
|
|
||||||
this.formSubmitted = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FormTemplate.createOrUpdateTemplate(postData)
|
||||||
|
.then(() => {
|
||||||
|
this.formSubmitted = false;
|
||||||
|
this.router.transitionTo("adminCustomizeFormTemplates.index");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
popupAjaxError(e);
|
||||||
|
this.formSubmitted = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@ -106,4 +108,33 @@ export default class FormTemplateForm extends Component {
|
|||||||
this.templateContent += `\n${structure}`;
|
this.templateContent += `\n${structure}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
showValidationOptionsModal() {
|
||||||
|
return showModal("admin-form-template-validation-options", {
|
||||||
|
admin: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
showPreview() {
|
||||||
|
const data = {
|
||||||
|
name: this.templateName,
|
||||||
|
template: this.templateContent,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.isEditing) {
|
||||||
|
data["id"] = this.args.model.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormTemplate.validateTemplate(data)
|
||||||
|
.then(() => {
|
||||||
|
return showModal("form-template-form-preview", {
|
||||||
|
model: {
|
||||||
|
content: this.templateContent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
<tr class="admin-list-item">
|
<tr class="admin-list-item">
|
||||||
<td class="col first">{{@template.name}}</td>
|
<td class="col first">{{@template.name}}</td>
|
||||||
|
<td class="col categories">
|
||||||
|
{{#each this.activeCategories as |category|}}
|
||||||
|
{{category-link category}}
|
||||||
|
{{/each}}
|
||||||
|
</td>
|
||||||
<td class="col action">
|
<td class="col action">
|
||||||
<DButton
|
<DButton
|
||||||
@title="admin.form_templates.list_table.actions.view"
|
@title="admin.form_templates.list_table.actions.view"
|
||||||
|
|||||||
@ -9,11 +9,17 @@ import I18n from "I18n";
|
|||||||
export default class FormTemplateRowItem extends Component {
|
export default class FormTemplateRowItem extends Component {
|
||||||
@service router;
|
@service router;
|
||||||
@service dialog;
|
@service dialog;
|
||||||
|
@service site;
|
||||||
|
|
||||||
|
get activeCategories() {
|
||||||
|
return this.site?.categories?.filter((c) =>
|
||||||
|
c["form_template_ids"].includes(this.args.template.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
viewTemplate() {
|
viewTemplate() {
|
||||||
showModal("admin-customize-form-template-view", {
|
showModal("customize-form-template-view", {
|
||||||
admin: true,
|
|
||||||
model: this.args.template,
|
model: this.args.template,
|
||||||
refreshModel: this.args.refreshModel,
|
refreshModel: this.args.refreshModel,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { observes, on } from "discourse-common/utils/decorators";
|
import { observes, on } from "@ember-decorators/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class HighlightedCode extends Component {
|
||||||
@on("didInsertElement")
|
@on("didInsertElement")
|
||||||
@observes("code")
|
@observes("code")
|
||||||
_refresh() {
|
_refresh() {
|
||||||
highlightSyntax(this.element, this.siteSettings, this.session);
|
highlightSyntax(this.element, this.siteSettings, this.session);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("inline-edit")
|
||||||
classNames: ["inline-edit"],
|
export default class InlineEditCheckbox extends Component {
|
||||||
|
buffer = null;
|
||||||
buffer: null,
|
bufferModelId = null;
|
||||||
bufferModelId: null,
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
super.didReceiveAttrs(...arguments);
|
||||||
|
|
||||||
if (this.modelId !== this.bufferModelId) {
|
if (this.modelId !== this.bufferModelId) {
|
||||||
// HACK: The condition above ensures this method is called only when its
|
// HACK: The condition above ensures this method is called only when its
|
||||||
@ -24,21 +24,21 @@ export default Component.extend({
|
|||||||
bufferModelId: this.modelId,
|
bufferModelId: this.modelId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("checked", "buffer")
|
@discourseComputed("checked", "buffer")
|
||||||
changed(checked, buffer) {
|
changed(checked, buffer) {
|
||||||
return !!checked !== !!buffer;
|
return !!checked !== !!buffer;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
apply() {
|
apply() {
|
||||||
this.set("checked", this.buffer);
|
this.set("checked", this.buffer);
|
||||||
this.action();
|
this.action();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
cancel() {
|
cancel() {
|
||||||
this.set("buffer", this.checked);
|
this.set("buffer", this.checked);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
classNames: ["install-theme-item"],
|
@classNames("install-theme-item")
|
||||||
});
|
export default class InstallThemeItem extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { classNames } from "@ember-decorators/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import AdminUser from "admin/models/admin-user";
|
import AdminUser from "admin/models/admin-user";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import EmberObject, { action } from "@ember/object";
|
import EmberObject, { action } from "@ember/object";
|
||||||
@ -6,12 +8,11 @@ import { ajax } from "discourse/lib/ajax";
|
|||||||
import copyText from "discourse/lib/copy-text";
|
import copyText from "discourse/lib/copy-text";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNames("ip-lookup")
|
||||||
classNames: ["ip-lookup"],
|
export default class IpLookup extends Component {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
|
|
||||||
@discourseComputed("other_accounts.length", "totalOthersWithSameIP")
|
@discourseComputed("other_accounts.length", "totalOthersWithSameIP")
|
||||||
otherAccountsToDelete(otherAccountsLength, totalOthersWithSameIP) {
|
otherAccountsToDelete(otherAccountsLength, totalOthersWithSameIP) {
|
||||||
@ -19,101 +20,100 @@ export default Component.extend({
|
|||||||
const total = Math.min(50, totalOthersWithSameIP || 0);
|
const total = Math.min(50, totalOthersWithSameIP || 0);
|
||||||
const visible = Math.min(50, otherAccountsLength || 0);
|
const visible = Math.min(50, otherAccountsLength || 0);
|
||||||
return Math.max(visible, total);
|
return Math.max(visible, total);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
hide(event) {
|
hide(event) {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
this.set("show", false);
|
this.set("show", false);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
lookup() {
|
lookup() {
|
||||||
this.set("show", true);
|
this.set("show", true);
|
||||||
|
|
||||||
if (!this.location) {
|
if (!this.location) {
|
||||||
ajax("/admin/users/ip-info", {
|
ajax("/admin/users/ip-info", {
|
||||||
data: { ip: this.ip },
|
data: { ip: this.ip },
|
||||||
}).then((location) =>
|
}).then((location) => this.set("location", EmberObject.create(location)));
|
||||||
this.set("location", EmberObject.create(location))
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.other_accounts) {
|
if (!this.other_accounts) {
|
||||||
this.set("otherAccountsLoading", true);
|
this.set("otherAccountsLoading", true);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
ip: this.ip,
|
ip: this.ip,
|
||||||
exclude: this.userId,
|
exclude: this.userId,
|
||||||
order: "trust_level DESC",
|
order: "trust_level DESC",
|
||||||
};
|
};
|
||||||
|
|
||||||
ajax("/admin/users/total-others-with-same-ip", {
|
ajax("/admin/users/total-others-with-same-ip", {
|
||||||
data,
|
data,
|
||||||
}).then((result) => this.set("totalOthersWithSameIP", result.total));
|
}).then((result) => this.set("totalOthersWithSameIP", result.total));
|
||||||
|
|
||||||
AdminUser.findAll("active", data).then((users) => {
|
AdminUser.findAll("active", data).then((users) => {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
other_accounts: users,
|
other_accounts: users,
|
||||||
otherAccountsLoading: false,
|
otherAccountsLoading: false,
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
copy() {
|
|
||||||
let text = `IP: ${this.ip}\n`;
|
|
||||||
const location = this.location;
|
|
||||||
if (location) {
|
|
||||||
if (location.hostname) {
|
|
||||||
text += `${I18n.t("ip_lookup.hostname")}: ${location.hostname}\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
text += I18n.t("ip_lookup.location");
|
|
||||||
if (location.location) {
|
|
||||||
text += `: ${location.location}\n`;
|
|
||||||
} else {
|
|
||||||
text += `: ${I18n.t("ip_lookup.location_not_found")}\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (location.organization) {
|
|
||||||
text += I18n.t("ip_lookup.organisation");
|
|
||||||
text += `: ${location.organization}\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const $copyRange = $('<p id="copy-range"></p>');
|
|
||||||
$copyRange.html(text.trim().replace(/\n/g, "<br>"));
|
|
||||||
$(document.body).append($copyRange);
|
|
||||||
if (copyText(text, $copyRange[0])) {
|
|
||||||
this.set("copied", true);
|
|
||||||
discourseLater(() => this.set("copied", false), 2000);
|
|
||||||
}
|
|
||||||
$copyRange.remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteOtherAccounts() {
|
|
||||||
this.dialog.yesNoConfirm({
|
|
||||||
message: I18n.t("ip_lookup.confirm_delete_other_accounts"),
|
|
||||||
didConfirm: () => {
|
|
||||||
this.setProperties({
|
|
||||||
other_accounts: null,
|
|
||||||
otherAccountsLoading: true,
|
|
||||||
totalOthersWithSameIP: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
ajax("/admin/users/delete-others-with-same-ip.json", {
|
|
||||||
type: "DELETE",
|
|
||||||
data: {
|
|
||||||
ip: this.ip,
|
|
||||||
exclude: this.userId,
|
|
||||||
order: "trust_level DESC",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError)
|
|
||||||
.finally(this.send("lookup"));
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
@action
|
||||||
|
copy() {
|
||||||
|
let text = `IP: ${this.ip}\n`;
|
||||||
|
const location = this.location;
|
||||||
|
if (location) {
|
||||||
|
if (location.hostname) {
|
||||||
|
text += `${I18n.t("ip_lookup.hostname")}: ${location.hostname}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
text += I18n.t("ip_lookup.location");
|
||||||
|
if (location.location) {
|
||||||
|
text += `: ${location.location}\n`;
|
||||||
|
} else {
|
||||||
|
text += `: ${I18n.t("ip_lookup.location_not_found")}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.organization) {
|
||||||
|
text += I18n.t("ip_lookup.organisation");
|
||||||
|
text += `: ${location.organization}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const $copyRange = $('<p id="copy-range"></p>');
|
||||||
|
$copyRange.html(text.trim().replace(/\n/g, "<br>"));
|
||||||
|
$(document.body).append($copyRange);
|
||||||
|
if (copyText(text, $copyRange[0])) {
|
||||||
|
this.set("copied", true);
|
||||||
|
discourseLater(() => this.set("copied", false), 2000);
|
||||||
|
}
|
||||||
|
$copyRange.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
deleteOtherAccounts() {
|
||||||
|
this.dialog.yesNoConfirm({
|
||||||
|
message: I18n.t("ip_lookup.confirm_delete_other_accounts"),
|
||||||
|
didConfirm: () => {
|
||||||
|
this.setProperties({
|
||||||
|
other_accounts: null,
|
||||||
|
otherAccountsLoading: true,
|
||||||
|
totalOthersWithSameIP: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
ajax("/admin/users/delete-others-with-same-ip.json", {
|
||||||
|
type: "DELETE",
|
||||||
|
data: {
|
||||||
|
ip: this.ip,
|
||||||
|
exclude: this.userId,
|
||||||
|
order: "trust_level DESC",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(this.send("lookup"));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "tr",
|
@tagName("tr")
|
||||||
});
|
export default class ModerationHistoryItem extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import Permalink from "admin/models/permalink";
|
import Permalink from "admin/models/permalink";
|
||||||
@ -5,16 +7,18 @@ import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
|||||||
import { fmt } from "discourse/lib/computed";
|
import { fmt } from "discourse/lib/computed";
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("")
|
||||||
tagName: "",
|
export default class PermalinkForm extends Component {
|
||||||
dialog: service(),
|
@service dialog;
|
||||||
formSubmitted: false,
|
|
||||||
permalinkType: "topic_id",
|
formSubmitted = false;
|
||||||
permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"),
|
permalinkType = "topic_id";
|
||||||
action: null,
|
|
||||||
permalinkTypeValue: null,
|
@fmt("permalinkType", "admin.permalink.%@") permalinkTypePlaceholder;
|
||||||
|
|
||||||
|
action = null;
|
||||||
|
permalinkTypeValue = null;
|
||||||
|
|
||||||
@discourseComputed
|
@discourseComputed
|
||||||
permalinkTypes() {
|
permalinkTypes() {
|
||||||
@ -25,21 +29,21 @@ export default Component.extend({
|
|||||||
{ id: "tag_name", name: I18n.t("admin.permalink.tag_name") },
|
{ id: "tag_name", name: I18n.t("admin.permalink.tag_name") },
|
||||||
{ id: "external_url", name: I18n.t("admin.permalink.external_url") },
|
{ id: "external_url", name: I18n.t("admin.permalink.external_url") },
|
||||||
];
|
];
|
||||||
},
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
focusPermalink() {
|
focusPermalink() {
|
||||||
schedule("afterRender", () =>
|
schedule("afterRender", () =>
|
||||||
document.querySelector(".permalink-url")?.focus()
|
document.querySelector(".permalink-url")?.focus()
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
submitFormOnEnter(event) {
|
submitFormOnEnter(event) {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
this.onSubmit();
|
this.onSubmit();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
@ -84,5 +88,5 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
export default class Bool extends FilterComponent {
|
||||||
checked: false,
|
checked = false;
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
this._super(...arguments);
|
super.didReceiveAttrs(...arguments);
|
||||||
this.set("checked", !!this.filter.default);
|
this.set("checked", !!this.filter.default);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChange() {
|
onChange() {
|
||||||
this.applyFilter(this.filter.id, !this.checked || undefined);
|
this.applyFilter(this.filter.id, !this.checked || undefined);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
|
import { readOnly } from "@ember/object/computed";
|
||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { readOnly } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
export default class Category extends FilterComponent {
|
||||||
category: readOnly("filter.default"),
|
@readOnly("filter.default") category;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChange(categoryId) {
|
onChange(categoryId) {
|
||||||
this.applyFilter(this.filter.id, categoryId || undefined);
|
this.applyFilter(this.filter.id, categoryId || undefined);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class Filter extends Component {
|
||||||
@action
|
@action
|
||||||
onChange(value) {
|
onChange(value) {
|
||||||
this.applyFilter(this.filter.id, value);
|
this.applyFilter(this.filter.id, value);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import { classNames } from "@ember-decorators/component";
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
|
|
||||||
export default FilterComponent.extend({
|
@classNames("group-filter")
|
||||||
classNames: ["group-filter"],
|
export default class Group extends FilterComponent {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
get groupOptions() {
|
get groupOptions() {
|
||||||
return (this.site.groups || []).map((group) => {
|
return (this.site.groups || []).map((group) => {
|
||||||
return { name: group["name"], value: group["id"] };
|
return { name: group["name"], value: group["id"] };
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@computed("filter.default")
|
@computed("filter.default")
|
||||||
get groupId() {
|
get groupId() {
|
||||||
return this.filter.default ? parseInt(this.filter.default, 10) : null;
|
return this.filter.default ? parseInt(this.filter.default, 10) : null;
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import FilterComponent from "admin/components/report-filters/filter";
|
import FilterComponent from "admin/components/report-filters/filter";
|
||||||
|
|
||||||
export default FilterComponent.extend();
|
export default class List extends FilterComponent {}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class ResumableUpload extends Component {}
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<DButton
|
<DButton
|
||||||
@type="submit"
|
@type="submit"
|
||||||
@class="btn-default"
|
@class="btn-default"
|
||||||
@action={{action "submit"}}
|
@action={{action "submitForm"}}
|
||||||
@disabled={{this.formSubmitted}}
|
@disabled={{this.formSubmitted}}
|
||||||
@label="admin.logs.screened_ips.form.add"
|
@label="admin.logs.screened_ips.form.add"
|
||||||
/>
|
/>
|
||||||
@ -1,9 +1,11 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
|
import { classNames, tagName } from "@ember-decorators/component";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
||||||
import { schedule } from "@ember/runloop";
|
import { schedule } from "@ember/runloop";
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A form to create an IP address that will be blocked or allowed.
|
A form to create an IP address that will be blocked or allowed.
|
||||||
@ -16,12 +18,13 @@ import { inject as service } from "@ember/service";
|
|||||||
as an argument.
|
as an argument.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
export default Component.extend({
|
@tagName("form")
|
||||||
tagName: "form",
|
@classNames("screened-ip-address-form", "inline-form")
|
||||||
dialog: service(),
|
export default class ScreenedIpAddressForm extends Component {
|
||||||
classNames: ["screened-ip-address-form", "inline-form"],
|
@service dialog;
|
||||||
formSubmitted: false,
|
|
||||||
actionName: "block",
|
formSubmitted = false;
|
||||||
|
actionName = "block";
|
||||||
|
|
||||||
@discourseComputed("siteSettings.use_admin_ip_allowlist")
|
@discourseComputed("siteSettings.use_admin_ip_allowlist")
|
||||||
actionNames(adminAllowlistEnabled) {
|
actionNames(adminAllowlistEnabled) {
|
||||||
@ -46,43 +49,42 @@ export default Component.extend({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
focusInput() {
|
focusInput() {
|
||||||
schedule("afterRender", () => {
|
schedule("afterRender", () => {
|
||||||
this.element.querySelector("input").focus();
|
this.element.querySelector("input").focus();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
submit() {
|
submitForm() {
|
||||||
if (!this.formSubmitted) {
|
if (!this.formSubmitted) {
|
||||||
this.set("formSubmitted", true);
|
this.set("formSubmitted", true);
|
||||||
const screenedIpAddress = ScreenedIpAddress.create({
|
const screenedIpAddress = ScreenedIpAddress.create({
|
||||||
ip_address: this.ip_address,
|
ip_address: this.ip_address,
|
||||||
action_name: this.actionName,
|
action_name: this.actionName,
|
||||||
});
|
});
|
||||||
screenedIpAddress
|
screenedIpAddress
|
||||||
.save()
|
.save()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setProperties({ ip_address: "", formSubmitted: false });
|
this.setProperties({ ip_address: "", formSubmitted: false });
|
||||||
this.action(ScreenedIpAddress.create(result.screened_ip_address));
|
this.action(ScreenedIpAddress.create(result.screened_ip_address));
|
||||||
this.focusInput();
|
this.focusInput();
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this.set("formSubmitted", false);
|
this.set("formSubmitted", false);
|
||||||
const message = e.jqXHR.responseJSON?.errors
|
const message = e.jqXHR.responseJSON?.errors
|
||||||
? I18n.t("generic_error_with_reason", {
|
? I18n.t("generic_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({
|
this.dialog.alert({
|
||||||
message,
|
message,
|
||||||
didConfirm: () => this.focusInput(),
|
didConfirm: () => this.focusInput(),
|
||||||
didCancel: () => this.focusInput(),
|
didCancel: () => this.focusInput(),
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
|
import { classNameBindings } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
import { on } from "discourse-common/utils/decorators";
|
import { on } from "@ember-decorators/object";
|
||||||
import { set } from "@ember/object";
|
import { action, set } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNameBindings(":value-list", ":secret-value-list")
|
||||||
classNameBindings: [":value-list", ":secret-value-list"],
|
export default class SecretValueList extends Component {
|
||||||
inputDelimiter: null,
|
inputDelimiter = null;
|
||||||
collection: null,
|
collection = null;
|
||||||
values: null,
|
values = null;
|
||||||
validationMessage: null,
|
validationMessage = null;
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
@on("didReceiveAttrs")
|
||||||
_setupCollection() {
|
_setupCollection() {
|
||||||
@ -19,41 +20,43 @@ export default Component.extend({
|
|||||||
"collection",
|
"collection",
|
||||||
this._splitValues(values, this.inputDelimiter || "\n")
|
this._splitValues(values, this.inputDelimiter || "\n")
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
changeKey(index, event) {
|
changeKey(index, event) {
|
||||||
const newValue = event.target.value;
|
const newValue = event.target.value;
|
||||||
|
|
||||||
if (this._checkInvalidInput(newValue)) {
|
if (this._checkInvalidInput(newValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._replaceValue(index, newValue, "key");
|
this._replaceValue(index, newValue, "key");
|
||||||
},
|
}
|
||||||
|
|
||||||
changeSecret(index, event) {
|
@action
|
||||||
const newValue = event.target.value;
|
changeSecret(index, event) {
|
||||||
|
const newValue = event.target.value;
|
||||||
|
|
||||||
if (this._checkInvalidInput(newValue)) {
|
if (this._checkInvalidInput(newValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._replaceValue(index, newValue, "secret");
|
this._replaceValue(index, newValue, "secret");
|
||||||
},
|
}
|
||||||
|
|
||||||
addValue() {
|
@action
|
||||||
if (this._checkInvalidInput([this.newKey, this.newSecret])) {
|
addValue() {
|
||||||
return;
|
if (this._checkInvalidInput([this.newKey, this.newSecret])) {
|
||||||
}
|
return;
|
||||||
this._addValue(this.newKey, this.newSecret);
|
}
|
||||||
this.setProperties({ newKey: "", newSecret: "" });
|
this._addValue(this.newKey, this.newSecret);
|
||||||
},
|
this.setProperties({ newKey: "", newSecret: "" });
|
||||||
|
}
|
||||||
|
|
||||||
removeValue(value) {
|
@action
|
||||||
this._removeValue(value);
|
removeValue(value) {
|
||||||
},
|
this._removeValue(value);
|
||||||
},
|
}
|
||||||
|
|
||||||
_checkInvalidInput(inputs) {
|
_checkInvalidInput(inputs) {
|
||||||
this.set("validationMessage", null);
|
this.set("validationMessage", null);
|
||||||
@ -66,25 +69,25 @@ export default Component.extend({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_addValue(value, secret) {
|
_addValue(value, secret) {
|
||||||
this.collection.addObject({ key: value, secret });
|
this.collection.addObject({ key: value, secret });
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_removeValue(value) {
|
_removeValue(value) {
|
||||||
const collection = this.collection;
|
const collection = this.collection;
|
||||||
collection.removeObject(value);
|
collection.removeObject(value);
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_replaceValue(index, newValue, keyName) {
|
_replaceValue(index, newValue, keyName) {
|
||||||
let item = this.collection[index];
|
let item = this.collection[index];
|
||||||
set(item, keyName, newValue);
|
set(item, keyName, newValue);
|
||||||
|
|
||||||
this._saveValues();
|
this._saveValues();
|
||||||
},
|
}
|
||||||
|
|
||||||
_saveValues() {
|
_saveValues() {
|
||||||
this.set(
|
this.set(
|
||||||
@ -95,7 +98,7 @@ export default Component.extend({
|
|||||||
})
|
})
|
||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
_splitValues(values, delimiter) {
|
_splitValues(values, delimiter) {
|
||||||
if (values && values.length) {
|
if (values && values.length) {
|
||||||
@ -113,5 +116,5 @@ export default Component.extend({
|
|||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class SettingValidationMessage extends Component {}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
import { tagName } from "@ember-decorators/component";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
export default Component.extend({
|
|
||||||
tagName: "",
|
@tagName("")
|
||||||
});
|
export default class SilenceDetails extends Component {}
|
||||||
|
|||||||
@ -1,34 +1,37 @@
|
|||||||
|
import { classNameBindings } from "@ember-decorators/component";
|
||||||
|
import { empty } from "@ember/object/computed";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { empty } from "@ember/object/computed";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
import { on } from "@ember-decorators/object";
|
||||||
|
|
||||||
export default Component.extend({
|
@classNameBindings(":simple-list", ":value-list")
|
||||||
classNameBindings: [":simple-list", ":value-list"],
|
export default class SimpleList extends Component {
|
||||||
inputEmpty: empty("newValue"),
|
@empty("newValue") inputEmpty;
|
||||||
inputDelimiter: null,
|
|
||||||
newValue: "",
|
inputDelimiter = null;
|
||||||
collection: null,
|
newValue = "";
|
||||||
values: null,
|
collection = null;
|
||||||
|
values = null;
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
@on("didReceiveAttrs")
|
||||||
_setupCollection() {
|
_setupCollection() {
|
||||||
this.set("collection", this._splitValues(this.values, this.inputDelimiter));
|
this.set("collection", this._splitValues(this.values, this.inputDelimiter));
|
||||||
},
|
}
|
||||||
|
|
||||||
keyDown(event) {
|
keyDown(event) {
|
||||||
if (event.which === 13) {
|
if (event.which === 13) {
|
||||||
this.addValue(this.newValue);
|
this.addValue(this.newValue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeValue(index, event) {
|
changeValue(index, event) {
|
||||||
this.collection.replace(index, 1, [event.target.value]);
|
this.collection.replace(index, 1, [event.target.value]);
|
||||||
this.collection.arrayContentDidChange(index);
|
this.collection.arrayContentDidChange(index);
|
||||||
this._onChange();
|
this._onChange();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
addValue(newValue) {
|
addValue(newValue) {
|
||||||
@ -39,13 +42,13 @@ export default Component.extend({
|
|||||||
this.set("newValue", null);
|
this.set("newValue", null);
|
||||||
this.collection.addObject(newValue);
|
this.collection.addObject(newValue);
|
||||||
this._onChange();
|
this._onChange();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
removeValue(value) {
|
removeValue(value) {
|
||||||
this.collection.removeObject(value);
|
this.collection.removeObject(value);
|
||||||
this._onChange();
|
this._onChange();
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
shift(operation, index) {
|
shift(operation, index) {
|
||||||
@ -62,20 +65,20 @@ export default Component.extend({
|
|||||||
this.collection.insertAt(futureIndex, shiftedValue);
|
this.collection.insertAt(futureIndex, shiftedValue);
|
||||||
|
|
||||||
this._onChange();
|
this._onChange();
|
||||||
},
|
}
|
||||||
|
|
||||||
_onChange() {
|
_onChange() {
|
||||||
this.onChange?.(this.collection);
|
this.onChange?.(this.collection);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("collection")
|
@discourseComputed("collection")
|
||||||
showUpDownButtons(collection) {
|
showUpDownButtons(collection) {
|
||||||
return collection.length - 1 ? true : false;
|
return collection.length - 1 ? true : false;
|
||||||
},
|
}
|
||||||
|
|
||||||
_splitValues(values, delimiter) {
|
_splitValues(values, delimiter) {
|
||||||
return values && values.length
|
return values && values.length
|
||||||
? values.split(delimiter || "\n").filter(Boolean)
|
? values.split(delimiter || "\n").filter(Boolean)
|
||||||
: [];
|
: [];
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class SiteCustomizationChangeDetails extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class SiteCustomizationChangeField extends Component {}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<h3>
|
<h3>
|
||||||
|
{{this.settingName}}
|
||||||
|
|
||||||
{{#if this.staffLogFilter}}
|
{{#if this.staffLogFilter}}
|
||||||
{{this.settingName}}
|
|
||||||
<LinkTo
|
<LinkTo
|
||||||
@route="adminLogs.staffActionLogs"
|
@route="adminLogs.staffActionLogs"
|
||||||
@query={{hash filters=this.staffLogFilter force_refresh=true}}
|
@query={{hash filters=this.staffLogFilter force_refresh=true}}
|
||||||
@ -11,17 +12,18 @@
|
|||||||
{{d-icon "history"}}
|
{{d-icon "history"}}
|
||||||
</span>
|
</span>
|
||||||
</LinkTo>
|
</LinkTo>
|
||||||
{{else}}
|
|
||||||
{{this.settingName}}
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{{#if this.defaultIsAvailable}}
|
{{#if this.defaultIsAvailable}}
|
||||||
<a
|
<DButton
|
||||||
href
|
class="btn-link"
|
||||||
onClick={{action "setDefaultValues"}}
|
@action={{this.setDefaultValues}}
|
||||||
>{{this.setting.setDefaultValuesLabel}}</a>
|
@translatedLabel={{this.setting.setDefaultValuesLabel}}
|
||||||
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-value">
|
<div class="setting-value">
|
||||||
{{component
|
{{component
|
||||||
this.componentName
|
this.componentName
|
||||||
@ -33,18 +35,20 @@
|
|||||||
allowAny=this.allowAny
|
allowAny=this.allowAny
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if this.dirty}}
|
{{#if this.dirty}}
|
||||||
<div class="setting-controls">
|
<div class="setting-controls">
|
||||||
<DButton @class="ok" @action={{action "update"}} @icon="check" />
|
<DButton class="ok" @action={{this.update}} @icon="check" />
|
||||||
<DButton @class="cancel" @action={{action "cancel"}} @icon="times" />
|
<DButton class="cancel" @action={{this.cancel}} @icon="times" />
|
||||||
</div>
|
</div>
|
||||||
{{else if this.setting.overridden}}
|
{{else if this.setting.overridden}}
|
||||||
{{#if this.setting.secret}}
|
{{#if this.setting.secret}}
|
||||||
<DButton @action={{action "toggleSecret"}} @icon="far-eye-slash" />
|
<DButton @action={{this.toggleSecret}} @icon="far-eye-slash" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<DButton
|
<DButton
|
||||||
@class="btn-default undo"
|
class="btn-default undo"
|
||||||
@action={{action "resetDefault"}}
|
@action={{this.resetDefault}}
|
||||||
@icon="undo"
|
@icon="undo"
|
||||||
@label="admin.settings.reset"
|
@label="admin.settings.reset"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
|
import { readOnly } from "@ember/object/computed";
|
||||||
import BufferedContent from "discourse/mixins/buffered-content";
|
import BufferedContent from "discourse/mixins/buffered-content";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import SettingComponent from "admin/mixins/setting-component";
|
import SettingComponent from "admin/mixins/setting-component";
|
||||||
import SiteSetting from "admin/models/site-setting";
|
import SiteSetting from "admin/models/site-setting";
|
||||||
import { readOnly } from "@ember/object/computed";
|
|
||||||
|
|
||||||
export default Component.extend(BufferedContent, SettingComponent, {
|
export default class SiteSettingComponent extends Component.extend(
|
||||||
updateExistingUsers: null,
|
BufferedContent,
|
||||||
|
SettingComponent
|
||||||
|
) {
|
||||||
|
updateExistingUsers = null;
|
||||||
|
|
||||||
|
@readOnly("setting.staffLogFilter") staffLogFilter;
|
||||||
|
|
||||||
_save() {
|
_save() {
|
||||||
const setting = this.buffered;
|
const setting = this.buffered;
|
||||||
return SiteSetting.update(setting.get("setting"), setting.get("value"), {
|
return SiteSetting.update(setting.get("setting"), setting.get("value"), {
|
||||||
updateExistingUsers: this.updateExistingUsers,
|
updateExistingUsers: this.updateExistingUsers,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
}
|
||||||
staffLogFilter: readOnly("setting.staffLogFilter"),
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,19 +1,18 @@
|
|||||||
|
import { computed } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
|
||||||
import { isEmpty } from "@ember/utils";
|
import { isEmpty } from "@ember/utils";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class Bool extends Component {
|
||||||
@discourseComputed("value")
|
@computed("value")
|
||||||
enabled: {
|
get enabled() {
|
||||||
get(value) {
|
if (isEmpty(this.value)) {
|
||||||
if (isEmpty(value)) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
return this.value.toString() === "true";
|
||||||
return value.toString() === "true";
|
}
|
||||||
},
|
|
||||||
set(value) {
|
set enabled(value) {
|
||||||
this.set("value", value ? "true" : "false");
|
this.set("value", value ? "true" : "false");
|
||||||
return value;
|
return value;
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
|
import { action, computed } from "@ember/object";
|
||||||
import Category from "discourse/models/category";
|
import Category from "discourse/models/category";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default class CategoryList extends Component {
|
||||||
selectedCategories: computed("value", function () {
|
@computed("value")
|
||||||
|
get selectedCategories() {
|
||||||
return Category.findByIds(this.value.split("|").filter(Boolean));
|
return Category.findByIds(this.value.split("|").filter(Boolean));
|
||||||
}),
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onChangeSelectedCategories(value) {
|
onChangeSelectedCategories(value) {
|
||||||
this.set("value", (value || []).mapBy("id").join("|"));
|
this.set("value", (value || []).mapBy("id").join("|"));
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class Category extends Component {}
|
||||||
|
|||||||
@ -24,8 +24,9 @@ function RGBToHex(rgb) {
|
|||||||
return "#" + r + g + b;
|
return "#" + r + g + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Component.extend({
|
export default class Color extends Component {
|
||||||
valid: computed("value", function () {
|
@computed("value")
|
||||||
|
get valid() {
|
||||||
let value = this.value.toLowerCase();
|
let value = this.value.toLowerCase();
|
||||||
|
|
||||||
let testColor = new Option().style;
|
let testColor = new Option().style;
|
||||||
@ -43,10 +44,10 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return testColor.color && hexifiedColor === value;
|
return testColor.color && hexifiedColor === value;
|
||||||
}),
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChangeColor(color) {
|
onChangeColor(color) {
|
||||||
this.set("value", color);
|
this.set("value", color);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,40 +1,36 @@
|
|||||||
|
import { action, computed } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
import { makeArray } from "discourse-common/lib/helpers";
|
import { makeArray } from "discourse-common/lib/helpers";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class CompactList extends Component {
|
||||||
tokenSeparator: "|",
|
tokenSeparator = "|";
|
||||||
|
createdChoices = null;
|
||||||
|
|
||||||
createdChoices: null,
|
@computed("value")
|
||||||
|
get settingValue() {
|
||||||
settingValue: computed("value", function () {
|
|
||||||
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
||||||
}),
|
}
|
||||||
|
|
||||||
settingChoices: computed(
|
@computed("settingValue", "setting.choices.[]", "createdChoices.[]")
|
||||||
"settingValue",
|
get settingChoices() {
|
||||||
"setting.choices.[]",
|
return [
|
||||||
"createdChoices.[]",
|
...new Set([
|
||||||
function () {
|
...makeArray(this.settingValue),
|
||||||
return [
|
...makeArray(this.setting.choices),
|
||||||
...new Set([
|
...makeArray(this.createdChoices),
|
||||||
...makeArray(this.settingValue),
|
]),
|
||||||
...makeArray(this.setting.choices),
|
];
|
||||||
...makeArray(this.createdChoices),
|
}
|
||||||
]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onChangeListSetting(value) {
|
onChangeListSetting(value) {
|
||||||
this.set("value", value.join(this.tokenSeparator));
|
this.set("value", value.join(this.tokenSeparator));
|
||||||
},
|
}
|
||||||
|
|
||||||
onChangeChoices(choices) {
|
@action
|
||||||
this.set("createdChoices", [
|
onChangeChoices(choices) {
|
||||||
...new Set([...makeArray(this.createdChoices), ...makeArray(choices)]),
|
this.set("createdChoices", [
|
||||||
]);
|
...new Set([...makeArray(this.createdChoices), ...makeArray(choices)]),
|
||||||
},
|
]);
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class EmojiList extends Component {}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class Enum extends Component {}
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
|
import { action, computed } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { computed } from "@ember/object";
|
|
||||||
|
|
||||||
export default Component.extend({
|
export default class GroupList extends Component {
|
||||||
tokenSeparator: "|",
|
tokenSeparator = "|";
|
||||||
|
nameProperty = "name";
|
||||||
|
valueProperty = "id";
|
||||||
|
|
||||||
nameProperty: "name",
|
@computed("site.groups")
|
||||||
valueProperty: "id",
|
get groupChoices() {
|
||||||
|
|
||||||
groupChoices: computed("site.groups", function () {
|
|
||||||
return (this.site.groups || []).map((g) => {
|
return (this.site.groups || []).map((g) => {
|
||||||
return { name: g.name, id: g.id.toString() };
|
return { name: g.name, id: g.id.toString() };
|
||||||
});
|
});
|
||||||
}),
|
}
|
||||||
|
|
||||||
settingValue: computed("value", function () {
|
@computed("value")
|
||||||
|
get settingValue() {
|
||||||
return (this.value || "").split(this.tokenSeparator).filter(Boolean);
|
return (this.value || "").split(this.tokenSeparator).filter(Boolean);
|
||||||
}),
|
}
|
||||||
|
|
||||||
actions: {
|
@action
|
||||||
onChangeGroupListSetting(value) {
|
onChangeGroupListSetting(value) {
|
||||||
this.set("value", value.join(this.tokenSeparator));
|
this.set("value", value.join(this.tokenSeparator));
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action, computed } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class HostList extends Component {
|
||||||
tokenSeparator: "|",
|
tokenSeparator = "|";
|
||||||
choices: null,
|
choices = null;
|
||||||
|
|
||||||
@computed("value")
|
@computed("value")
|
||||||
get settingValue() {
|
get settingValue() {
|
||||||
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChange(value) {
|
onChange(value) {
|
||||||
@ -17,5 +17,5 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.set("value", value.join(this.tokenSeparator));
|
this.set("value", value.join(this.tokenSeparator));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class List extends Component {}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action, computed } from "@ember/object";
|
import { action, computed } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class NamedList extends Component {
|
||||||
tokenSeparator: "|",
|
tokenSeparator = "|";
|
||||||
|
|
||||||
@computed("value")
|
@computed("value")
|
||||||
get settingValue() {
|
get settingValue() {
|
||||||
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
|
||||||
},
|
}
|
||||||
|
|
||||||
@computed("setting.choices.[]", "settingValue")
|
@computed("setting.choices.[]", "settingValue")
|
||||||
get settingChoices() {
|
get settingChoices() {
|
||||||
@ -24,10 +24,10 @@ export default Component.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return choices;
|
return choices;
|
||||||
},
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChangeListSetting(value) {
|
onChangeListSetting(value) {
|
||||||
this.set("value", value.join(this.tokenSeparator));
|
this.set("value", value.join(this.tokenSeparator));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class SecretList extends Component {}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class SimpleList extends Component {
|
||||||
inputDelimiter: "|",
|
inputDelimiter = "|";
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onChange(value) {
|
onChange(value) {
|
||||||
this.set("value", value.join(this.inputDelimiter || "\n"));
|
this.set("value", value.join(this.inputDelimiter || "\n"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { action } from "@ember/object";
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class String extends Component {
|
||||||
@action
|
@action
|
||||||
launchJsonEditorModal() {
|
launchJsonEditorModal() {
|
||||||
const schemaModal = showModal("json-schema-editor", {
|
const schemaModal = showModal("json-schema-editor", {
|
||||||
@ -16,5 +16,5 @@ export default Component.extend({
|
|||||||
schemaModal.set("onClose", () => {
|
schemaModal.set("onClose", () => {
|
||||||
this.set("value", schemaModal.model.value);
|
this.set("value", schemaModal.model.value);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -2,16 +2,14 @@ import Component from "@ember/component";
|
|||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class TagList extends Component {
|
||||||
@discourseComputed("value")
|
@discourseComputed("value")
|
||||||
selectedTags: {
|
selectedTags(value) {
|
||||||
get(value) {
|
return value.split("|").filter(Boolean);
|
||||||
return value.split("|").filter(Boolean);
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeSelectedTags(tags) {
|
changeSelectedTags(tags) {
|
||||||
this.set("value", tags.join("|"));
|
this.set("value", tags.join("|"));
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class Upload extends Component {}
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
|
import { action } from "@ember/object";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import showModal from "discourse/lib/show-modal";
|
||||||
|
|
||||||
export default Component.extend({
|
export default class UploadedImageList extends Component {
|
||||||
actions: {
|
@action
|
||||||
showUploadModal({ value, setting }) {
|
showUploadModal({ value, setting }) {
|
||||||
showModal("admin-uploaded-image-list", {
|
showModal("admin-uploaded-image-list", {
|
||||||
admin: true,
|
admin: true,
|
||||||
title: `admin.site_settings.${setting.setting}.title`,
|
title: `admin.site_settings.${setting.setting}.title`,
|
||||||
model: { value, setting },
|
model: { value, setting },
|
||||||
}).setProperties({
|
}).setProperties({
|
||||||
save: (v) => this.set("value", v),
|
save: (v) => this.set("value", v),
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
|
||||||
export default Component.extend({});
|
export default class UrlList extends Component {}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user