Compare commits
4 Commits
main
...
admin-comp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
217abaf446 | ||
|
|
b229e7a865 | ||
|
|
cbc47a7af9 | ||
|
|
f1c8aef911 |
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')"
|
||||
name: ${{ matrix.target }} ${{ matrix.build_type }} ${{ matrix.ruby }}
|
||||
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.1') && '-ruby-3.1.0' || '' }}
|
||||
container: discourse/discourse_test:slim${{ (matrix.build_type == 'frontend' || matrix.build_type == 'system') && '-browsers' || '' }}${{ (matrix.ruby == '3.2') && '-ruby-3.2.0' || '' }}
|
||||
timeout-minutes: 20
|
||||
|
||||
env:
|
||||
@ -38,7 +38,7 @@ jobs:
|
||||
matrix:
|
||||
build_type: [backend, frontend, system, annotations]
|
||||
target: [core, plugins]
|
||||
ruby: ['3.2']
|
||||
ruby: ['3.1']
|
||||
exclude:
|
||||
- build_type: annotations
|
||||
target: plugins
|
||||
@ -159,22 +159,6 @@ jobs:
|
||||
path: tmp/turbo_rspec_runtime.log
|
||||
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
|
||||
if: matrix.build_type == 'backend' && matrix.target == 'core'
|
||||
run: bin/turbo_rspec --verbose
|
||||
@ -198,11 +182,11 @@ jobs:
|
||||
|
||||
- name: Core System Tests
|
||||
if: matrix.build_type == 'system' && matrix.target == 'core'
|
||||
run: bin/rspec spec/system
|
||||
run: PARALLEL_TEST_PROCESSORS=1 bin/turbo_rspec --verbose spec/system
|
||||
|
||||
- name: Plugin System Tests
|
||||
if: matrix.build_type == 'system' && matrix.target == 'plugins'
|
||||
run: LOAD_PLUGINS=1 bin/rspec plugins/*/spec/system
|
||||
run: LOAD_PLUGINS=1 PARALLEL_TEST_PROCESSORS=1 bin/turbo_rspec --verbose plugins/*/spec/system
|
||||
|
||||
- name: Upload failed system test screenshots
|
||||
uses: actions/upload-artifact@v3
|
||||
|
||||
@ -7,7 +7,3 @@ Discourse/NoAddReferenceOrAliasesActiveRecordMigration:
|
||||
|
||||
Discourse/NoResetColumnInformationInMigrations:
|
||||
Enabled: true
|
||||
|
||||
Lint/Debugger:
|
||||
Exclude:
|
||||
- script/**/*
|
||||
|
||||
@ -1 +1 @@
|
||||
3.2.1
|
||||
3.1.3
|
||||
|
||||
@ -15,7 +15,7 @@ module.exports = {
|
||||
"directory-item-value",
|
||||
"directory-table-header-title",
|
||||
"loading-spinner",
|
||||
"directory-item-label",
|
||||
"mobile-directory-item-label",
|
||||
],
|
||||
},
|
||||
"no-implicit-this": {
|
||||
|
||||
4
Gemfile
4
Gemfile
@ -18,7 +18,7 @@ else
|
||||
# this allows us to include the bits of rails we use without pieces we do not.
|
||||
#
|
||||
# To issue a rails update bump the version number here
|
||||
rails_version = "7.0.4.3"
|
||||
rails_version = "7.0.4.1"
|
||||
gem "actionmailer", rails_version
|
||||
gem "actionpack", rails_version
|
||||
gem "actionview", rails_version
|
||||
@ -279,5 +279,3 @@ gem "webrick", require: false
|
||||
|
||||
# Workaround until Ruby ships with cgi version 0.3.6 or higher.
|
||||
gem "cgi", ">= 0.3.6", require: false
|
||||
|
||||
gem "tzinfo-data"
|
||||
|
||||
122
Gemfile.lock
122
Gemfile.lock
@ -17,25 +17,25 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
activejob (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
actionmailer (7.0.4.1)
|
||||
actionpack (= 7.0.4.1)
|
||||
actionview (= 7.0.4.1)
|
||||
activejob (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
actionpack (7.0.4.1)
|
||||
actionview (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
rack (~> 2.0, >= 2.2.0)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
actionview (7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
@ -44,15 +44,15 @@ GEM
|
||||
actionview (>= 6.0.a)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activejob (7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activerecord (7.0.4.3)
|
||||
activemodel (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activesupport (7.0.4.3)
|
||||
activemodel (7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
activerecord (7.0.4.1)
|
||||
activemodel (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
activesupport (7.0.4.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@ -110,7 +110,7 @@ GEM
|
||||
chunky_png (1.4.0)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.2.2)
|
||||
concurrent-ruby (1.2.0)
|
||||
connection_pool (2.3.0)
|
||||
cose (1.3.0)
|
||||
cbor (~> 0.5.9)
|
||||
@ -157,7 +157,7 @@ GEM
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-net_http (3.0.2)
|
||||
faraday-retry (2.1.0)
|
||||
faraday-retry (2.0.0)
|
||||
faraday (~> 2.0)
|
||||
fast_blank (1.0.1)
|
||||
fast_xs (0.8.0)
|
||||
@ -167,11 +167,10 @@ GEM
|
||||
gc_tracer (1.5.1)
|
||||
globalid (1.1.0)
|
||||
activesupport (>= 5.0)
|
||||
google-protobuf (3.22.2)
|
||||
google-protobuf (3.22.2-aarch64-linux)
|
||||
google-protobuf (3.22.2-arm64-darwin)
|
||||
google-protobuf (3.22.2-x86_64-darwin)
|
||||
google-protobuf (3.22.2-x86_64-linux)
|
||||
google-protobuf (3.22.0)
|
||||
google-protobuf (3.22.0-arm64-darwin)
|
||||
google-protobuf (3.22.0-x86_64-darwin)
|
||||
google-protobuf (3.22.0-x86_64-linux)
|
||||
guess_html_encoding (0.0.11)
|
||||
hana (1.3.7)
|
||||
hashdiff (1.0.1)
|
||||
@ -219,7 +218,7 @@ GEM
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.12.2)
|
||||
logster (2.11.4)
|
||||
loofah (2.19.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
@ -240,10 +239,10 @@ GEM
|
||||
mini_sql (1.4.0)
|
||||
mini_suffix (0.3.3)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.18.0)
|
||||
minitest (5.17.0)
|
||||
mocha (2.0.2)
|
||||
ruby2_keywords (>= 0.0.5)
|
||||
msgpack (1.6.1)
|
||||
msgpack (1.6.0)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
mustache (1.1.1)
|
||||
@ -312,10 +311,10 @@ GEM
|
||||
parallel (1.22.1)
|
||||
parallel_tests (4.2.0)
|
||||
parallel
|
||||
parser (3.2.1.1)
|
||||
parser (3.2.1.0)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.4.6)
|
||||
prettier_print (1.2.1)
|
||||
pg (1.4.5)
|
||||
prettier_print (1.2.0)
|
||||
progress (3.6.0)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
@ -326,15 +325,15 @@ GEM
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (5.0.1)
|
||||
puma (6.1.1)
|
||||
puma (6.1.0)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.6.2)
|
||||
rack (2.2.6.4)
|
||||
rack (2.2.6.2)
|
||||
rack-mini-profiler (3.0.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (3.0.5)
|
||||
rack
|
||||
rack-test (2.1.0)
|
||||
rack-test (2.0.2)
|
||||
rack (>= 1.3)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
@ -348,15 +347,15 @@ GEM
|
||||
rails_multisite (4.0.1)
|
||||
activerecord (> 5.0, < 7.1)
|
||||
railties (> 5.0, < 7.1)
|
||||
railties (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
railties (7.0.4.1)
|
||||
actionpack (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
zeitwerk (~> 2.5)
|
||||
rainbow (3.1.1)
|
||||
raindrops (0.20.1)
|
||||
raindrops (0.20.0)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
@ -391,7 +390,7 @@ GEM
|
||||
rspec-html-matchers (0.10.0)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a)
|
||||
rspec-mocks (3.12.4)
|
||||
rspec-mocks (3.12.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.12.0)
|
||||
rspec-rails (6.0.1)
|
||||
@ -412,28 +411,28 @@ GEM
|
||||
rspec-core (>= 2.14)
|
||||
rtlcss (0.2.0)
|
||||
mini_racer (~> 0.6.3)
|
||||
rubocop (1.48.1)
|
||||
rubocop (1.44.1)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.2.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.26.0, < 2.0)
|
||||
rubocop-ast (>= 1.24.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.27.0)
|
||||
rubocop-ast (1.26.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-capybara (2.17.1)
|
||||
rubocop-capybara (2.17.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-discourse (3.2.0)
|
||||
rubocop-discourse (3.0.3)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.19.0)
|
||||
rubocop-rspec (2.18.1)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-capybara (~> 2.17)
|
||||
ruby-prof (1.6.1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-prof (1.5.0)
|
||||
ruby-progressbar (1.11.0)
|
||||
ruby-readability (0.7.0)
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
@ -442,16 +441,16 @@ GEM
|
||||
sanitize (6.0.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
sass-embedded (1.59.2)
|
||||
sass-embedded (1.58.3)
|
||||
google-protobuf (~> 3.21)
|
||||
rake (>= 10.0.0)
|
||||
sass-embedded (1.59.2-aarch64-linux-gnu)
|
||||
sass-embedded (1.58.3-aarch64-linux-gnu)
|
||||
google-protobuf (~> 3.21)
|
||||
sass-embedded (1.59.2-arm64-darwin)
|
||||
sass-embedded (1.58.3-arm64-darwin)
|
||||
google-protobuf (~> 3.21)
|
||||
sass-embedded (1.59.2-x86_64-darwin)
|
||||
sass-embedded (1.58.3-x86_64-darwin)
|
||||
google-protobuf (~> 3.21)
|
||||
sass-embedded (1.59.2-x86_64-linux-gnu)
|
||||
sass-embedded (1.58.3-x86_64-linux-gnu)
|
||||
google-protobuf (~> 3.21)
|
||||
selenium-webdriver (4.8.1)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
@ -478,7 +477,7 @@ GEM
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.23)
|
||||
syntax_tree (6.0.2)
|
||||
syntax_tree (6.0.0)
|
||||
prettier_print (>= 1.2.0)
|
||||
syntax_tree-disable_ternary (1.0.0)
|
||||
test-prof (1.2.0)
|
||||
@ -487,8 +486,6 @@ GEM
|
||||
timeout (0.3.2)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2022.7)
|
||||
tzinfo (>= 1.0.0)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
@ -534,14 +531,14 @@ PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
actionmailer (= 7.0.4.1)
|
||||
actionpack (= 7.0.4.1)
|
||||
actionview (= 7.0.4.1)
|
||||
actionview_precompiler
|
||||
active_model_serializers (~> 0.8.3)
|
||||
activemodel (= 7.0.4.3)
|
||||
activerecord (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activemodel (= 7.0.4.1)
|
||||
activerecord (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
addressable
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
@ -627,7 +624,7 @@ DEPENDENCIES
|
||||
rack-protection
|
||||
rails_failover
|
||||
rails_multisite
|
||||
railties (= 7.0.4.3)
|
||||
railties (= 7.0.4.1)
|
||||
rake
|
||||
rb-fsevent
|
||||
rbtrace
|
||||
@ -660,7 +657,6 @@ DEPENDENCIES
|
||||
syntax_tree-disable_ternary
|
||||
test-prof
|
||||
thor
|
||||
tzinfo-data
|
||||
uglifier
|
||||
unf
|
||||
unicorn
|
||||
|
||||
@ -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.
|
||||
|
||||
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!
|
||||
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!
|
||||
|
||||
## Setting up Discourse
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
import RESTAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class ApiKey extends RestAdapter {
|
||||
jsonMode = true;
|
||||
export default RESTAdapter.extend({
|
||||
jsonMode: true,
|
||||
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
}
|
||||
},
|
||||
|
||||
apiNameFor() {
|
||||
return "key";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default function buildPluginAdapter(pluginName) {
|
||||
return class extends RestAdapter {
|
||||
return RestAdapter.extend({
|
||||
pathFor(store, type, findArgs) {
|
||||
return (
|
||||
"/admin/plugins/" + pluginName + super.pathFor(store, type, findArgs)
|
||||
"/admin/plugins/" + pluginName + this._super(store, type, findArgs)
|
||||
);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class CustomizationBase extends RestAdapter {
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/customize/";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class EmailStyle extends RestAdapter {
|
||||
export default RestAdapter.extend({
|
||||
pathFor() {
|
||||
return "/admin/customize/email_style";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class Embedding extends RestAdapter {
|
||||
export default RestAdapter.extend({
|
||||
pathFor() {
|
||||
return "/admin/customize/embedding";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class StaffActionLog extends RestAdapter {
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/logs/";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class TagGroup extends RestAdapter {
|
||||
jsonMode = true;
|
||||
}
|
||||
export default RestAdapter.extend({
|
||||
jsonMode: true,
|
||||
});
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class Theme extends RestAdapter {
|
||||
jsonMode = true;
|
||||
export default RestAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/";
|
||||
}
|
||||
},
|
||||
|
||||
afterFindAll(results) {
|
||||
let map = {};
|
||||
@ -21,5 +20,7 @@ export default class Theme extends RestAdapter {
|
||||
theme.set("parentThemes", mappedParents);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
jsonMode: true,
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
import RESTAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class WebHookEvent extends RestAdapter {
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
import RESTAdapter from "discourse/adapters/rest";
|
||||
|
||||
export default class WebHook extends RestAdapter {
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return "/admin/api/";
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { action } from "@ember/object";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import Component from "@ember/component";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import I18n from "I18n";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import { bind, observes } from "discourse-common/utils/decorators";
|
||||
|
||||
const COLOR_VARS_REGEX =
|
||||
/\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
|
||||
@ -200,7 +200,7 @@ export default class AceEditor extends Component {
|
||||
|
||||
this._editor.getSession().setAnnotations(warnings);
|
||||
|
||||
this.setWarning?.(
|
||||
this.setWarning(
|
||||
warnings.length
|
||||
? I18n.t("admin.customize.theme.scss_color_variables_warning")
|
||||
: false
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
@ -10,8 +10,11 @@ export default class AdminBackupsLogs extends Component {
|
||||
showLoadingSpinner = false;
|
||||
hasFormattedLogs = false;
|
||||
noLogsMessage = I18n.t("admin.backups.logs.none");
|
||||
formattedLogs = "";
|
||||
index = 0;
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this._reset();
|
||||
}
|
||||
|
||||
_reset() {
|
||||
this.setProperties({ formattedLogs: "", index: 0 });
|
||||
|
||||
@ -7,6 +7,11 @@ export default class AdminEditableField extends Component {
|
||||
buffer = "";
|
||||
editing = false;
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this.set("editing", false);
|
||||
}
|
||||
|
||||
@action
|
||||
edit(event) {
|
||||
event?.preventDefault();
|
||||
|
||||
@ -61,8 +61,11 @@ export default class AdminReport extends Component {
|
||||
@equal("model.error", "timeout") showTimeoutError;
|
||||
@equal("model.error", "exception") showExceptionError;
|
||||
@notEmpty("model.data") hasData;
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
|
||||
_reports = [];
|
||||
this._reports = [];
|
||||
}
|
||||
|
||||
@computed("siteSettings.dashboard_hidden_reports")
|
||||
get isHidden() {
|
||||
@ -321,6 +324,8 @@ export default class AdminReport extends Component {
|
||||
}
|
||||
|
||||
_fetchReport() {
|
||||
undefined;
|
||||
|
||||
this.setProperties({ isLoading: true, rateLimitationString: null });
|
||||
|
||||
next(() => {
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
@checked={{this.onlyOverridden}}
|
||||
{{on
|
||||
"click"
|
||||
(action this.onlyOverriddenChanged value="target.checked")
|
||||
(action "onlyOverriddenChanged" value="target.checked")
|
||||
}}
|
||||
/>
|
||||
{{i18n "admin.customize.theme.hide_unused_fields"}}
|
||||
@ -125,6 +125,6 @@
|
||||
@autofocus="true"
|
||||
@placeholder={{this.placeholder}}
|
||||
@htmlPlaceholder={{true}}
|
||||
@save={{this.save}}
|
||||
@save={{action "save"}}
|
||||
@setWarning={{action "setWarning"}}
|
||||
/>
|
||||
@ -3,7 +3,7 @@ import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { action, computed } from "@ember/object";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
|
||||
export default class AdminThemeEditor extends Component {
|
||||
@ -62,13 +62,13 @@ export default class AdminThemeEditor extends Component {
|
||||
return "";
|
||||
}
|
||||
|
||||
@computed("fieldName", "currentTargetName", "theme")
|
||||
@discourseComputed("fieldName", "currentTargetName", "theme")
|
||||
get activeSection() {
|
||||
return this.theme.getField(this.currentTargetName, this.fieldName);
|
||||
return this.model.getField(this.currentTargetName, this.fieldName);
|
||||
}
|
||||
|
||||
set activeSection(value) {
|
||||
this.theme.setField(this.currentTargetName, this.fieldName, value);
|
||||
this.theme.setField(this.fieldName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -126,6 +126,16 @@ export default class AdminThemeEditor extends Component {
|
||||
this.fieldAdded(this.currentTargetName, name);
|
||||
}
|
||||
|
||||
@action
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
}
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.attrs.save();
|
||||
}
|
||||
|
||||
@action
|
||||
setWarning(message) {
|
||||
this.set("warning", message);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import { action, computed } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
/**
|
||||
An input field for a color.
|
||||
|
||||
@ -9,11 +9,11 @@ export default class DashboardNewFeatures extends Component {
|
||||
newFeatures = null;
|
||||
releaseNotesLink = null;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
|
||||
ajax("/admin/dashboard/new-features.json").then((json) => {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
@content={{this.editorContents}}
|
||||
@mode={{this.currentEditorMode}}
|
||||
@editorId={{this.editorId}}
|
||||
@save={{@save}}
|
||||
@save={{action "save"}}
|
||||
/>
|
||||
|
||||
<div class="admin-footer">
|
||||
|
||||
@ -48,4 +48,9 @@ export default class EmailStylesEditor extends Component {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.attrs.save();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,15 @@
|
||||
autofocus={{true}}
|
||||
/>
|
||||
</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">
|
||||
<div class="label">{{i18n "admin.embedding.allowed_paths"}}</div>
|
||||
<Input
|
||||
@ -45,6 +54,12 @@
|
||||
<div class="label">{{i18n "admin.embedding.host"}}</div>
|
||||
{{this.host.host}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="label">
|
||||
{{i18n "admin.embedding.class_name"}}
|
||||
</div>
|
||||
{{this.host.class_name}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="label">
|
||||
{{i18n "admin.embedding.allowed_paths"}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div class="form-templates__form">
|
||||
<div class="form-templates--form">
|
||||
<div class="control-group">
|
||||
<label for="template-name">
|
||||
{{i18n "admin.form_templates.new_template_form.name.label"}}
|
||||
@ -6,38 +6,24 @@
|
||||
<TextField
|
||||
@value={{this.templateName}}
|
||||
@name="template-name"
|
||||
@class="form-templates__form-name-input"
|
||||
@class="form-templates--form-name-input"
|
||||
@placeholderKey="admin.form_templates.new_template_form.name.placeholder"
|
||||
/>
|
||||
</div>
|
||||
<div class="control-group form-templates__editor">
|
||||
<div class="form-templates__quick-insert-field-buttons">
|
||||
<span>
|
||||
{{I18n "admin.form_templates.quick_insert_fields.add_new_field"}}
|
||||
</span>
|
||||
{{#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}}
|
||||
|
||||
<div class="control-group form-templates--quick-insert-field-buttons">
|
||||
<span>
|
||||
{{I18n "admin.form_templates.quick_insert_fields.add_new_field"}}
|
||||
</span>
|
||||
{{#each this.quickInsertFields as |field|}}
|
||||
<DButton
|
||||
class="btn-flat btn-icon-text form-templates__validations-modal-button"
|
||||
@label="admin.form_templates.validations_modal.button_title"
|
||||
@icon="check-circle"
|
||||
@action={{this.showValidationOptionsModal}}
|
||||
@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}}
|
||||
/>
|
||||
</div>
|
||||
<DButton
|
||||
@class="form-templates__preview-button"
|
||||
@icon="eye"
|
||||
@label="admin.form_templates.new_template_form.preview"
|
||||
@action={{this.showPreview}}
|
||||
@disabled={{this.disablePreviewButton}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
@ -50,7 +36,7 @@
|
||||
@label="admin.form_templates.new_template_form.submit"
|
||||
@icon="check"
|
||||
@action={{this.onSubmit}}
|
||||
@disabled={{this.disableSubmitButton}}
|
||||
@disabled={{this.formSubmitted}}
|
||||
/>
|
||||
|
||||
<DButton
|
||||
|
||||
@ -6,15 +6,14 @@ import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { templateFormFields } from "admin/lib/template-form-fields";
|
||||
import FormTemplate from "admin/models/form-template";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default class FormTemplateForm extends Component {
|
||||
@service router;
|
||||
@service dialog;
|
||||
@tracked formSubmitted = false;
|
||||
@tracked templateContent = this.args.model?.template || "";
|
||||
@tracked templateName = this.args.model?.name || "";
|
||||
isEditing = this.args.model?.id ? true : false;
|
||||
templateName = this.args.model?.name;
|
||||
quickInsertFields = [
|
||||
{
|
||||
type: "checkbox",
|
||||
@ -42,17 +41,6 @@ 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
|
||||
onSubmit() {
|
||||
if (!this.formSubmitted) {
|
||||
@ -66,17 +54,27 @@ export default class FormTemplateForm extends Component {
|
||||
|
||||
if (this.isEditing) {
|
||||
postData["id"] = this.args.model.id;
|
||||
}
|
||||
|
||||
FormTemplate.createOrUpdateTemplate(postData)
|
||||
.then(() => {
|
||||
this.formSubmitted = false;
|
||||
this.router.transitionTo("adminCustomizeFormTemplates.index");
|
||||
})
|
||||
.catch((e) => {
|
||||
popupAjaxError(e);
|
||||
this.formSubmitted = false;
|
||||
});
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
@ -108,33 +106,4 @@ export default class FormTemplateForm extends Component {
|
||||
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,10 +1,5 @@
|
||||
<tr class="admin-list-item">
|
||||
<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">
|
||||
<DButton
|
||||
@title="admin.form_templates.list_table.actions.view"
|
||||
|
||||
@ -9,17 +9,11 @@ import I18n from "I18n";
|
||||
export default class FormTemplateRowItem extends Component {
|
||||
@service router;
|
||||
@service dialog;
|
||||
@service site;
|
||||
|
||||
get activeCategories() {
|
||||
return this.site?.categories?.filter((c) =>
|
||||
c["form_template_ids"].includes(this.args.template.id)
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
viewTemplate() {
|
||||
showModal("customize-form-template-view", {
|
||||
showModal("admin-customize-form-template-view", {
|
||||
admin: true,
|
||||
model: this.args.template,
|
||||
refreshModel: this.args.refreshModel,
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { observes, on } from "@ember-decorators/object";
|
||||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import highlightSyntax from "discourse/lib/highlight-syntax";
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import { classNameBindings } from "@ember-decorators/component";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
import { action, set } from "@ember/object";
|
||||
|
||||
@classNameBindings(":value-list", ":secret-value-list")
|
||||
|
||||
@ -2,8 +2,7 @@ import { classNameBindings } from "@ember-decorators/component";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
|
||||
@classNameBindings(":simple-list", ":value-list")
|
||||
export default class SimpleList extends Component {
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
<div class="setting-label">
|
||||
<h3>
|
||||
{{this.settingName}}
|
||||
|
||||
{{#if this.staffLogFilter}}
|
||||
{{this.settingName}}
|
||||
<LinkTo
|
||||
@route="adminLogs.staffActionLogs"
|
||||
@query={{hash filters=this.staffLogFilter force_refresh=true}}
|
||||
@ -12,18 +11,17 @@
|
||||
{{d-icon "history"}}
|
||||
</span>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
{{this.settingName}}
|
||||
{{/if}}
|
||||
</h3>
|
||||
|
||||
{{#if this.defaultIsAvailable}}
|
||||
<DButton
|
||||
class="btn-link"
|
||||
@action={{this.setDefaultValues}}
|
||||
@translatedLabel={{this.setting.setDefaultValuesLabel}}
|
||||
/>
|
||||
<a
|
||||
href
|
||||
onClick={{action "setDefaultValues"}}
|
||||
>{{this.setting.setDefaultValuesLabel}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="setting-value">
|
||||
{{component
|
||||
this.componentName
|
||||
@ -35,20 +33,18 @@
|
||||
allowAny=this.allowAny
|
||||
}}
|
||||
</div>
|
||||
|
||||
{{#if this.dirty}}
|
||||
<div class="setting-controls">
|
||||
<DButton class="ok" @action={{this.update}} @icon="check" />
|
||||
<DButton class="cancel" @action={{this.cancel}} @icon="times" />
|
||||
<DButton @class="ok" @action={{action "update"}} @icon="check" />
|
||||
<DButton @class="cancel" @action={{action "cancel"}} @icon="times" />
|
||||
</div>
|
||||
{{else if this.setting.overridden}}
|
||||
{{#if this.setting.secret}}
|
||||
<DButton @action={{this.toggleSecret}} @icon="far-eye-slash" />
|
||||
<DButton @action={{action "toggleSecret"}} @icon="far-eye-slash" />
|
||||
{{/if}}
|
||||
|
||||
<DButton
|
||||
class="btn-default undo"
|
||||
@action={{this.resetDefault}}
|
||||
@class="btn-default undo"
|
||||
@action={{action "resetDefault"}}
|
||||
@icon="undo"
|
||||
@label="admin.settings.reset"
|
||||
/>
|
||||
|
||||
@ -11,7 +11,6 @@ export default class SiteSettingComponent extends Component.extend(
|
||||
updateExistingUsers = null;
|
||||
|
||||
@readOnly("setting.staffLogFilter") staffLogFilter;
|
||||
|
||||
_save() {
|
||||
const setting = this.buffered;
|
||||
return SiteSetting.update(setting.get("setting"), setting.get("value"), {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { classNameBindings, classNames } from "@ember-decorators/component";
|
||||
import Component from "@ember/component";
|
||||
import highlightHTML from "discourse/lib/highlight-html";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
|
||||
@classNames("site-text")
|
||||
@classNameBindings("siteText.overridden")
|
||||
|
||||
@ -56,7 +56,6 @@
|
||||
{{#if this.hasInactiveThemes}}
|
||||
{{#each this.inactiveThemes as |theme|}}
|
||||
<ThemesListItem
|
||||
@classNames="inactive-theme"
|
||||
@theme={{theme}}
|
||||
@navigateToTheme={{action "navigateToTheme" theme}}
|
||||
/>
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
import { action } from "@ember/object";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { on } from "@ember-decorators/object";
|
||||
import { classNameBindings } from "@ember-decorators/component";
|
||||
import { empty, reads } from "@ember/object/computed";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
|
||||
@classNames("value-list")
|
||||
@classNameBindings(":value-list")
|
||||
export default class ValueList extends Component {
|
||||
@empty("newValue") inputInvalid;
|
||||
|
||||
|
||||
@ -2,8 +2,7 @@ import { action } from "@ember/object";
|
||||
import { classNames, tagName } from "@ember-decorators/component";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { equal, not } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import WatchedWord from "admin/models/watched-word";
|
||||
|
||||
@ -2,18 +2,18 @@ import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default class AdminApiKeysIndexController extends Controller {
|
||||
loading = false;
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
@action
|
||||
revokeKey(key) {
|
||||
key.revoke().catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
undoRevokeKey(key) {
|
||||
key.undoRevoke().catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
@ -35,5 +35,5 @@ export default class AdminApiKeysIndexController extends Controller {
|
||||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,32 +1,37 @@
|
||||
import { equal } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isBlank } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { action, get } from "@ember/object";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default class AdminApiKeysNewController extends Controller {
|
||||
userModes = [
|
||||
{ id: "all", name: I18n.t("admin.api.all_users") },
|
||||
{ id: "single", name: I18n.t("admin.api.single_user") },
|
||||
];
|
||||
scopeModes = [
|
||||
{ id: "granular", name: I18n.t("admin.api.scopes.granular") },
|
||||
{ id: "read_only", name: I18n.t("admin.api.scopes.read_only") },
|
||||
{ id: "global", name: I18n.t("admin.api.scopes.global") },
|
||||
];
|
||||
globalScopes = null;
|
||||
scopes = null;
|
||||
|
||||
@equal("userMode", "single") showUserSelector;
|
||||
export default Controller.extend({
|
||||
userModes: null,
|
||||
scopeModes: null,
|
||||
globalScopes: null,
|
||||
scopes: null,
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("userModes", [
|
||||
{ id: "all", name: I18n.t("admin.api.all_users") },
|
||||
{ id: "single", name: I18n.t("admin.api.single_user") },
|
||||
]);
|
||||
|
||||
this.set("scopeModes", [
|
||||
{ id: "granular", name: I18n.t("admin.api.scopes.granular") },
|
||||
{ id: "read_only", name: I18n.t("admin.api.scopes.read_only") },
|
||||
{ id: "global", name: I18n.t("admin.api.scopes.global") },
|
||||
]);
|
||||
|
||||
this._loadScopes();
|
||||
}
|
||||
},
|
||||
|
||||
showUserSelector: equal("userMode", "single"),
|
||||
|
||||
@discourseComputed("model.{description,username}", "showUserSelector")
|
||||
saveDisabled(model, showUserSelector) {
|
||||
@ -37,12 +42,12 @@ export default class AdminApiKeysNewController extends Controller {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
updateUsername(selected) {
|
||||
this.set("model.username", get(selected, "firstObject"));
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
changeUserMode(userMode) {
|
||||
@ -50,12 +55,12 @@ export default class AdminApiKeysNewController extends Controller {
|
||||
this.model.set("username", null);
|
||||
}
|
||||
this.set("userMode", userMode);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
changeScopeMode(scopeMode) {
|
||||
this.set("scopeMode", scopeMode);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
save() {
|
||||
@ -72,12 +77,12 @@ export default class AdminApiKeysNewController extends Controller {
|
||||
}
|
||||
|
||||
return this.model.save().catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
continue() {
|
||||
this.transitionToRoute("adminApiKeys.show", this.model.id);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
showURLs(urls) {
|
||||
@ -85,7 +90,7 @@ export default class AdminApiKeysNewController extends Controller {
|
||||
admin: true,
|
||||
model: { urls },
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_loadScopes() {
|
||||
return ajax("/admin/api/keys/scopes.json")
|
||||
@ -97,5 +102,5 @@ export default class AdminApiKeysNewController extends Controller {
|
||||
this.set("scopes", data.scopes);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,74 +1,66 @@
|
||||
import { action } from "@ember/object";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default class AdminApiKeysShowController extends Controller.extend(
|
||||
bufferedProperty("model")
|
||||
) {
|
||||
@empty("model.id") isNew;
|
||||
export default Controller.extend(bufferedProperty("model"), {
|
||||
isNew: empty("model.id"),
|
||||
|
||||
@action
|
||||
saveDescription() {
|
||||
const buffered = this.buffered;
|
||||
const attrs = buffered.getProperties("description");
|
||||
actions: {
|
||||
saveDescription() {
|
||||
const buffered = this.buffered;
|
||||
const attrs = buffered.getProperties("description");
|
||||
|
||||
this.model
|
||||
.save(attrs)
|
||||
.then(() => {
|
||||
this.set("editingDescription", false);
|
||||
this.model
|
||||
.save(attrs)
|
||||
.then(() => {
|
||||
this.set("editingDescription", false);
|
||||
this.rollbackBuffer();
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
cancel() {
|
||||
const id = this.get("userField.id");
|
||||
if (isEmpty(id)) {
|
||||
this.destroyAction(this.userField);
|
||||
} else {
|
||||
this.rollbackBuffer();
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
this.set("editing", false);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
cancel() {
|
||||
const id = this.get("userField.id");
|
||||
if (isEmpty(id)) {
|
||||
this.destroyAction(this.userField);
|
||||
} else {
|
||||
this.rollbackBuffer();
|
||||
this.set("editing", false);
|
||||
}
|
||||
}
|
||||
editDescription() {
|
||||
this.toggleProperty("editingDescription");
|
||||
if (!this.editingDescription) {
|
||||
this.rollbackBuffer();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
editDescription() {
|
||||
this.toggleProperty("editingDescription");
|
||||
if (!this.editingDescription) {
|
||||
this.rollbackBuffer();
|
||||
}
|
||||
}
|
||||
revokeKey(key) {
|
||||
key.revoke().catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
revokeKey(key) {
|
||||
key.revoke().catch(popupAjaxError);
|
||||
}
|
||||
deleteKey(key) {
|
||||
key
|
||||
.destroyRecord()
|
||||
.then(() => this.transitionToRoute("adminApiKeys.index"))
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
deleteKey(key) {
|
||||
key
|
||||
.destroyRecord()
|
||||
.then(() => this.transitionToRoute("adminApiKeys.index"))
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
undoRevokeKey(key) {
|
||||
key.undoRevoke().catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
undoRevokeKey(key) {
|
||||
key.undoRevoke().catch(popupAjaxError);
|
||||
}
|
||||
|
||||
@action
|
||||
showURLs(urls) {
|
||||
return showModal("admin-api-key-urls", {
|
||||
admin: true,
|
||||
model: {
|
||||
urls,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
showURLs(urls) {
|
||||
return showModal("admin-api-key-urls", {
|
||||
admin: true,
|
||||
model: {
|
||||
urls,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default class AdminApiKeysController extends Controller {}
|
||||
export default Controller.extend();
|
||||
|
||||
@ -1,21 +1,19 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import { i18n, setting } from "discourse/lib/computed";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminBackupsIndexController extends Controller {
|
||||
@service dialog;
|
||||
@controller adminBackups;
|
||||
|
||||
@alias("adminBackups.model") status;
|
||||
@i18n("admin.backups.upload.label") uploadLabel;
|
||||
@setting("backup_location") backupLocation;
|
||||
@equal("backupLocation", "local") localBackupStorage;
|
||||
export default Controller.extend({
|
||||
adminBackups: controller(),
|
||||
dialog: service(),
|
||||
status: alias("adminBackups.model"),
|
||||
uploadLabel: i18n("admin.backups.upload.label"),
|
||||
backupLocation: setting("backup_location"),
|
||||
localBackupStorage: equal("backupLocation", "local"),
|
||||
|
||||
@discourseComputed("status.allowRestore", "status.isOperationRunning")
|
||||
restoreTitle(allowRestore, isOperationRunning) {
|
||||
@ -26,35 +24,35 @@ export default class AdminBackupsIndexController extends Controller {
|
||||
} else {
|
||||
return "admin.backups.operations.restore.title";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
toggleReadOnlyMode() {
|
||||
if (!this.site.get("isReadOnly")) {
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.backups.read_only.enable.confirm"),
|
||||
didConfirm: () => {
|
||||
this.set("currentUser.hideReadOnlyAlert", true);
|
||||
this._toggleReadOnlyMode(true);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this._toggleReadOnlyMode(false);
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
toggleReadOnlyMode() {
|
||||
if (!this.site.get("isReadOnly")) {
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.backups.read_only.enable.confirm"),
|
||||
didConfirm: () => {
|
||||
this.set("currentUser.hideReadOnlyAlert", true);
|
||||
this._toggleReadOnlyMode(true);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this._toggleReadOnlyMode(false);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
download(backup) {
|
||||
const link = backup.get("filename");
|
||||
ajax(`/admin/backups/${link}`, { type: "PUT" }).then(() =>
|
||||
this.dialog.alert(I18n.t("admin.backups.operations.download.alert"))
|
||||
);
|
||||
}
|
||||
download(backup) {
|
||||
const link = backup.get("filename");
|
||||
ajax(`/admin/backups/${link}`, { type: "PUT" }).then(() =>
|
||||
this.dialog.alert(I18n.t("admin.backups.operations.download.alert"))
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
_toggleReadOnlyMode(enable) {
|
||||
ajax("/admin/backups/readonly", {
|
||||
type: "PUT",
|
||||
data: { enable },
|
||||
}).then(() => this.site.set("isReadOnly", enable));
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default class AdminBackupsLogsController extends Controller {
|
||||
@controller adminBackups;
|
||||
export default Controller.extend({
|
||||
adminBackups: controller(),
|
||||
status: alias("adminBackups.model"),
|
||||
|
||||
@alias("adminBackups.model") status;
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
logs = [];
|
||||
}
|
||||
this.logs = [];
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { and, not } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
export default class AdminBackupsController extends Controller {
|
||||
@not("model.isOperationRunning") noOperationIsRunning;
|
||||
@not("rollbackEnabled") rollbackDisabled;
|
||||
@and("model.canRollback", "model.restoreEnabled", "noOperationIsRunning")
|
||||
rollbackEnabled;
|
||||
}
|
||||
export default Controller.extend({
|
||||
noOperationIsRunning: not("model.isOperationRunning"),
|
||||
rollbackEnabled: and(
|
||||
"model.canRollback",
|
||||
"model.restoreEnabled",
|
||||
"noOperationIsRunning"
|
||||
),
|
||||
rollbackDisabled: not("rollbackEnabled"),
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
@ -248,13 +248,8 @@ export default class AdminBadgesShowController extends Controller.extend(
|
||||
|
||||
@action
|
||||
toggleBadge() {
|
||||
const originalState = this.buffered.get("enabled");
|
||||
const newState = !this.buffered.get("enabled");
|
||||
|
||||
this.buffered.set("enabled", newState);
|
||||
this.model.save({ enabled: newState }).catch((error) => {
|
||||
this.buffered.set("enabled", originalState);
|
||||
return popupAjaxError(error);
|
||||
});
|
||||
this.model
|
||||
.save({ enabled: !this.buffered.get("enabled") })
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import Controller from "@ember/controller";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default class AdminCustomizeColorsController extends Controller {
|
||||
export default Controller.extend({
|
||||
@discourseComputed("model.@each.id")
|
||||
baseColorScheme() {
|
||||
return this.model.findBy("is_base", true);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.@each.id")
|
||||
baseColorSchemes() {
|
||||
return this.model.filterBy("is_base", true);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("baseColorScheme")
|
||||
baseColors(baseColorScheme) {
|
||||
@ -22,28 +22,28 @@ export default class AdminCustomizeColorsController extends Controller {
|
||||
baseColorsHash.set(color.get("name"), color);
|
||||
});
|
||||
return baseColorsHash;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
newColorSchemeWithBase(baseKey) {
|
||||
const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey);
|
||||
const newColorScheme = base.copy();
|
||||
newColorScheme.setProperties({
|
||||
name: I18n.t("admin.customize.colors.new_name"),
|
||||
base_scheme_id: base.get("base_scheme_id"),
|
||||
});
|
||||
newColorScheme.save().then(() => {
|
||||
this.model.pushObject(newColorScheme);
|
||||
newColorScheme.set("savingStatus", null);
|
||||
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
||||
});
|
||||
}
|
||||
actions: {
|
||||
newColorSchemeWithBase(baseKey) {
|
||||
const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey);
|
||||
const newColorScheme = base.copy();
|
||||
newColorScheme.setProperties({
|
||||
name: I18n.t("admin.customize.colors.new_name"),
|
||||
base_scheme_id: base.get("base_scheme_id"),
|
||||
});
|
||||
newColorScheme.save().then(() => {
|
||||
this.model.pushObject(newColorScheme);
|
||||
newColorScheme.set("savingStatus", null);
|
||||
this.replaceRoute("adminCustomize.colors.show", newColorScheme);
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
newColorScheme() {
|
||||
showModal("admin-color-scheme-select-base", {
|
||||
model: this.baseColorSchemes,
|
||||
admin: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
newColorScheme() {
|
||||
showModal("admin-color-scheme-select-base", {
|
||||
model: this.baseColorSchemes,
|
||||
admin: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,38 +1,38 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminCustomizeEmailStyleEditController extends Controller {
|
||||
@service dialog;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
|
||||
@discourseComputed("model.isSaving")
|
||||
saveButtonText(isSaving) {
|
||||
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.changed", "model.isSaving")
|
||||
saveDisabled(changed, isSaving) {
|
||||
return !changed || isSaving;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
save() {
|
||||
if (!this.model.saving) {
|
||||
this.set("saving", true);
|
||||
this.model
|
||||
.update(this.model.getProperties("html", "css"))
|
||||
.catch((e) => {
|
||||
const msg =
|
||||
e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors
|
||||
? I18n.t("admin.customize.email_style.save_error_with_reason", {
|
||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||
})
|
||||
: I18n.t("generic_error");
|
||||
this.dialog.alert(msg);
|
||||
})
|
||||
.finally(() => this.set("model.changed", false));
|
||||
}
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
save() {
|
||||
if (!this.model.saving) {
|
||||
this.set("saving", true);
|
||||
this.model
|
||||
.update(this.model.getProperties("html", "css"))
|
||||
.catch((e) => {
|
||||
const msg =
|
||||
e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors
|
||||
? I18n.t("admin.customize.email_style.save_error_with_reason", {
|
||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||
})
|
||||
: I18n.t("generic_error");
|
||||
this.dialog.alert(msg);
|
||||
})
|
||||
.finally(() => this.set("model.changed", false));
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,26 +1,23 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { action } from "@ember/object";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminCustomizeEmailTemplatesEditController extends Controller.extend(
|
||||
bufferedProperty("emailTemplate")
|
||||
) {
|
||||
@service dialog;
|
||||
@controller adminCustomizeEmailTemplates;
|
||||
|
||||
emailTemplate = null;
|
||||
saved = false;
|
||||
export default Controller.extend(bufferedProperty("emailTemplate"), {
|
||||
adminCustomizeEmailTemplates: controller(),
|
||||
dialog: service(),
|
||||
emailTemplate: null,
|
||||
saved: false,
|
||||
|
||||
@discourseComputed("buffered.body", "buffered.subject")
|
||||
saveDisabled(body, subject) {
|
||||
return (
|
||||
this.emailTemplate.body === body && this.emailTemplate.subject === subject
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("buffered")
|
||||
hasMultipleSubjects(buffered) {
|
||||
@ -29,7 +26,7 @@ export default class AdminCustomizeEmailTemplatesEditController extends Controll
|
||||
} else {
|
||||
return buffered.getProperties("id")["id"];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
saveChanges() {
|
||||
@ -41,7 +38,7 @@ export default class AdminCustomizeEmailTemplatesEditController extends Controll
|
||||
this.set("saved", true);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
revertChanges() {
|
||||
@ -60,5 +57,5 @@ export default class AdminCustomizeEmailTemplatesEditController extends Controll
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
import { sort } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { sort } from "@ember/object/computed";
|
||||
|
||||
export default class AdminCustomizeEmailTemplatesController extends Controller {
|
||||
titleSorting = ["title"];
|
||||
@sort("emailTemplates", "titleSorting") sortedTemplates;
|
||||
export default Controller.extend({
|
||||
sortedTemplates: sort("emailTemplates", "titleSorting"),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("titleSorting", ["title"]);
|
||||
},
|
||||
|
||||
@action
|
||||
onSelectTemplate(template) {
|
||||
this.transitionToRoute("adminCustomizeEmailTemplates.edit", template);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,52 +1,47 @@
|
||||
import { action } from "@ember/object";
|
||||
import { not } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { not } from "@ember/object/computed";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
|
||||
export default class AdminCustomizeRobotsTxtController extends Controller.extend(
|
||||
bufferedProperty("model")
|
||||
) {
|
||||
saved = false;
|
||||
isSaving = false;
|
||||
export default Controller.extend(bufferedProperty("model"), {
|
||||
saved: false,
|
||||
isSaving: false,
|
||||
saveDisabled: propertyEqual("model.robots_txt", "buffered.robots_txt"),
|
||||
resetDisabled: not("model.overridden"),
|
||||
|
||||
@propertyEqual("model.robots_txt", "buffered.robots_txt") saveDisabled;
|
||||
actions: {
|
||||
save() {
|
||||
this.setProperties({
|
||||
isSaving: true,
|
||||
saved: false,
|
||||
});
|
||||
|
||||
@not("model.overridden") resetDisabled;
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.setProperties({
|
||||
isSaving: true,
|
||||
saved: false,
|
||||
});
|
||||
|
||||
ajax("robots.json", {
|
||||
type: "PUT",
|
||||
data: { robots_txt: this.buffered.get("robots_txt") },
|
||||
})
|
||||
.then((data) => {
|
||||
this.commitBuffer();
|
||||
this.set("saved", true);
|
||||
this.set("model.overridden", data.overridden);
|
||||
ajax("robots.json", {
|
||||
type: "PUT",
|
||||
data: { robots_txt: this.buffered.get("robots_txt") },
|
||||
})
|
||||
.finally(() => this.set("isSaving", false));
|
||||
}
|
||||
.then((data) => {
|
||||
this.commitBuffer();
|
||||
this.set("saved", true);
|
||||
this.set("model.overridden", data.overridden);
|
||||
})
|
||||
.finally(() => this.set("isSaving", false));
|
||||
},
|
||||
|
||||
@action
|
||||
reset() {
|
||||
this.setProperties({
|
||||
isSaving: true,
|
||||
saved: false,
|
||||
});
|
||||
ajax("robots.json", { type: "DELETE" })
|
||||
.then((data) => {
|
||||
this.buffered.set("robots_txt", data.robots_txt);
|
||||
this.commitBuffer();
|
||||
this.set("saved", true);
|
||||
this.set("model.overridden", false);
|
||||
})
|
||||
.finally(() => this.set("isSaving", false));
|
||||
}
|
||||
}
|
||||
reset() {
|
||||
this.setProperties({
|
||||
isSaving: true,
|
||||
saved: false,
|
||||
});
|
||||
ajax("robots.json", { type: "DELETE" })
|
||||
.then((data) => {
|
||||
this.buffered.set("robots_txt", data.robots_txt);
|
||||
this.commitBuffer();
|
||||
this.set("saved", true);
|
||||
this.set("model.overridden", false);
|
||||
})
|
||||
.finally(() => this.set("isSaving", false));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,24 +1,21 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { url } from "discourse/lib/computed";
|
||||
|
||||
export default class AdminCustomizeThemesEditController extends Controller {
|
||||
section = null;
|
||||
currentTarget = 0;
|
||||
maximized = false;
|
||||
|
||||
@url("model.id", "/admin/themes/%@/preview") previewUrl;
|
||||
|
||||
showAdvanced = false;
|
||||
editRouteName = "adminCustomizeThemes.edit";
|
||||
showRouteName = "adminCustomizeThemes.show";
|
||||
export default Controller.extend({
|
||||
section: null,
|
||||
currentTarget: 0,
|
||||
maximized: false,
|
||||
previewUrl: url("model.id", "/admin/themes/%@/preview"),
|
||||
showAdvanced: false,
|
||||
editRouteName: "adminCustomizeThemes.edit",
|
||||
showRouteName: "adminCustomizeThemes.show",
|
||||
|
||||
setTargetName(name) {
|
||||
const target = this.get("model.targets").find((t) => t.name === name);
|
||||
this.set("currentTarget", target && target.id);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("currentTarget")
|
||||
currentTargetName(id) {
|
||||
@ -26,52 +23,50 @@ export default class AdminCustomizeThemesEditController extends Controller {
|
||||
(t) => t.id === parseInt(id, 10)
|
||||
);
|
||||
return target && target.name;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.isSaving")
|
||||
saveButtonText(isSaving) {
|
||||
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.changed", "model.isSaving")
|
||||
saveDisabled(changed, isSaving) {
|
||||
return !changed || isSaving;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
save() {
|
||||
this.set("saving", true);
|
||||
this.model.saveChanges("theme_fields").finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
}
|
||||
actions: {
|
||||
save() {
|
||||
this.set("saving", true);
|
||||
this.model.saveChanges("theme_fields").finally(() => {
|
||||
this.set("saving", false);
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
fieldAdded(target, name) {
|
||||
this.replaceRoute(this.editRouteName, this.get("model.id"), target, name);
|
||||
}
|
||||
fieldAdded(target, name) {
|
||||
this.replaceRoute(this.editRouteName, this.get("model.id"), target, name);
|
||||
},
|
||||
|
||||
@action
|
||||
onlyOverriddenChanged(onlyShowOverridden) {
|
||||
if (onlyShowOverridden) {
|
||||
if (!this.model.hasEdited(this.currentTargetName, this.fieldName)) {
|
||||
let firstTarget = this.get("model.targets").find((t) => t.edited);
|
||||
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
|
||||
(f) => f.edited
|
||||
);
|
||||
onlyOverriddenChanged(onlyShowOverridden) {
|
||||
if (onlyShowOverridden) {
|
||||
if (!this.model.hasEdited(this.currentTargetName, this.fieldName)) {
|
||||
let firstTarget = this.get("model.targets").find((t) => t.edited);
|
||||
let firstField = this.get(`model.fields.${firstTarget.name}`).find(
|
||||
(f) => f.edited
|
||||
);
|
||||
|
||||
this.replaceRoute(
|
||||
this.editRouteName,
|
||||
this.get("model.id"),
|
||||
firstTarget.name,
|
||||
firstField.name
|
||||
);
|
||||
this.replaceRoute(
|
||||
this.editRouteName,
|
||||
this.get("model.id"),
|
||||
firstTarget.name,
|
||||
firstField.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.replaceRoute(this.showRouteName, this.model.id);
|
||||
}
|
||||
}
|
||||
goBack() {
|
||||
this.replaceRoute(this.showRouteName, this.model.id);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import {
|
||||
empty,
|
||||
filterBy,
|
||||
@ -6,9 +6,8 @@ import {
|
||||
match,
|
||||
notEmpty,
|
||||
} from "@ember/object/computed";
|
||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||
import Controller from "@ember/controller";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import ThemeSettings from "admin/models/theme-settings";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
@ -16,35 +15,31 @@ import { makeArray } from "discourse-common/lib/helpers";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { url } from "discourse/lib/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
const THEME_UPLOAD_VAR = 2;
|
||||
|
||||
export default class AdminCustomizeThemesShowController extends Controller {
|
||||
@service dialog;
|
||||
|
||||
editRouteName = "adminCustomizeThemes.edit";
|
||||
|
||||
@url("model.id", "/admin/customize/themes/%@/export") downloadUrl;
|
||||
@url("model.id", "/admin/themes/%@/preview") previewUrl;
|
||||
@empty("selectedChildThemeId") addButtonDisabled;
|
||||
@mapBy("model.parentThemes", "name") parentThemesNames;
|
||||
@filterBy("allThemes", "component", false) availableParentThemes;
|
||||
@filterBy("availableParentThemes", "isActive") availableActiveParentThemes;
|
||||
@mapBy("availableParentThemes", "name") availableThemesNames;
|
||||
@mapBy("availableActiveParentThemes", "name") availableActiveThemesNames;
|
||||
@filterBy("availableChildThemes", "hasParents") availableActiveChildThemes;
|
||||
@mapBy("availableChildThemes", "name") availableComponentsNames;
|
||||
@mapBy("availableActiveChildThemes", "name") availableActiveComponentsNames;
|
||||
@mapBy("model.childThemes", "name") childThemesNames;
|
||||
@filterBy("model.theme_fields", "target", "extra_js") extraFiles;
|
||||
@notEmpty("settings") hasSettings;
|
||||
@notEmpty("translations") hasTranslations;
|
||||
@match("model.remote_theme.remote_url", /^http(s)?:\/\//) sourceIsHttp;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
downloadUrl: url("model.id", "/admin/customize/themes/%@/export"),
|
||||
previewUrl: url("model.id", "/admin/themes/%@/preview"),
|
||||
addButtonDisabled: empty("selectedChildThemeId"),
|
||||
editRouteName: "adminCustomizeThemes.edit",
|
||||
parentThemesNames: mapBy("model.parentThemes", "name"),
|
||||
availableParentThemes: filterBy("allThemes", "component", false),
|
||||
availableActiveParentThemes: filterBy("availableParentThemes", "isActive"),
|
||||
availableThemesNames: mapBy("availableParentThemes", "name"),
|
||||
availableActiveThemesNames: mapBy("availableActiveParentThemes", "name"),
|
||||
availableActiveChildThemes: filterBy("availableChildThemes", "hasParents"),
|
||||
availableComponentsNames: mapBy("availableChildThemes", "name"),
|
||||
availableActiveComponentsNames: mapBy("availableActiveChildThemes", "name"),
|
||||
childThemesNames: mapBy("model.childThemes", "name"),
|
||||
extraFiles: filterBy("model.theme_fields", "target", "extra_js"),
|
||||
|
||||
@discourseComputed("model.component", "model.remote_theme")
|
||||
showCheckboxes() {
|
||||
return !this.model.component || this.model.remote_theme;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.editedFields")
|
||||
editedFieldsFormatted() {
|
||||
@ -62,13 +57,13 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
descriptions.push(resultString);
|
||||
});
|
||||
return descriptions;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("colorSchemeId", "model.color_scheme_id")
|
||||
colorSchemeChanged(colorSchemeId, existingId) {
|
||||
colorSchemeId = colorSchemeId === null ? null : parseInt(colorSchemeId, 10);
|
||||
return colorSchemeId !== existingId;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("availableChildThemes", "model.childThemes.[]", "model")
|
||||
selectableChildThemes(available, childThemes) {
|
||||
@ -78,7 +73,7 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
: available.filter((theme) => !childThemes.includes(theme));
|
||||
return themes.length === 0 ? null : themes;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.parentThemes.[]")
|
||||
relativesSelectorSettingsForComponent() {
|
||||
@ -96,7 +91,7 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
allThemes: this.allThemes,
|
||||
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all_themes"),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.parentThemes.[]")
|
||||
relativesSelectorSettingsForTheme() {
|
||||
@ -114,7 +109,7 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
allThemes: this.allThemes,
|
||||
setDefaultValuesLabel: I18n.t("admin.customize.theme.add_all"),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("allThemes", "model.component", "model")
|
||||
availableChildThemes(allThemes) {
|
||||
@ -124,36 +119,40 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
(theme) => theme.get("id") !== themeId && theme.get("component")
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.component")
|
||||
convertKey(component) {
|
||||
const type = component ? "component" : "theme";
|
||||
return `admin.customize.theme.convert_${type}`;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.component")
|
||||
convertIcon(component) {
|
||||
return component ? "cube" : "";
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.component")
|
||||
convertTooltip(component) {
|
||||
const type = component ? "component" : "theme";
|
||||
return `admin.customize.theme.convert_${type}_tooltip`;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.settings")
|
||||
settings(settings) {
|
||||
return settings.map((setting) => ThemeSettings.create(setting));
|
||||
}
|
||||
},
|
||||
|
||||
hasSettings: notEmpty("settings"),
|
||||
|
||||
@discourseComputed("model.translations")
|
||||
translations(translations) {
|
||||
return translations.map((setting) =>
|
||||
ThemeSettings.create({ ...setting, textarea: true })
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
hasTranslations: notEmpty("translations"),
|
||||
|
||||
@discourseComputed(
|
||||
"model.remote_theme.local_version",
|
||||
@ -162,12 +161,12 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
)
|
||||
hasOverwrittenHistory(localVersion, remoteVersion, commitsBehind) {
|
||||
return localVersion !== remoteVersion && commitsBehind === -1;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.remoteError", "updatingRemote")
|
||||
showRemoteError(errorMessage, updating) {
|
||||
return errorMessage && !updating;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"model.remote_theme.remote_url",
|
||||
@ -176,13 +175,13 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
)
|
||||
finishInstall(remoteUrl, localVersion, commitsBehind) {
|
||||
return remoteUrl && !localVersion && !commitsBehind;
|
||||
}
|
||||
},
|
||||
|
||||
editedFieldsForTarget(target) {
|
||||
return this.get("model.editedFields").filter(
|
||||
(field) => field.target === target
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
commitSwitchType() {
|
||||
const model = this.model;
|
||||
@ -223,8 +222,7 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
});
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
|
||||
},
|
||||
transitionToEditRoute() {
|
||||
this.transitionToRoute(
|
||||
this.editRouteName,
|
||||
@ -232,7 +230,8 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
"common",
|
||||
"scss"
|
||||
);
|
||||
}
|
||||
},
|
||||
sourceIsHttp: match("model.remote_theme.remote_url", /^http(s)?:\/\//),
|
||||
|
||||
@discourseComputed(
|
||||
"model.remote_theme.remote_url",
|
||||
@ -242,186 +241,168 @@ export default class AdminCustomizeThemesShowController extends Controller {
|
||||
return remoteThemeBranch
|
||||
? `${remoteThemeUrl.replace(/\.git$/, "")}/tree/${remoteThemeBranch}`
|
||||
: remoteThemeUrl;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.user.id", "model.default")
|
||||
showConvert(userId, defaultTheme) {
|
||||
return userId > 0 && !defaultTheme;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
updateToLatest() {
|
||||
this.set("updatingRemote", true);
|
||||
this.model
|
||||
.updateToLatest()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("updatingRemote", false);
|
||||
actions: {
|
||||
updateToLatest() {
|
||||
this.set("updatingRemote", true);
|
||||
this.model
|
||||
.updateToLatest()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("updatingRemote", false);
|
||||
});
|
||||
},
|
||||
|
||||
checkForThemeUpdates() {
|
||||
this.set("updatingRemote", true);
|
||||
this.model
|
||||
.checkForUpdates()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("updatingRemote", false);
|
||||
});
|
||||
},
|
||||
|
||||
addUploadModal() {
|
||||
showModal("admin-add-upload", { admin: true, name: "" });
|
||||
},
|
||||
|
||||
addUpload(info) {
|
||||
let model = this.model;
|
||||
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
||||
model.saveChanges("theme_fields").catch((e) => popupAjaxError(e));
|
||||
},
|
||||
|
||||
cancelChangeScheme() {
|
||||
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
||||
},
|
||||
changeScheme() {
|
||||
let schemeId = this.colorSchemeId;
|
||||
this.set(
|
||||
"model.color_scheme_id",
|
||||
schemeId === null ? null : parseInt(schemeId, 10)
|
||||
);
|
||||
this.model.saveChanges("color_scheme_id");
|
||||
},
|
||||
startEditingName() {
|
||||
this.set("oldName", this.get("model.name"));
|
||||
this.set("editingName", true);
|
||||
},
|
||||
cancelEditingName() {
|
||||
this.set("model.name", this.oldName);
|
||||
this.set("editingName", false);
|
||||
},
|
||||
finishedEditingName() {
|
||||
this.model.saveChanges("name");
|
||||
this.set("editingName", false);
|
||||
},
|
||||
|
||||
editTheme() {
|
||||
if (this.get("model.remote_theme.is_git")) {
|
||||
this.dialog.confirm({
|
||||
message: I18n.t("admin.customize.theme.edit_confirm"),
|
||||
didConfirm: () => this.transitionToEditRoute(),
|
||||
});
|
||||
} else {
|
||||
this.transitionToEditRoute();
|
||||
}
|
||||
},
|
||||
|
||||
applyDefault() {
|
||||
const model = this.model;
|
||||
model.saveChanges("default").then(() => {
|
||||
if (model.get("default")) {
|
||||
this.allThemes.forEach((theme) => {
|
||||
if (theme !== model && theme.get("default")) {
|
||||
theme.set("default", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
checkForThemeUpdates() {
|
||||
this.set("updatingRemote", true);
|
||||
this.model
|
||||
.checkForUpdates()
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("updatingRemote", false);
|
||||
applyUserSelectable() {
|
||||
this.model.saveChanges("user_selectable");
|
||||
},
|
||||
|
||||
applyAutoUpdateable() {
|
||||
this.model.saveChanges("auto_update");
|
||||
},
|
||||
|
||||
addChildTheme() {
|
||||
let themeId = parseInt(this.selectedChildThemeId, 10);
|
||||
let theme = this.allThemes.findBy("id", themeId);
|
||||
this.model.addChildTheme(theme).then(() => this.store.findAll("theme"));
|
||||
},
|
||||
|
||||
removeUpload(upload) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.customize.theme.delete_upload_confirm"),
|
||||
didConfirm: () => this.model.removeField(upload),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
addUploadModal() {
|
||||
showModal("admin-add-upload", { admin: true, name: "" });
|
||||
}
|
||||
removeChildTheme(theme) {
|
||||
this.model
|
||||
.removeChildTheme(theme)
|
||||
.then(() => this.store.findAll("theme"));
|
||||
},
|
||||
|
||||
@action
|
||||
addUpload(info) {
|
||||
let model = this.model;
|
||||
model.setField("common", info.name, "", info.upload_id, THEME_UPLOAD_VAR);
|
||||
model.saveChanges("theme_fields").catch((e) => popupAjaxError(e));
|
||||
}
|
||||
|
||||
@action
|
||||
cancelChangeScheme() {
|
||||
this.set("colorSchemeId", this.get("model.color_scheme_id"));
|
||||
}
|
||||
|
||||
@action
|
||||
changeScheme() {
|
||||
let schemeId = this.colorSchemeId;
|
||||
this.set(
|
||||
"model.color_scheme_id",
|
||||
schemeId === null ? null : parseInt(schemeId, 10)
|
||||
);
|
||||
this.model.saveChanges("color_scheme_id");
|
||||
}
|
||||
|
||||
@action
|
||||
startEditingName() {
|
||||
this.set("oldName", this.get("model.name"));
|
||||
this.set("editingName", true);
|
||||
}
|
||||
|
||||
@action
|
||||
cancelEditingName() {
|
||||
this.set("model.name", this.oldName);
|
||||
this.set("editingName", false);
|
||||
}
|
||||
|
||||
@action
|
||||
finishedEditingName() {
|
||||
this.model.saveChanges("name");
|
||||
this.set("editingName", false);
|
||||
}
|
||||
|
||||
@action
|
||||
editTheme() {
|
||||
if (this.get("model.remote_theme.is_git")) {
|
||||
this.dialog.confirm({
|
||||
message: I18n.t("admin.customize.theme.edit_confirm"),
|
||||
didConfirm: () => this.transitionToEditRoute(),
|
||||
destroy() {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.customize.delete_confirm", {
|
||||
theme_name: this.get("model.name"),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
const model = this.model;
|
||||
model.setProperties({ recentlyInstalled: false });
|
||||
model.destroyRecord().then(() => {
|
||||
this.allThemes.removeObject(model);
|
||||
this.transitionToRoute("adminCustomizeThemes");
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.transitionToEditRoute();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
applyDefault() {
|
||||
const model = this.model;
|
||||
model.saveChanges("default").then(() => {
|
||||
if (model.get("default")) {
|
||||
this.allThemes.forEach((theme) => {
|
||||
if (theme !== model && theme.get("default")) {
|
||||
theme.set("default", false);
|
||||
}
|
||||
switchType() {
|
||||
const relatives = this.get("model.component")
|
||||
? this.get("model.parentThemes")
|
||||
: this.get("model.childThemes");
|
||||
|
||||
let message = I18n.t(`${this.convertKey}_alert_generic`);
|
||||
|
||||
if (relatives && relatives.length > 0) {
|
||||
message = I18n.t(`${this.convertKey}_alert`, {
|
||||
relatives: relatives
|
||||
.map((relative) => relative.get("name"))
|
||||
.join(", "),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
applyUserSelectable() {
|
||||
this.model.saveChanges("user_selectable");
|
||||
}
|
||||
|
||||
@action
|
||||
applyAutoUpdateable() {
|
||||
this.model.saveChanges("auto_update");
|
||||
}
|
||||
|
||||
@action
|
||||
addChildTheme() {
|
||||
let themeId = parseInt(this.selectedChildThemeId, 10);
|
||||
let theme = this.allThemes.findBy("id", themeId);
|
||||
this.model.addChildTheme(theme).then(() => this.store.findAll("theme"));
|
||||
}
|
||||
|
||||
@action
|
||||
removeUpload(upload) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.customize.theme.delete_upload_confirm"),
|
||||
didConfirm: () => this.model.removeField(upload),
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
removeChildTheme(theme) {
|
||||
this.model.removeChildTheme(theme).then(() => this.store.findAll("theme"));
|
||||
}
|
||||
|
||||
@action
|
||||
destroyTheme() {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.customize.delete_confirm", {
|
||||
theme_name: this.get("model.name"),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
const model = this.model;
|
||||
model.setProperties({ recentlyInstalled: false });
|
||||
model.destroyRecord().then(() => {
|
||||
this.allThemes.removeObject(model);
|
||||
this.transitionToRoute("adminCustomizeThemes");
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
switchType() {
|
||||
const relatives = this.get("model.component")
|
||||
? this.get("model.parentThemes")
|
||||
: this.get("model.childThemes");
|
||||
|
||||
let message = I18n.t(`${this.convertKey}_alert_generic`);
|
||||
|
||||
if (relatives && relatives.length > 0) {
|
||||
message = I18n.t(`${this.convertKey}_alert`, {
|
||||
relatives: relatives.map((relative) => relative.get("name")).join(", "),
|
||||
return this.dialog.yesNoConfirm({
|
||||
message,
|
||||
didConfirm: () => this.commitSwitchType(),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
return this.dialog.yesNoConfirm({
|
||||
message,
|
||||
didConfirm: () => this.commitSwitchType(),
|
||||
});
|
||||
}
|
||||
enableComponent() {
|
||||
this.model.set("enabled", true);
|
||||
this.model
|
||||
.saveChanges("enabled")
|
||||
.catch(() => this.model.set("enabled", false));
|
||||
},
|
||||
|
||||
@action
|
||||
enableComponent() {
|
||||
this.model.set("enabled", true);
|
||||
this.model
|
||||
.saveChanges("enabled")
|
||||
.catch(() => this.model.set("enabled", false));
|
||||
}
|
||||
|
||||
@action
|
||||
disableComponent() {
|
||||
this.model.set("enabled", false);
|
||||
this.model
|
||||
.saveChanges("enabled")
|
||||
.catch(() => this.model.set("enabled", true));
|
||||
}
|
||||
}
|
||||
disableComponent() {
|
||||
this.model.set("enabled", false);
|
||||
this.model
|
||||
.saveChanges("enabled")
|
||||
.catch(() => this.model.set("enabled", true));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,21 +2,21 @@ import Controller from "@ember/controller";
|
||||
import { THEMES } from "admin/models/theme";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminCustomizeThemesController extends Controller {
|
||||
currentTab = THEMES;
|
||||
export default Controller.extend({
|
||||
currentTab: THEMES,
|
||||
|
||||
@discourseComputed("model", "model.@each.component")
|
||||
fullThemes(themes) {
|
||||
return themes.filter((t) => !t.get("component"));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model", "model.@each.component")
|
||||
childThemes(themes) {
|
||||
return themes.filter((t) => t.get("component"));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.content")
|
||||
installedThemes(content) {
|
||||
return content || [];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { computed } from "@ember/object";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import I18n from "I18n";
|
||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||
import Report from "admin/models/report";
|
||||
import { computed } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { makeArray } from "discourse-common/lib/helpers";
|
||||
@ -15,49 +15,41 @@ function staticReport(reportType) {
|
||||
});
|
||||
}
|
||||
|
||||
export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
PeriodComputationMixin
|
||||
) {
|
||||
@controller("exception") exceptionController;
|
||||
|
||||
isLoading = false;
|
||||
dashboardFetchedAt = null;
|
||||
|
||||
@setting("log_search_queries") logSearchQueriesEnabled;
|
||||
|
||||
@staticReport("users_by_type") usersByTypeReport;
|
||||
@staticReport("users_by_trust_level") usersByTrustLevelReport;
|
||||
@staticReport("storage_report") storageReport;
|
||||
export default Controller.extend(PeriodComputationMixin, {
|
||||
isLoading: false,
|
||||
dashboardFetchedAt: null,
|
||||
exceptionController: controller("exception"),
|
||||
logSearchQueriesEnabled: setting("log_search_queries"),
|
||||
|
||||
@discourseComputed("siteSettings.dashboard_general_tab_activity_metrics")
|
||||
activityMetrics(metrics) {
|
||||
return (metrics || "").split("|").filter(Boolean);
|
||||
}
|
||||
},
|
||||
|
||||
@computed("siteSettings.dashboard_hidden_reports")
|
||||
get hiddenReports() {
|
||||
hiddenReports: computed("siteSettings.dashboard_hidden_reports", function () {
|
||||
return (this.siteSettings.dashboard_hidden_reports || "")
|
||||
.split("|")
|
||||
.filter(Boolean);
|
||||
}
|
||||
}),
|
||||
|
||||
@computed("activityMetrics", "hiddenReports")
|
||||
get isActivityMetricsVisible() {
|
||||
return (
|
||||
this.activityMetrics.length &&
|
||||
this.activityMetrics.some((x) => !this.hiddenReports.includes(x))
|
||||
);
|
||||
}
|
||||
isActivityMetricsVisible: computed(
|
||||
"activityMetrics",
|
||||
"hiddenReports",
|
||||
function () {
|
||||
return (
|
||||
this.activityMetrics.length &&
|
||||
this.activityMetrics.some((x) => !this.hiddenReports.includes(x))
|
||||
);
|
||||
}
|
||||
),
|
||||
|
||||
@computed("hiddenReports")
|
||||
get isSearchReportsVisible() {
|
||||
isSearchReportsVisible: computed("hiddenReports", function () {
|
||||
return ["top_referred_topics", "trending_search"].some(
|
||||
(x) => !this.hiddenReports.includes(x)
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
@computed("hiddenReports")
|
||||
get isCommunityHealthVisible() {
|
||||
isCommunityHealthVisible: computed("hiddenReports", function () {
|
||||
return [
|
||||
"consolidated_page_views",
|
||||
"signups",
|
||||
@ -67,7 +59,7 @@ export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
"daily_engaged_users",
|
||||
"new_contributors",
|
||||
].some((x) => !this.hiddenReports.includes(x));
|
||||
}
|
||||
}),
|
||||
|
||||
@discourseComputed
|
||||
activityMetricsFilters() {
|
||||
@ -75,14 +67,14 @@ export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
startDate: this.lastMonth,
|
||||
endDate: this.today,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
topReferredTopicsOptions() {
|
||||
return {
|
||||
table: { total: false, limit: 8 },
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
topReferredTopicsFilters() {
|
||||
@ -90,7 +82,7 @@ export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
startDate: moment().subtract(6, "days").startOf("day"),
|
||||
endDate: this.today,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
trendingSearchFilters() {
|
||||
@ -98,21 +90,25 @@ export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
startDate: moment().subtract(1, "month").startOf("day"),
|
||||
endDate: this.today,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
trendingSearchOptions() {
|
||||
return {
|
||||
table: { total: false, limit: 8 },
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
trendingSearchDisabledLabel() {
|
||||
return I18n.t("admin.dashboard.reports.trending_search.disabled", {
|
||||
basePath: getURL(""),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
usersByTypeReport: staticReport("users_by_type"),
|
||||
usersByTrustLevelReport: staticReport("users_by_trust_level"),
|
||||
storageReport: staticReport("storage_report"),
|
||||
|
||||
fetchDashboard() {
|
||||
if (this.isLoading) {
|
||||
@ -141,14 +137,14 @@ export default class AdminDashboardGeneralController extends Controller.extend(
|
||||
})
|
||||
.finally(() => this.set("isLoading", false));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("startDate", "endDate")
|
||||
filters(startDate, endDate) {
|
||||
return { startDate, endDate };
|
||||
}
|
||||
},
|
||||
|
||||
_reportsForPeriodURL(period) {
|
||||
return getURL(`/admin?period=${period}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { computed } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import PeriodComputationMixin from "admin/mixins/period-computation";
|
||||
import { computed } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
||||
export default class AdminDashboardModerationController extends Controller.extend(
|
||||
PeriodComputationMixin
|
||||
) {
|
||||
export default Controller.extend(PeriodComputationMixin, {
|
||||
@discourseComputed
|
||||
flagsStatusOptions() {
|
||||
return {
|
||||
@ -15,15 +13,17 @@ export default class AdminDashboardModerationController extends Controller.exten
|
||||
perPage: 10,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@computed("siteSettings.dashboard_hidden_reports")
|
||||
get isModeratorsActivityVisible() {
|
||||
return !(this.siteSettings.dashboard_hidden_reports || "")
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.includes("moderators_activity");
|
||||
}
|
||||
isModeratorsActivityVisible: computed(
|
||||
"siteSettings.dashboard_hidden_reports",
|
||||
function () {
|
||||
return !(this.siteSettings.dashboard_hidden_reports || "")
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.includes("moderators_activity");
|
||||
}
|
||||
),
|
||||
|
||||
@discourseComputed
|
||||
userFlaggingRatioOptions() {
|
||||
@ -33,19 +33,19 @@ export default class AdminDashboardModerationController extends Controller.exten
|
||||
perPage: 10,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("startDate", "endDate")
|
||||
filters(startDate, endDate) {
|
||||
return { startDate, endDate };
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("lastWeek", "endDate")
|
||||
lastWeekfilters(startDate, endDate) {
|
||||
return { startDate, endDate };
|
||||
}
|
||||
},
|
||||
|
||||
_reportsForPeriodURL(period) {
|
||||
return getURL(`/admin/dashboard/moderation?period=${period}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,10 +2,10 @@ import Controller from "@ember/controller";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { action, get } from "@ember/object";
|
||||
import { get } from "@ember/object";
|
||||
|
||||
export default class AdminDashboardReportsController extends Controller {
|
||||
filter = null;
|
||||
export default Controller.extend({
|
||||
filter: null,
|
||||
|
||||
@discourseComputed(
|
||||
"model.[]",
|
||||
@ -29,14 +29,15 @@ export default class AdminDashboardReportsController extends Controller {
|
||||
reports = reports.filter((report) => !hiddenReports.includes(report.type));
|
||||
|
||||
return reports;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterReports(filter) {
|
||||
discourseDebounce(this, this._performFiltering, filter, INPUT_DELAY);
|
||||
}
|
||||
actions: {
|
||||
filterReports(filter) {
|
||||
discourseDebounce(this, this._performFiltering, filter, INPUT_DELAY);
|
||||
},
|
||||
},
|
||||
|
||||
_performFiltering(filter) {
|
||||
this.set("filter", filter);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,19 +1,17 @@
|
||||
import { action, computed } from "@ember/object";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import AdminDashboard from "admin/models/admin-dashboard";
|
||||
import VersionCheck from "admin/models/version-check";
|
||||
import { computed } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
|
||||
const PROBLEMS_CHECK_MINUTES = 1;
|
||||
|
||||
export default class AdminDashboardController extends Controller {
|
||||
@controller("exception") exceptionController;
|
||||
|
||||
isLoading = false;
|
||||
dashboardFetchedAt = null;
|
||||
|
||||
@setting("version_checks") showVersionChecks;
|
||||
export default Controller.extend({
|
||||
isLoading: false,
|
||||
dashboardFetchedAt: null,
|
||||
exceptionController: controller("exception"),
|
||||
showVersionChecks: setting("version_checks"),
|
||||
|
||||
@discourseComputed(
|
||||
"lowPriorityProblems.length",
|
||||
@ -23,29 +21,25 @@ export default class AdminDashboardController extends Controller {
|
||||
const problemsLength =
|
||||
lowPriorityProblemsLength + highPriorityProblemsLength;
|
||||
return this.currentUser.admin && problemsLength > 0;
|
||||
}
|
||||
},
|
||||
|
||||
@computed("siteSettings.dashboard_visible_tabs")
|
||||
get visibleTabs() {
|
||||
visibleTabs: computed("siteSettings.dashboard_visible_tabs", function () {
|
||||
return (this.siteSettings.dashboard_visible_tabs || "")
|
||||
.split("|")
|
||||
.filter(Boolean);
|
||||
}
|
||||
}),
|
||||
|
||||
@computed("visibleTabs")
|
||||
get isModerationTabVisible() {
|
||||
isModerationTabVisible: computed("visibleTabs", function () {
|
||||
return this.visibleTabs.includes("moderation");
|
||||
}
|
||||
}),
|
||||
|
||||
@computed("visibleTabs")
|
||||
get isSecurityTabVisible() {
|
||||
isSecurityTabVisible: computed("visibleTabs", function () {
|
||||
return this.visibleTabs.includes("security");
|
||||
}
|
||||
}),
|
||||
|
||||
@computed("visibleTabs")
|
||||
get isReportsTabVisible() {
|
||||
isReportsTabVisible: computed("visibleTabs", function () {
|
||||
return this.visibleTabs.includes("reports");
|
||||
}
|
||||
}),
|
||||
|
||||
fetchProblems() {
|
||||
if (this.isLoadingProblems) {
|
||||
@ -59,7 +53,7 @@ export default class AdminDashboardController extends Controller {
|
||||
) {
|
||||
this._loadProblems();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fetchDashboard() {
|
||||
const versionChecks = this.siteSettings.version_checks;
|
||||
@ -94,7 +88,7 @@ export default class AdminDashboardController extends Controller {
|
||||
this.set("isLoading", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_loadProblems() {
|
||||
this.setProperties({
|
||||
@ -114,15 +108,16 @@ export default class AdminDashboardController extends Controller {
|
||||
);
|
||||
})
|
||||
.finally(() => this.set("loadingProblems", false));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("problemsFetchedAt")
|
||||
problemsTimestamp(problemsFetchedAt) {
|
||||
return moment(problemsFetchedAt).locale("en").format("LLL");
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
refreshProblems() {
|
||||
this._loadProblems();
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
refreshProblems() {
|
||||
this._loadProblems();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default class AdminEmailAdvancedTestController extends Controller {
|
||||
email = null;
|
||||
text = null;
|
||||
elided = null;
|
||||
format = null;
|
||||
loading = null;
|
||||
export default Controller.extend({
|
||||
email: null,
|
||||
text: null,
|
||||
elided: null,
|
||||
format: null,
|
||||
loading: null,
|
||||
|
||||
@action
|
||||
run() {
|
||||
this.set("loading", true);
|
||||
actions: {
|
||||
run() {
|
||||
this.set("loading", true);
|
||||
|
||||
ajax("/admin/email/advanced-test", {
|
||||
type: "POST",
|
||||
data: { email: this.email },
|
||||
})
|
||||
.then((data) => {
|
||||
this.setProperties({
|
||||
text: data.text,
|
||||
elided: data.elided,
|
||||
format: data.format,
|
||||
});
|
||||
ajax("/admin/email/advanced-test", {
|
||||
type: "POST",
|
||||
data: { email: this.email },
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.set("loading", false));
|
||||
}
|
||||
}
|
||||
.then((data) => {
|
||||
this.setProperties({
|
||||
text: data.text,
|
||||
elided: data.elided,
|
||||
format: data.format,
|
||||
});
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.set("loading", false));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class AdminEmailBouncedController extends AdminEmailLogsController {
|
||||
export default AdminEmailLogsController.extend({
|
||||
@action
|
||||
handleShowIncomingEmail(id, event) {
|
||||
event?.preventDefault();
|
||||
this.send("showIncomingEmail", id);
|
||||
}
|
||||
},
|
||||
|
||||
@observes("filter.{status,user,address,type}")
|
||||
filterEmailLogs() {
|
||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,22 +1,21 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default class AdminEmailIndexController extends Controller {
|
||||
@service dialog;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
|
||||
/**
|
||||
Is the "send test email" button disabled?
|
||||
|
||||
@property sendTestEmailDisabled
|
||||
**/
|
||||
@empty("testEmailAddress") sendTestEmailDisabled;
|
||||
sendTestEmailDisabled: empty("testEmailAddress"),
|
||||
|
||||
/**
|
||||
Clears the 'sentTestEmail' property on successful send.
|
||||
@ -26,40 +25,43 @@ export default class AdminEmailIndexController extends Controller {
|
||||
@observes("testEmailAddress")
|
||||
testEmailAddressChanged() {
|
||||
this.set("sentTestEmail", false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Sends a test email to the currently entered email address
|
||||
actions: {
|
||||
/**
|
||||
Sends a test email to the currently entered email address
|
||||
|
||||
@method sendTestEmail
|
||||
**/
|
||||
@action
|
||||
sendTestEmail() {
|
||||
this.setProperties({
|
||||
sendingEmail: true,
|
||||
sentTestEmail: false,
|
||||
});
|
||||
@method sendTestEmail
|
||||
**/
|
||||
sendTestEmail() {
|
||||
this.setProperties({
|
||||
sendingEmail: true,
|
||||
sentTestEmail: false,
|
||||
});
|
||||
|
||||
ajax("/admin/email/test", {
|
||||
type: "POST",
|
||||
data: { email_address: this.testEmailAddress },
|
||||
})
|
||||
.then((response) =>
|
||||
this.set("sentTestEmailMessage", response.sent_test_email_message)
|
||||
)
|
||||
.catch((e) => {
|
||||
if (e.jqXHR.responseJSON?.errors) {
|
||||
this.dialog.alert({
|
||||
message: htmlSafe(
|
||||
I18n.t("admin.email.error", {
|
||||
server_error: escapeExpression(e.jqXHR.responseJSON.errors[0]),
|
||||
})
|
||||
),
|
||||
});
|
||||
} else {
|
||||
this.dialog.alert({ message: I18n.t("admin.email.test_error") });
|
||||
}
|
||||
ajax("/admin/email/test", {
|
||||
type: "POST",
|
||||
data: { email_address: this.testEmailAddress },
|
||||
})
|
||||
.finally(() => this.set("sendingEmail", false));
|
||||
}
|
||||
}
|
||||
.then((response) =>
|
||||
this.set("sentTestEmailMessage", response.sent_test_email_message)
|
||||
)
|
||||
.catch((e) => {
|
||||
if (e.jqXHR.responseJSON?.errors) {
|
||||
this.dialog.alert({
|
||||
message: htmlSafe(
|
||||
I18n.t("admin.email.error", {
|
||||
server_error: escapeExpression(
|
||||
e.jqXHR.responseJSON.errors[0]
|
||||
),
|
||||
})
|
||||
),
|
||||
});
|
||||
} else {
|
||||
this.dialog.alert({ message: I18n.t("admin.email.test_error") });
|
||||
}
|
||||
})
|
||||
.finally(() => this.set("sendingEmail", false));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
import Controller from "@ember/controller";
|
||||
import EmailLog from "admin/models/email-log";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import EmberObject from "@ember/object";
|
||||
|
||||
export default class AdminEmailLogsController extends Controller {
|
||||
loading = false;
|
||||
filter = EmberObject.create();
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("filter", EmberObject.create());
|
||||
},
|
||||
loadLogs(sourceModel, loadMore) {
|
||||
if ((loadMore && this.loading) || this.get("model.allLoaded")) {
|
||||
return;
|
||||
@ -35,10 +38,11 @@ export default class AdminEmailLogsController extends Controller {
|
||||
}
|
||||
})
|
||||
.finally(() => this.set("loading", false));
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.loadLogs(EmailLog, true);
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(EmailLog, true);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,67 +1,66 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { empty, notEmpty, or } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import EmailPreview from "admin/models/email-preview";
|
||||
import { action, get } from "@ember/object";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminEmailPreviewDigestController extends Controller {
|
||||
@service dialog;
|
||||
|
||||
username = null;
|
||||
lastSeen = null;
|
||||
|
||||
@empty("email") emailEmpty;
|
||||
@or("emailEmpty", "sendingEmail") sendEmailDisabled;
|
||||
@notEmpty("model.html_content") showSendEmailForm;
|
||||
@empty("model.html_content") htmlEmpty;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
username: null,
|
||||
lastSeen: null,
|
||||
emailEmpty: empty("email"),
|
||||
sendEmailDisabled: or("emailEmpty", "sendingEmail"),
|
||||
showSendEmailForm: notEmpty("model.html_content"),
|
||||
htmlEmpty: empty("model.html_content"),
|
||||
|
||||
@action
|
||||
toggleShowHtml(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showHtml");
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
updateUsername(selected) {
|
||||
this.set("username", get(selected, "firstObject"));
|
||||
}
|
||||
actions: {
|
||||
updateUsername(selected) {
|
||||
this.set("username", get(selected, "firstObject"));
|
||||
},
|
||||
|
||||
@action
|
||||
refresh() {
|
||||
const model = this.model;
|
||||
refresh() {
|
||||
const model = this.model;
|
||||
|
||||
this.set("loading", true);
|
||||
this.set("sentEmail", false);
|
||||
this.set("loading", true);
|
||||
this.set("sentEmail", false);
|
||||
|
||||
let username = this.username;
|
||||
if (!username) {
|
||||
username = this.currentUser.get("username");
|
||||
this.set("username", username);
|
||||
}
|
||||
let username = this.username;
|
||||
if (!username) {
|
||||
username = this.currentUser.get("username");
|
||||
this.set("username", username);
|
||||
}
|
||||
|
||||
EmailPreview.findDigest(username, this.lastSeen).then((email) => {
|
||||
model.setProperties(email.getProperties("html_content", "text_content"));
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
sendEmail() {
|
||||
this.set("sendingEmail", true);
|
||||
this.set("sentEmail", false);
|
||||
|
||||
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
|
||||
.then((result) => {
|
||||
if (result.errors) {
|
||||
this.dialog.alert(result.errors);
|
||||
} else {
|
||||
this.set("sentEmail", true);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("sendingEmail", false);
|
||||
EmailPreview.findDigest(username, this.lastSeen).then((email) => {
|
||||
model.setProperties(
|
||||
email.getProperties("html_content", "text_content")
|
||||
);
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
sendEmail() {
|
||||
this.set("sendingEmail", true);
|
||||
this.set("sentEmail", false);
|
||||
|
||||
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
|
||||
.then((result) => {
|
||||
if (result.errors) {
|
||||
this.dialog.alert(result.errors);
|
||||
} else {
|
||||
this.set("sentEmail", true);
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => {
|
||||
this.set("sendingEmail", false);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { action } from "@ember/object";
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminEmailReceivedController extends AdminEmailLogsController {
|
||||
export default AdminEmailLogsController.extend({
|
||||
@observes("filter.{status,from,to,subject}")
|
||||
filterIncomingEmails() {
|
||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,23 +2,24 @@ import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import IncomingEmail from "admin/models/incoming-email";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class AdminEmailRejectedController extends AdminEmailLogsController {
|
||||
export default AdminEmailLogsController.extend({
|
||||
@observes("filter.{status,from,to,subject,error}")
|
||||
filterIncomingEmails() {
|
||||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
handleShowIncomingEmail(id, event) {
|
||||
event?.preventDefault();
|
||||
this.send("showIncomingEmail", id);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminEmailSentController extends AdminEmailLogsController {
|
||||
export default AdminEmailLogsController.extend({
|
||||
@observes("filter.{status,user,address,type,reply_key}")
|
||||
filterEmailLogs() {
|
||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminEmailSkippedController extends AdminEmailLogsController {
|
||||
export default AdminEmailLogsController.extend({
|
||||
@observes("filter.{status,user,address,type}")
|
||||
filterEmailLogs() {
|
||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,30 +1,25 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default class AdminEmbeddingController extends Controller {
|
||||
saved = false;
|
||||
embedding = null;
|
||||
export default Controller.extend({
|
||||
saved: false,
|
||||
embedding: null,
|
||||
|
||||
// show settings if we have at least one created host
|
||||
@discourseComputed("embedding.embeddable_hosts.@each.isCreated")
|
||||
showSecondary() {
|
||||
const hosts = this.get("embedding.embeddable_hosts");
|
||||
return hosts.length && hosts.findBy("isCreated");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("embedding.base_url")
|
||||
embeddingCode(baseUrl) {
|
||||
const html = `<div id='discourse-comments'></div>
|
||||
<meta name='discourse-username' content='DISCOURSE_USERNAME'>
|
||||
|
||||
<script type="text/javascript">
|
||||
DiscourseEmbed = {
|
||||
discourseUrl: '${baseUrl}/',
|
||||
discourseEmbedUrl: 'EMBED_URL',
|
||||
// className: 'CLASS_NAME',
|
||||
};
|
||||
DiscourseEmbed = { discourseUrl: '${baseUrl}/',
|
||||
discourseEmbedUrl: 'REPLACE_ME' };
|
||||
|
||||
(function() {
|
||||
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
|
||||
@ -34,28 +29,27 @@ export default class AdminEmbeddingController extends Controller {
|
||||
</script>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
saveChanges() {
|
||||
const embedding = this.embedding;
|
||||
const updates = embedding.getProperties(embedding.get("fields"));
|
||||
actions: {
|
||||
saveChanges() {
|
||||
const embedding = this.embedding;
|
||||
const updates = embedding.getProperties(embedding.get("fields"));
|
||||
|
||||
this.set("saved", false);
|
||||
this.embedding
|
||||
.update(updates)
|
||||
.then(() => this.set("saved", true))
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
this.set("saved", false);
|
||||
this.embedding
|
||||
.update(updates)
|
||||
.then(() => this.set("saved", true))
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
addHost() {
|
||||
const host = this.store.createRecord("embeddable-host");
|
||||
this.get("embedding.embeddable_hosts").pushObject(host);
|
||||
}
|
||||
addHost() {
|
||||
const host = this.store.createRecord("embeddable-host");
|
||||
this.get("embedding.embeddable_hosts").pushObject(host);
|
||||
},
|
||||
|
||||
@action
|
||||
deleteHost(host) {
|
||||
this.get("embedding.embeddable_hosts").removeObject(host);
|
||||
}
|
||||
}
|
||||
deleteHost(host) {
|
||||
this.get("embedding.embeddable_hosts").removeObject(host);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,46 +1,49 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { sort } from "@ember/object/computed";
|
||||
import EmberObject, { action, computed } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { sort } from "@ember/object/computed";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
const ALL_FILTER = "all";
|
||||
|
||||
export default class AdminEmojisController extends Controller {
|
||||
@service dialog;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
filter: null,
|
||||
sorting: null,
|
||||
|
||||
filter = null;
|
||||
sorting = null;
|
||||
|
||||
@sort("filteredEmojis.[]", "sorting") sortedEmojis;
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this._super(...arguments);
|
||||
|
||||
this.setProperties({
|
||||
filter: ALL_FILTER,
|
||||
sorting: ["group", "name"],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@computed("model")
|
||||
get emojiGroups() {
|
||||
return this.model.mapBy("group").uniq();
|
||||
}
|
||||
sortedEmojis: sort("filteredEmojis.[]", "sorting"),
|
||||
|
||||
@computed("emojiGroups.[]")
|
||||
get sortingGroups() {
|
||||
return [ALL_FILTER].concat(this.emojiGroups);
|
||||
}
|
||||
emojiGroups: computed("model", {
|
||||
get() {
|
||||
return this.model.mapBy("group").uniq();
|
||||
},
|
||||
}),
|
||||
|
||||
@computed("model.[]", "filter")
|
||||
get filteredEmojis() {
|
||||
if (!this.filter || this.filter === ALL_FILTER) {
|
||||
return this.model;
|
||||
} else {
|
||||
return this.model.filterBy("group", this.filter);
|
||||
}
|
||||
}
|
||||
sortingGroups: computed("emojiGroups.[]", {
|
||||
get() {
|
||||
return [ALL_FILTER].concat(this.emojiGroups);
|
||||
},
|
||||
}),
|
||||
|
||||
filteredEmojis: computed("model.[]", "filter", {
|
||||
get() {
|
||||
if (!this.filter || this.filter === ALL_FILTER) {
|
||||
return this.model;
|
||||
} else {
|
||||
return this.model.filterBy("group", this.filter);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
_highlightEmojiList() {
|
||||
const customEmojiListEl = document.querySelector("#custom_emoji");
|
||||
@ -53,12 +56,12 @@ export default class AdminEmojisController extends Controller {
|
||||
customEmojiListEl.classList.remove("highlighted");
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterGroups(value) {
|
||||
this.set("filter", value);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
emojiUploaded(emoji, group) {
|
||||
@ -66,7 +69,7 @@ export default class AdminEmojisController extends Controller {
|
||||
emoji.group = group;
|
||||
this.model.pushObject(EmberObject.create(emoji));
|
||||
this._highlightEmojiList();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
destroyEmoji(emoji) {
|
||||
@ -82,5 +85,5 @@ export default class AdminEmojisController extends Controller {
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import ScreenedEmail from "admin/models/screened-email";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
|
||||
export default class AdminLogsScreenedEmailsController extends Controller {
|
||||
loading = false;
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
@action
|
||||
clearBlock(row) {
|
||||
row.clearBlock().then(function () {
|
||||
// feeling lazy
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
actions: {
|
||||
clearBlock(row) {
|
||||
row.clearBlock().then(function () {
|
||||
// feeling lazy
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
exportScreenedEmailList() {
|
||||
exportEntity("screened_email").then(outputExportResult);
|
||||
}
|
||||
exportScreenedEmailList() {
|
||||
exportEntity("screened_email").then(outputExportResult);
|
||||
},
|
||||
},
|
||||
|
||||
show() {
|
||||
this.set("loading", true);
|
||||
@ -26,5 +25,5 @@ export default class AdminLogsScreenedEmailsController extends Controller {
|
||||
this.set("model", result);
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,32 +1,31 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import ScreenedIpAddress from "admin/models/screened-ip-address";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminLogsScreenedIpAddressesController extends Controller {
|
||||
@service dialog;
|
||||
|
||||
loading = false;
|
||||
filter = null;
|
||||
savedIpAddress = null;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
loading: false,
|
||||
filter: null,
|
||||
savedIpAddress: null,
|
||||
|
||||
_debouncedShow() {
|
||||
this.set("loading", true);
|
||||
ScreenedIpAddress.findAll(this.filter).then((result) => {
|
||||
this.setProperties({ model: result, loading: false });
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@observes("filter")
|
||||
show() {
|
||||
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
edit(record, event) {
|
||||
@ -35,86 +34,81 @@ export default class AdminLogsScreenedIpAddressesController extends Controller {
|
||||
this.set("savedIpAddress", record.get("ip_address"));
|
||||
}
|
||||
record.set("editing", true);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
allow(record) {
|
||||
record.set("action_name", "do_nothing");
|
||||
record.save();
|
||||
}
|
||||
actions: {
|
||||
allow(record) {
|
||||
record.set("action_name", "do_nothing");
|
||||
record.save();
|
||||
},
|
||||
|
||||
@action
|
||||
block(record) {
|
||||
record.set("action_name", "block");
|
||||
record.save();
|
||||
}
|
||||
block(record) {
|
||||
record.set("action_name", "block");
|
||||
record.save();
|
||||
},
|
||||
|
||||
@action
|
||||
cancel(record) {
|
||||
const savedIpAddress = this.savedIpAddress;
|
||||
if (savedIpAddress && record.get("editing")) {
|
||||
record.set("ip_address", savedIpAddress);
|
||||
}
|
||||
record.set("editing", false);
|
||||
}
|
||||
cancel(record) {
|
||||
const savedIpAddress = this.savedIpAddress;
|
||||
if (savedIpAddress && record.get("editing")) {
|
||||
record.set("ip_address", savedIpAddress);
|
||||
}
|
||||
record.set("editing", false);
|
||||
},
|
||||
|
||||
@action
|
||||
save(record) {
|
||||
const wasEditing = record.get("editing");
|
||||
record.set("editing", false);
|
||||
record
|
||||
.save()
|
||||
.then(() => this.set("savedIpAddress", null))
|
||||
.catch((e) => {
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
this.dialog.alert(
|
||||
I18n.t("generic_error_with_reason", {
|
||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
if (wasEditing) {
|
||||
record.set("editing", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
destroyRecord(record) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.logs.screened_ips.delete_confirm", {
|
||||
ip_address: record.get("ip_address"),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
return record
|
||||
.destroy()
|
||||
.then((deleted) => {
|
||||
if (deleted) {
|
||||
this.model.removeObject(record);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
save(record) {
|
||||
const wasEditing = record.get("editing");
|
||||
record.set("editing", false);
|
||||
record
|
||||
.save()
|
||||
.then(() => this.set("savedIpAddress", null))
|
||||
.catch((e) => {
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
this.dialog.alert(
|
||||
I18n.t("generic_error_with_reason", {
|
||||
error: `http: ${e.status} - ${e.body}`,
|
||||
error: e.jqXHR.responseJSON.errors.join(". "),
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
if (wasEditing) {
|
||||
record.set("editing", true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
recordAdded(arg) {
|
||||
this.model.unshiftObject(arg);
|
||||
}
|
||||
destroy(record) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.logs.screened_ips.delete_confirm", {
|
||||
ip_address: record.get("ip_address"),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
return record
|
||||
.destroy()
|
||||
.then((deleted) => {
|
||||
if (deleted) {
|
||||
this.model.removeObject(record);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
this.dialog.alert(
|
||||
I18n.t("generic_error_with_reason", {
|
||||
error: `http: ${e.status} - ${e.body}`,
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
exportScreenedIpList() {
|
||||
exportEntity("screened_ip").then(outputExportResult);
|
||||
}
|
||||
}
|
||||
recordAdded(arg) {
|
||||
this.model.unshiftObject(arg);
|
||||
},
|
||||
|
||||
exportScreenedIpList() {
|
||||
exportEntity("screened_ip").then(outputExportResult);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import ScreenedUrl from "admin/models/screened-url";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
|
||||
export default class AdminLogsScreenedUrlsController extends Controller {
|
||||
loading = false;
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
show() {
|
||||
this.set("loading", true);
|
||||
@ -13,10 +12,11 @@ export default class AdminLogsScreenedUrlsController extends Controller {
|
||||
this.set("model", result);
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
exportScreenedUrlList() {
|
||||
exportEntity("screened_url").then(outputExportResult);
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
exportScreenedUrlList() {
|
||||
exportEntity("screened_url").then(outputExportResult);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -7,21 +7,22 @@ import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
queryParams = ["filters"];
|
||||
model = null;
|
||||
filters = null;
|
||||
userHistoryActions = null;
|
||||
export default Controller.extend({
|
||||
queryParams: ["filters"],
|
||||
|
||||
model: null,
|
||||
filters: null,
|
||||
userHistoryActions: null,
|
||||
|
||||
@discourseComputed("filters.action_name")
|
||||
actionFilter(name) {
|
||||
return name ? I18n.t("admin.logs.staff_actions.actions." + name) : null;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("filters")
|
||||
filtersExists(filters) {
|
||||
return filters && Object.keys(filters).length > 0;
|
||||
}
|
||||
},
|
||||
|
||||
_refresh() {
|
||||
this.store.findAll("staff-action-log", this.filters).then((result) => {
|
||||
@ -43,11 +44,11 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
scheduleRefresh() {
|
||||
scheduleOnce("afterRender", this, this._refresh);
|
||||
}
|
||||
},
|
||||
|
||||
resetFilters() {
|
||||
this.setProperties({
|
||||
@ -55,7 +56,7 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
filters: EmberObject.create(),
|
||||
});
|
||||
this.scheduleRefresh();
|
||||
}
|
||||
},
|
||||
|
||||
changeFilters(props) {
|
||||
this.set("model", EmberObject.create({ loadingMore: true }));
|
||||
@ -75,7 +76,7 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
|
||||
this.send("onFiltersChange", this.filters);
|
||||
this.scheduleRefresh();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterActionIdChanged(filterActionId) {
|
||||
@ -86,7 +87,7 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
.action_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
clearFilter(key, event) {
|
||||
@ -101,14 +102,14 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
} else {
|
||||
this.changeFilters({ [key]: null });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
clearAllFilters(event) {
|
||||
event?.preventDefault();
|
||||
this.set("filterActionId", null);
|
||||
this.resetFilters();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterByAction(logItem, event) {
|
||||
@ -118,35 +119,35 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
action_id: logItem.get("action"),
|
||||
custom_type: logItem.get("custom_type"),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterByStaffUser(acting_user, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ acting_user: acting_user.username });
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterByTargetUser(target_user, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ target_user: target_user.username });
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
filterBySubject(subject, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ subject });
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
exportStaffActionLogs() {
|
||||
exportEntity("staff_action").then(outputExportResult);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.model.loadMore();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
showDetailsModal(model, event) {
|
||||
@ -156,7 +157,7 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
admin: true,
|
||||
modalClass: "log-details-modal",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
showCustomDetailsModal(model, event) {
|
||||
@ -167,5 +168,5 @@ export default class AdminLogsStaffActionLogsController extends Controller {
|
||||
modalClass: "history-modal",
|
||||
});
|
||||
modal.loadDiff();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,63 +1,59 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { or } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import Permalink from "admin/models/permalink";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { clipboardCopy } from "discourse/lib/utilities";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { or } from "@ember/object/computed";
|
||||
|
||||
export default class AdminPermalinksController extends Controller {
|
||||
@service dialog;
|
||||
|
||||
loading = false;
|
||||
filter = null;
|
||||
|
||||
@or("model.length", "filter") showSearch;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
loading: false,
|
||||
filter: null,
|
||||
showSearch: or("model.length", "filter"),
|
||||
|
||||
_debouncedShow() {
|
||||
Permalink.findAll(this.filter).then((result) => {
|
||||
this.set("model", result);
|
||||
this.set("loading", false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@observes("filter")
|
||||
show() {
|
||||
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
recordAdded(arg) {
|
||||
this.model.unshiftObject(arg);
|
||||
}
|
||||
actions: {
|
||||
recordAdded(arg) {
|
||||
this.model.unshiftObject(arg);
|
||||
},
|
||||
|
||||
@action
|
||||
copyUrl(pl) {
|
||||
let linkElement = document.querySelector(`#admin-permalink-${pl.id}`);
|
||||
clipboardCopy(linkElement.textContent);
|
||||
}
|
||||
copyUrl(pl) {
|
||||
let linkElement = document.querySelector(`#admin-permalink-${pl.id}`);
|
||||
clipboardCopy(linkElement.textContent);
|
||||
},
|
||||
|
||||
@action
|
||||
destroyRecord(record) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.permalink.delete_confirm"),
|
||||
didConfirm: () => {
|
||||
return record.destroy().then(
|
||||
(deleted) => {
|
||||
if (deleted) {
|
||||
this.model.removeObject(record);
|
||||
} else {
|
||||
destroy(record) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.permalink.delete_confirm"),
|
||||
didConfirm: () => {
|
||||
return record.destroy().then(
|
||||
(deleted) => {
|
||||
if (deleted) {
|
||||
this.model.removeObject(record);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
},
|
||||
function () {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
},
|
||||
function () {
|
||||
this.dialog.alert(I18n.t("generic_error"));
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller from "@ember/controller";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminPluginsController extends Controller {
|
||||
@service router;
|
||||
export default Controller.extend({
|
||||
router: service(),
|
||||
|
||||
get adminRoutes() {
|
||||
return this.allAdminRoutes.filter((r) => this.routeExists(r.full_location));
|
||||
}
|
||||
},
|
||||
|
||||
get brokenAdminRoutes() {
|
||||
return this.allAdminRoutes.filter(
|
||||
(r) => !this.routeExists(r.full_location)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
get allAdminRoutes() {
|
||||
return this.model
|
||||
@ -21,7 +21,7 @@ export default class AdminPluginsController extends Controller {
|
||||
return p.admin_route;
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
},
|
||||
|
||||
routeExists(routeName) {
|
||||
try {
|
||||
@ -30,5 +30,5 @@ export default class AdminPluginsController extends Controller {
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminReportsShowController extends Controller {
|
||||
queryParams = ["start_date", "end_date", "filters", "chart_grouping", "mode"];
|
||||
start_date = null;
|
||||
end_date = null;
|
||||
filters = null;
|
||||
chart_grouping = null;
|
||||
export default Controller.extend({
|
||||
queryParams: ["start_date", "end_date", "filters", "chart_grouping", "mode"],
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
filters: null,
|
||||
chart_grouping: null,
|
||||
|
||||
@discourseComputed("model.type")
|
||||
reportOptions(type) {
|
||||
@ -19,5 +19,5 @@ export default class AdminReportsShowController extends Controller {
|
||||
options.chartGrouping = this.chart_grouping;
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,19 +2,24 @@ import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
export const DEFAULT_PERIOD = "yearly";
|
||||
|
||||
export default class AdminSearchLogsIndexController extends Controller {
|
||||
loading = false;
|
||||
period = DEFAULT_PERIOD;
|
||||
searchType = "all";
|
||||
searchTypeOptions = [
|
||||
{
|
||||
id: "all",
|
||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||
},
|
||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||
{
|
||||
id: "full_page",
|
||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||
},
|
||||
];
|
||||
}
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
period: DEFAULT_PERIOD,
|
||||
searchType: "all",
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.searchTypeOptions = [
|
||||
{
|
||||
id: "all",
|
||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||
},
|
||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||
{
|
||||
id: "full_page",
|
||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,24 +2,29 @@ import Controller from "@ember/controller";
|
||||
import { DEFAULT_PERIOD } from "admin/controllers/admin-search-logs-index";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default class AdminSearchLogsTermController extends Controller {
|
||||
loading = false;
|
||||
term = null;
|
||||
period = DEFAULT_PERIOD;
|
||||
searchType = "all";
|
||||
searchTypeOptions = [
|
||||
{
|
||||
id: "all",
|
||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||
},
|
||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||
{
|
||||
id: "full_page",
|
||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||
},
|
||||
{
|
||||
id: "click_through_only",
|
||||
name: I18n.t("admin.logs.search_logs.types.click_through_only"),
|
||||
},
|
||||
];
|
||||
}
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
term: null,
|
||||
period: DEFAULT_PERIOD,
|
||||
searchType: "all",
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.searchTypeOptions = [
|
||||
{
|
||||
id: "all",
|
||||
name: I18n.t("admin.logs.search_logs.types.all_search_types"),
|
||||
},
|
||||
{ id: "header", name: I18n.t("admin.logs.search_logs.types.header") },
|
||||
{
|
||||
id: "full_page",
|
||||
name: I18n.t("admin.logs.search_logs.types.full_page"),
|
||||
},
|
||||
{
|
||||
id: "click_through_only",
|
||||
name: I18n.t("admin.logs.search_logs.types.click_through_only"),
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminSiteSettingsCategoryController extends Controller {
|
||||
@controller adminSiteSettings;
|
||||
|
||||
categoryNameKey = null;
|
||||
export default Controller.extend({
|
||||
adminSiteSettings: controller(),
|
||||
categoryNameKey: null,
|
||||
|
||||
@discourseComputed("adminSiteSettings.visibleSiteSettings", "categoryNameKey")
|
||||
category(categories, nameKey) {
|
||||
return (categories || []).findBy("nameKey", nameKey);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("category")
|
||||
filteredContent(category) {
|
||||
return category ? category.siteSettings : [];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,23 +1,20 @@
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { debounce } from "discourse-common/utils/decorators";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { debounce, observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class AdminSiteSettingsController extends Controller {
|
||||
filter = null;
|
||||
|
||||
@alias("model") allSiteSettings;
|
||||
|
||||
visibleSiteSettings = null;
|
||||
onlyOverridden = false;
|
||||
export default Controller.extend({
|
||||
filter: null,
|
||||
allSiteSettings: alias("model"),
|
||||
visibleSiteSettings: null,
|
||||
onlyOverridden: false,
|
||||
|
||||
filterContentNow(category) {
|
||||
// If we have no content, don't bother filtering anything
|
||||
if (isEmpty(this.allSiteSettings)) {
|
||||
if (!!isEmpty(this.allSiteSettings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -76,7 +73,7 @@ export default class AdminSiteSettingsController extends Controller {
|
||||
setting.includes(filter) ||
|
||||
setting.replace(/_/g, " ").includes(filter) ||
|
||||
item.get("description").toLowerCase().includes(filter) ||
|
||||
(item.get("value") || "").toString().toLowerCase().includes(filter)
|
||||
(item.get("value") || "").toLowerCase().includes(filter)
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
@ -112,13 +109,9 @@ export default class AdminSiteSettingsController extends Controller {
|
||||
"adminSiteSettingsCategory",
|
||||
category || "all_results"
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@observes("filter", "onlyOverridden", "model")
|
||||
optsChanged() {
|
||||
this.filterContent();
|
||||
}
|
||||
|
||||
@debounce(INPUT_DELAY)
|
||||
filterContent() {
|
||||
if (this._skipBounce) {
|
||||
@ -126,12 +119,12 @@ export default class AdminSiteSettingsController extends Controller {
|
||||
} else {
|
||||
this.filterContentNow(this.categoryNameKey);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
clearFilter() {
|
||||
this.setProperties({ filter: "", onlyOverridden: false });
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
toggleMenu() {
|
||||
@ -139,5 +132,5 @@ export default class AdminSiteSettingsController extends Controller {
|
||||
["mobile-closed", "mobile-open"].forEach((state) => {
|
||||
adminDetail.classList.toggle(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
let lastSearch;
|
||||
|
||||
export default class AdminSiteTextIndexController extends Controller {
|
||||
searching = false;
|
||||
siteTexts = null;
|
||||
preferred = false;
|
||||
queryParams = ["q", "overridden", "locale"];
|
||||
locale = null;
|
||||
q = null;
|
||||
overridden = false;
|
||||
export default Controller.extend({
|
||||
searching: false,
|
||||
siteTexts: null,
|
||||
preferred: false,
|
||||
queryParams: ["q", "overridden", "locale"],
|
||||
locale: null,
|
||||
|
||||
q: null,
|
||||
overridden: false,
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("locale", this.siteSettings.default_locale);
|
||||
}
|
||||
},
|
||||
|
||||
_performSearch() {
|
||||
this.store
|
||||
@ -26,12 +26,12 @@ export default class AdminSiteTextIndexController extends Controller {
|
||||
this.set("siteTexts", results);
|
||||
})
|
||||
.finally(() => this.set("searching", false));
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed()
|
||||
availableLocales() {
|
||||
return JSON.parse(this.siteSettings.available_locales);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("locale")
|
||||
fallbackLocaleFullName() {
|
||||
@ -40,41 +40,39 @@ export default class AdminSiteTextIndexController extends Controller {
|
||||
return l.value === this.siteTexts.extras.fallback_locale;
|
||||
}).name;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
edit(siteText) {
|
||||
this.transitionToRoute("adminSiteText.edit", siteText.get("id"), {
|
||||
queryParams: {
|
||||
locale: this.locale,
|
||||
},
|
||||
});
|
||||
}
|
||||
actions: {
|
||||
edit(siteText) {
|
||||
this.transitionToRoute("adminSiteText.edit", siteText.get("id"), {
|
||||
queryParams: {
|
||||
locale: this.locale,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
toggleOverridden() {
|
||||
this.toggleProperty("overridden");
|
||||
this.set("searching", true);
|
||||
discourseDebounce(this, this._performSearch, 400);
|
||||
}
|
||||
|
||||
@action
|
||||
search() {
|
||||
const q = this.q;
|
||||
if (q !== lastSearch) {
|
||||
toggleOverridden() {
|
||||
this.toggleProperty("overridden");
|
||||
this.set("searching", true);
|
||||
discourseDebounce(this, this._performSearch, 400);
|
||||
lastSearch = q;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
updateLocale(value) {
|
||||
this.setProperties({
|
||||
searching: true,
|
||||
locale: value,
|
||||
});
|
||||
search() {
|
||||
const q = this.q;
|
||||
if (q !== lastSearch) {
|
||||
this.set("searching", true);
|
||||
discourseDebounce(this, this._performSearch, 400);
|
||||
lastSearch = q;
|
||||
}
|
||||
},
|
||||
|
||||
discourseDebounce(this, this._performSearch, 400);
|
||||
}
|
||||
}
|
||||
updateLocale(value) {
|
||||
this.setProperties({
|
||||
searching: true,
|
||||
locale: value,
|
||||
});
|
||||
|
||||
discourseDebounce(this, this._performSearch, 400);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { alias, sort } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { alias, sort } from "@ember/object/computed";
|
||||
import GrantBadgeController from "discourse/mixins/grant-badge-controller";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { next } from "@ember/runloop";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminUserBadgesController extends Controller.extend(
|
||||
GrantBadgeController
|
||||
) {
|
||||
@service dialog;
|
||||
@controller adminUser;
|
||||
export default Controller.extend(GrantBadgeController, {
|
||||
adminUser: controller(),
|
||||
dialog: service(),
|
||||
user: alias("adminUser.model"),
|
||||
userBadges: alias("model"),
|
||||
allBadges: alias("badges"),
|
||||
sortedBadges: sort("model", "badgeSortOrder"),
|
||||
|
||||
@alias("adminUser.model") user;
|
||||
@alias("model") userBadges;
|
||||
@alias("badges") allBadges;
|
||||
@sort("model", "badgeSortOrder") sortedBadges;
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
badgeSortOrder = ["granted_at:desc"];
|
||||
this.badgeSortOrder = ["granted_at:desc"];
|
||||
},
|
||||
|
||||
@discourseComputed("model", "model.[]", "model.expandedBadges.[]")
|
||||
groupedBadges() {
|
||||
@ -59,47 +59,46 @@ export default class AdminUserBadgesController extends Controller.extend(
|
||||
});
|
||||
|
||||
return expanded.sortBy("granted_at").reverse();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
expandGroup(userBadge) {
|
||||
const model = this.model;
|
||||
model.set("expandedBadges", model.get("expandedBadges") || []);
|
||||
model.get("expandedBadges").pushObject(userBadge.badge.id);
|
||||
}
|
||||
actions: {
|
||||
expandGroup(userBadge) {
|
||||
const model = this.model;
|
||||
model.set("expandedBadges", model.get("expandedBadges") || []);
|
||||
model.get("expandedBadges").pushObject(userBadge.badge.id);
|
||||
},
|
||||
|
||||
@action
|
||||
grantBadge() {
|
||||
this.grantBadge(
|
||||
this.selectedBadgeId,
|
||||
this.get("user.username"),
|
||||
this.badgeReason
|
||||
).then(
|
||||
() => {
|
||||
this.set("badgeReason", "");
|
||||
next(() => {
|
||||
// Update the selected badge ID after the combobox has re-rendered.
|
||||
const newSelectedBadge = this.grantableBadges[0];
|
||||
if (newSelectedBadge) {
|
||||
this.set("selectedBadgeId", newSelectedBadge.get("id"));
|
||||
}
|
||||
});
|
||||
},
|
||||
function (error) {
|
||||
popupAjaxError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
grantBadge() {
|
||||
this.grantBadge(
|
||||
this.selectedBadgeId,
|
||||
this.get("user.username"),
|
||||
this.badgeReason
|
||||
).then(
|
||||
() => {
|
||||
this.set("badgeReason", "");
|
||||
next(() => {
|
||||
// Update the selected badge ID after the combobox has re-rendered.
|
||||
const newSelectedBadge = this.grantableBadges[0];
|
||||
if (newSelectedBadge) {
|
||||
this.set("selectedBadgeId", newSelectedBadge.get("id"));
|
||||
}
|
||||
});
|
||||
},
|
||||
function (error) {
|
||||
popupAjaxError(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@action
|
||||
revokeBadge(userBadge) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.badges.revoke_confirm"),
|
||||
didConfirm: () => {
|
||||
return userBadge.revoke().then(() => {
|
||||
this.model.removeObject(userBadge);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
revokeBadge(userBadge) {
|
||||
return this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.badges.revoke_confirm"),
|
||||
didConfirm: () => {
|
||||
return userBadge.revoke().then(() => {
|
||||
this.model.removeObject(userBadge);
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,74 +1,73 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { gte, sort } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
const MAX_FIELDS = 30;
|
||||
|
||||
export default class AdminUserFieldsController extends Controller {
|
||||
@service dialog;
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
fieldTypes: null,
|
||||
createDisabled: gte("model.length", MAX_FIELDS),
|
||||
sortedFields: sort("model", "fieldSortOrder"),
|
||||
|
||||
fieldTypes = null;
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
@gte("model.length", MAX_FIELDS) createDisabled;
|
||||
@sort("model", "fieldSortOrder") sortedFields;
|
||||
this.fieldSortOrder = ["position"];
|
||||
},
|
||||
|
||||
fieldSortOrder = ["position"];
|
||||
|
||||
@action
|
||||
createField() {
|
||||
const f = this.store.createRecord("user-field", {
|
||||
field_type: "text",
|
||||
position: MAX_FIELDS,
|
||||
});
|
||||
this.model.pushObject(f);
|
||||
}
|
||||
|
||||
@action
|
||||
moveUp(f) {
|
||||
const idx = this.sortedFields.indexOf(f);
|
||||
if (idx) {
|
||||
const prev = this.sortedFields.objectAt(idx - 1);
|
||||
const prevPos = prev.get("position");
|
||||
|
||||
prev.update({ position: f.get("position") });
|
||||
f.update({ position: prevPos });
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
moveDown(f) {
|
||||
const idx = this.sortedFields.indexOf(f);
|
||||
if (idx > -1) {
|
||||
const next = this.sortedFields.objectAt(idx + 1);
|
||||
const nextPos = next.get("position");
|
||||
|
||||
next.update({ position: f.get("position") });
|
||||
f.update({ position: nextPos });
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
destroyField(f) {
|
||||
const model = this.model;
|
||||
|
||||
// Only confirm if we already been saved
|
||||
if (f.get("id")) {
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.user_fields.delete_confirm"),
|
||||
didConfirm: () => {
|
||||
return f
|
||||
.destroyRecord()
|
||||
.then(function () {
|
||||
model.removeObject(f);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
actions: {
|
||||
createField() {
|
||||
const f = this.store.createRecord("user-field", {
|
||||
field_type: "text",
|
||||
position: MAX_FIELDS,
|
||||
});
|
||||
} else {
|
||||
model.removeObject(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.model.pushObject(f);
|
||||
},
|
||||
|
||||
moveUp(f) {
|
||||
const idx = this.sortedFields.indexOf(f);
|
||||
if (idx) {
|
||||
const prev = this.sortedFields.objectAt(idx - 1);
|
||||
const prevPos = prev.get("position");
|
||||
|
||||
prev.update({ position: f.get("position") });
|
||||
f.update({ position: prevPos });
|
||||
}
|
||||
},
|
||||
|
||||
moveDown(f) {
|
||||
const idx = this.sortedFields.indexOf(f);
|
||||
if (idx > -1) {
|
||||
const next = this.sortedFields.objectAt(idx + 1);
|
||||
const nextPos = next.get("position");
|
||||
|
||||
next.update({ position: f.get("position") });
|
||||
f.update({ position: nextPos });
|
||||
}
|
||||
},
|
||||
|
||||
destroy(f) {
|
||||
const model = this.model;
|
||||
|
||||
// Only confirm if we already been saved
|
||||
if (f.get("id")) {
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.user_fields.delete_confirm"),
|
||||
didConfirm: () => {
|
||||
return f
|
||||
.destroyRecord()
|
||||
.then(function () {
|
||||
model.removeObject(f);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
model.removeObject(f);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
import Controller from "@ember/controller";
|
||||
export default class AdminUserController extends Controller {}
|
||||
export default Controller.extend();
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import AdminUser from "admin/models/admin-user";
|
||||
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
||||
import Controller from "@ember/controller";
|
||||
@ -9,55 +7,41 @@ import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { i18n } from "discourse/lib/computed";
|
||||
|
||||
export default class AdminUsersListShowController extends Controller.extend(
|
||||
CanCheckEmails
|
||||
) {
|
||||
model = null;
|
||||
query = null;
|
||||
order = null;
|
||||
asc = null;
|
||||
showEmails = false;
|
||||
refreshing = false;
|
||||
listFilter = null;
|
||||
selectAll = false;
|
||||
export default Controller.extend(CanCheckEmails, {
|
||||
model: null,
|
||||
query: null,
|
||||
order: null,
|
||||
asc: null,
|
||||
showEmails: false,
|
||||
refreshing: false,
|
||||
listFilter: null,
|
||||
selectAll: false,
|
||||
searchHint: i18n("search_hint"),
|
||||
|
||||
@i18n("search_hint") searchHint;
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
_page = 1;
|
||||
_results = [];
|
||||
_canLoadMore = true;
|
||||
this._page = 1;
|
||||
this._results = [];
|
||||
this._canLoadMore = true;
|
||||
},
|
||||
|
||||
@discourseComputed("query")
|
||||
title(query) {
|
||||
return I18n.t("admin.users.titles." + query);
|
||||
}
|
||||
|
||||
@discourseComputed("showEmails")
|
||||
columnCount(showEmails) {
|
||||
let colCount = 7; // note that the first column is hardcoded in the template
|
||||
|
||||
if (showEmails) {
|
||||
colCount += 1;
|
||||
}
|
||||
|
||||
if (this.siteSettings.must_approve_users) {
|
||||
colCount += 1;
|
||||
}
|
||||
|
||||
return colCount;
|
||||
}
|
||||
},
|
||||
|
||||
@observes("listFilter")
|
||||
_filterUsers() {
|
||||
discourseDebounce(this, this.resetFilters, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
resetFilters() {
|
||||
this._page = 1;
|
||||
this._results = [];
|
||||
this._canLoadMore = true;
|
||||
this._refreshUsers();
|
||||
}
|
||||
},
|
||||
|
||||
_refreshUsers() {
|
||||
if (!this._canLoadMore) {
|
||||
@ -85,17 +69,17 @@ export default class AdminUsersListShowController extends Controller.extend(
|
||||
.finally(() => {
|
||||
this.set("refreshing", false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this._page += 1;
|
||||
this._refreshUsers();
|
||||
}
|
||||
actions: {
|
||||
loadMore() {
|
||||
this._page += 1;
|
||||
this._refreshUsers();
|
||||
},
|
||||
|
||||
@action
|
||||
toggleEmailVisibility() {
|
||||
this.toggleProperty("showEmails");
|
||||
this.resetFilters();
|
||||
}
|
||||
}
|
||||
toggleEmailVisibility() {
|
||||
this.toggleProperty("showEmails");
|
||||
this.resetFilters();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,35 +1,32 @@
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { or } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import WatchedWord from "admin/models/watched-word";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { or } from "@ember/object/computed";
|
||||
import { schedule } from "@ember/runloop";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminWatchedWordsActionController extends Controller {
|
||||
@service dialog;
|
||||
@controller adminWatchedWords;
|
||||
|
||||
actionNameKey = null;
|
||||
|
||||
@fmt("actionNameKey", "/admin/customize/watched_words/action/%@/download")
|
||||
downloadLink;
|
||||
|
||||
@or("adminWatchedWords.showWords", "adminWatchedWords.filter")
|
||||
showWordsList;
|
||||
export default Controller.extend({
|
||||
adminWatchedWords: controller(),
|
||||
actionNameKey: null,
|
||||
dialog: service(),
|
||||
downloadLink: fmt(
|
||||
"actionNameKey",
|
||||
"/admin/customize/watched_words/action/%@/download"
|
||||
),
|
||||
showWordsList: or("adminWatchedWords.showWords", "adminWatchedWords.filter"),
|
||||
|
||||
findAction(actionName) {
|
||||
return (this.adminWatchedWords.model || []).findBy("nameKey", actionName);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("actionNameKey", "adminWatchedWords.model")
|
||||
currentAction(actionName) {
|
||||
return this.findAction(actionName);
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("currentAction.words.[]")
|
||||
regexpError(words) {
|
||||
@ -40,81 +37,78 @@ export default class AdminWatchedWordsActionController extends Controller {
|
||||
return I18n.t("admin.watched_words.invalid_regex", { word });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("actionNameKey")
|
||||
actionDescription(actionNameKey) {
|
||||
return I18n.t("admin.watched_words.action_descriptions." + actionNameKey);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
recordAdded(arg) {
|
||||
const foundAction = this.findAction(this.actionNameKey);
|
||||
if (!foundAction) {
|
||||
return;
|
||||
}
|
||||
actions: {
|
||||
recordAdded(arg) {
|
||||
const action = this.findAction(this.actionNameKey);
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
foundAction.words.unshiftObject(arg);
|
||||
schedule("afterRender", () => {
|
||||
// remove from other actions lists
|
||||
let match = null;
|
||||
this.adminWatchedWords.model.forEach((otherAction) => {
|
||||
if (match) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherAction.nameKey !== this.actionNameKey) {
|
||||
match = otherAction.words.findBy("id", arg.id);
|
||||
action.words.unshiftObject(arg);
|
||||
schedule("afterRender", () => {
|
||||
// remove from other actions lists
|
||||
let match = null;
|
||||
this.adminWatchedWords.model.forEach((otherAction) => {
|
||||
if (match) {
|
||||
otherAction.words.removeObject(match);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
recordRemoved(arg) {
|
||||
if (this.currentAction) {
|
||||
this.currentAction.words.removeObject(arg);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
uploadComplete() {
|
||||
WatchedWord.findAll().then((data) => {
|
||||
this.adminWatchedWords.set("model", data);
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
test() {
|
||||
WatchedWord.findAll().then((data) => {
|
||||
this.adminWatchedWords.set("model", data);
|
||||
showModal("admin-watched-word-test", {
|
||||
admin: true,
|
||||
model: this.currentAction,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
clearAll() {
|
||||
const actionKey = this.actionNameKey;
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.watched_words.clear_all_confirm", {
|
||||
action: I18n.t("admin.watched_words.actions." + actionKey),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
ajax(`/admin/customize/watched_words/action/${actionKey}.json`, {
|
||||
type: "DELETE",
|
||||
}).then(() => {
|
||||
const foundAction = this.findAction(actionKey);
|
||||
if (foundAction) {
|
||||
foundAction.set("words", []);
|
||||
if (otherAction.nameKey !== this.actionNameKey) {
|
||||
match = otherAction.words.findBy("id", arg.id);
|
||||
if (match) {
|
||||
otherAction.words.removeObject(match);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
recordRemoved(arg) {
|
||||
if (this.currentAction) {
|
||||
this.currentAction.words.removeObject(arg);
|
||||
}
|
||||
},
|
||||
|
||||
uploadComplete() {
|
||||
WatchedWord.findAll().then((data) => {
|
||||
this.adminWatchedWords.set("model", data);
|
||||
});
|
||||
},
|
||||
|
||||
test() {
|
||||
WatchedWord.findAll().then((data) => {
|
||||
this.adminWatchedWords.set("model", data);
|
||||
showModal("admin-watched-word-test", {
|
||||
admin: true,
|
||||
model: this.currentAction,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
clearAll() {
|
||||
const actionKey = this.actionNameKey;
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("admin.watched_words.clear_all_confirm", {
|
||||
action: I18n.t("admin.watched_words.actions." + actionKey),
|
||||
}),
|
||||
didConfirm: () => {
|
||||
ajax(`/admin/customize/watched_words/action/${actionKey}.json`, {
|
||||
type: "DELETE",
|
||||
}).then(() => {
|
||||
const action = this.findAction(actionKey);
|
||||
if (action) {
|
||||
action.set("words", []);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -3,11 +3,11 @@ import EmberObject, { action } from "@ember/object";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
||||
export default class AdminWatchedWordsController extends Controller {
|
||||
filter = null;
|
||||
showWords = false;
|
||||
export default Controller.extend({
|
||||
filter: null,
|
||||
showWords: false,
|
||||
|
||||
_filterContent() {
|
||||
if (isEmpty(this.allWatchedWords)) {
|
||||
@ -36,17 +36,17 @@ export default class AdminWatchedWordsController extends Controller {
|
||||
);
|
||||
});
|
||||
this.set("model", model);
|
||||
}
|
||||
},
|
||||
|
||||
@observes("filter")
|
||||
filterContent() {
|
||||
discourseDebounce(this, this._filterContent, INPUT_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
clearFilter() {
|
||||
this.set("filter", "");
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
toggleMenu() {
|
||||
@ -54,5 +54,5 @@ export default class AdminWatchedWordsController extends Controller {
|
||||
["mobile-closed", "mobile-open"].forEach((state) => {
|
||||
adminDetail.classList.toggle(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminWebHooksEditController extends Controller {
|
||||
@service dialog;
|
||||
@controller adminWebHooks;
|
||||
|
||||
@alias("adminWebHooks.eventTypes") eventTypes;
|
||||
@alias("adminWebHooks.defaultEventTypes") defaultEventTypes;
|
||||
@alias("adminWebHooks.contentTypes") contentTypes;
|
||||
export default Controller.extend({
|
||||
adminWebHooks: controller(),
|
||||
dialog: service(),
|
||||
eventTypes: alias("adminWebHooks.eventTypes"),
|
||||
defaultEventTypes: alias("adminWebHooks.defaultEventTypes"),
|
||||
contentTypes: alias("adminWebHooks.contentTypes"),
|
||||
|
||||
@discourseComputed
|
||||
showTagsFilter() {
|
||||
return this.siteSettings.tagging_enabled;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.isSaving", "saved", "saveButtonDisabled")
|
||||
savingStatus(isSaving, saved, saveButtonDisabled) {
|
||||
@ -30,14 +29,14 @@ export default class AdminWebHooksEditController extends Controller {
|
||||
// Use side effect of validation to clear saved text
|
||||
this.set("saved", false);
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.isNew")
|
||||
saveButtonText(isNew) {
|
||||
return isNew
|
||||
? I18n.t("admin.web_hooks.create")
|
||||
: I18n.t("admin.web_hooks.save");
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.secret")
|
||||
secretValidation(secret) {
|
||||
@ -56,7 +55,7 @@ export default class AdminWebHooksEditController extends Controller {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.wildcard_web_hook", "model.web_hook_event_types.[]")
|
||||
eventTypeValidation(isWildcard, eventTypes) {
|
||||
@ -66,7 +65,7 @@ export default class AdminWebHooksEditController extends Controller {
|
||||
reason: I18n.t("admin.web_hooks.event_type_missing"),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"model.isSaving",
|
||||
@ -83,7 +82,7 @@ export default class AdminWebHooksEditController extends Controller {
|
||||
return isSaving
|
||||
? false
|
||||
: secretValidation || eventTypeValidation || isEmpty(payloadUrl);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
async save() {
|
||||
@ -98,5 +97,5 @@ export default class AdminWebHooksEditController extends Controller {
|
||||
} catch (e) {
|
||||
popupAjaxError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
|
||||
export default class AdminWebHooksIndexController extends Controller {
|
||||
@service dialog;
|
||||
@controller adminWebHooks;
|
||||
|
||||
@alias("adminWebHooks.contentTypes") contentTypes;
|
||||
@alias("adminWebHooks.defaultEventTypes") defaultEventTypes;
|
||||
@alias("adminWebHooks.deliveryStatuses") deliveryStatuses;
|
||||
@alias("adminWebHooks.eventTypes") eventTypes;
|
||||
@alias("adminWebHooks.model") model;
|
||||
export default Controller.extend({
|
||||
adminWebHooks: controller(),
|
||||
dialog: service(),
|
||||
contentTypes: alias("adminWebHooks.contentTypes"),
|
||||
defaultEventTypes: alias("adminWebHooks.defaultEventTypes"),
|
||||
deliveryStatuses: alias("adminWebHooks.deliveryStatuses"),
|
||||
eventTypes: alias("adminWebHooks.eventTypes"),
|
||||
model: alias("adminWebHooks.model"),
|
||||
|
||||
@action
|
||||
destroy(webhook) {
|
||||
@ -28,10 +27,10 @@ export default class AdminWebHooksIndexController extends Controller {
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.model.loadMore();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminWebHooksShowController extends Controller {
|
||||
@service dialog;
|
||||
@service router;
|
||||
@controller adminWebHooks;
|
||||
export default Controller.extend({
|
||||
adminWebHooks: controller(),
|
||||
dialog: service(),
|
||||
router: service(),
|
||||
|
||||
@action
|
||||
edit() {
|
||||
return this.router.transitionTo("adminWebHooks.edit", this.model);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
destroy() {
|
||||
@ -28,5 +28,5 @@ export default class AdminWebHooksShowController extends Controller {
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
import Controller from "@ember/controller";
|
||||
|
||||
export default class AdminWebHooksController extends Controller {}
|
||||
export default Controller.extend({});
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { inject as service } from "@ember/service";
|
||||
import Controller from "@ember/controller";
|
||||
import { dasherize } from "@ember/string";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default class AdminController extends Controller {
|
||||
@service router;
|
||||
export default Controller.extend({
|
||||
router: service(),
|
||||
|
||||
@discourseComputed("siteSettings.enable_group_directory")
|
||||
showGroups(enableGroupDirectory) {
|
||||
return !enableGroupDirectory;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("siteSettings.enable_badges")
|
||||
showBadges(enableBadges) {
|
||||
return this.currentUser.get("admin") && enableBadges;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("router._router.currentPath")
|
||||
adminContentsClassName(currentPath) {
|
||||
@ -37,5 +37,5 @@ export default class AdminController extends Controller {
|
||||
}
|
||||
|
||||
return cssClasses;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { action } from "@ember/object";
|
||||
import { and, not } from "@ember/object/computed";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { observes } from "@ember-decorators/object";
|
||||
import { and, not } from "@ember/object/computed";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
@ -55,20 +53,18 @@ const SCSS_VARIABLE_NAMES = [
|
||||
"love-low",
|
||||
];
|
||||
|
||||
export default class AdminAddUploadController extends Controller.extend(
|
||||
ModalFunctionality
|
||||
) {
|
||||
@controller adminCustomizeThemesShow;
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
adminCustomizeThemesShow: controller(),
|
||||
|
||||
uploadUrl = "/admin/themes/upload_asset";
|
||||
|
||||
@and("nameValid", "fileSelected") enabled;
|
||||
@not("enabled") disabled;
|
||||
uploadUrl: "/admin/themes/upload_asset",
|
||||
|
||||
onShow() {
|
||||
this.set("name", null);
|
||||
this.set("fileSelected", false);
|
||||
}
|
||||
},
|
||||
|
||||
enabled: and("nameValid", "fileSelected"),
|
||||
disabled: not("enabled"),
|
||||
|
||||
@discourseComputed("name", "adminCustomizeThemesShow.model.theme_fields")
|
||||
errorMessage(name, themeFields) {
|
||||
@ -93,54 +89,54 @@ export default class AdminAddUploadController extends Controller.extend(
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("errorMessage")
|
||||
nameValid(errorMessage) {
|
||||
return null === errorMessage;
|
||||
}
|
||||
},
|
||||
|
||||
@observes("name")
|
||||
uploadChanged() {
|
||||
const file = $("#file-input")[0];
|
||||
this.set("fileSelected", file && file.files[0]);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
updateName() {
|
||||
let name = this.name;
|
||||
if (isEmpty(name)) {
|
||||
name = $("#file-input")[0].files[0].name;
|
||||
this.set("name", name.split(".")[0]);
|
||||
}
|
||||
this.uploadChanged();
|
||||
}
|
||||
actions: {
|
||||
updateName() {
|
||||
let name = this.name;
|
||||
if (isEmpty(name)) {
|
||||
name = $("#file-input")[0].files[0].name;
|
||||
this.set("name", name.split(".")[0]);
|
||||
}
|
||||
this.uploadChanged();
|
||||
},
|
||||
|
||||
@action
|
||||
upload() {
|
||||
const file = $("#file-input")[0].files[0];
|
||||
upload() {
|
||||
const file = $("#file-input")[0].files[0];
|
||||
|
||||
const options = {
|
||||
type: "POST",
|
||||
processData: false,
|
||||
contentType: false,
|
||||
data: new FormData(),
|
||||
};
|
||||
const options = {
|
||||
type: "POST",
|
||||
processData: false,
|
||||
contentType: false,
|
||||
data: new FormData(),
|
||||
};
|
||||
|
||||
options.data.append("file", file);
|
||||
options.data.append("file", file);
|
||||
|
||||
ajax(this.uploadUrl, options)
|
||||
.then((result) => {
|
||||
const upload = {
|
||||
upload_id: result.upload_id,
|
||||
name: this.name,
|
||||
original_filename: file.name,
|
||||
};
|
||||
this.adminCustomizeThemesShow.send("addUpload", upload);
|
||||
this.send("closeModal");
|
||||
})
|
||||
.catch((e) => {
|
||||
popupAjaxError(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
ajax(this.uploadUrl, options)
|
||||
.then((result) => {
|
||||
const upload = {
|
||||
upload_id: result.upload_id,
|
||||
name: this.name,
|
||||
original_filename: file.name,
|
||||
};
|
||||
this.adminCustomizeThemesShow.send("addUpload", upload);
|
||||
this.send("closeModal");
|
||||
})
|
||||
.catch((e) => {
|
||||
popupAjaxError(e);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -4,12 +4,39 @@ import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
|
||||
export default class AdminBadgePreviewController extends Controller {
|
||||
@alias("model.sample") sample;
|
||||
@alias("model.errors") errors;
|
||||
@alias("model.grant_count") count;
|
||||
export default Controller.extend({
|
||||
sample: alias("model.sample"),
|
||||
errors: alias("model.errors"),
|
||||
count: alias("model.grant_count"),
|
||||
|
||||
@map("model.sample", (grant) => {
|
||||
@discourseComputed("count", "sample.length")
|
||||
countWarning(count, sampleLength) {
|
||||
if (count <= 10) {
|
||||
return sampleLength !== count;
|
||||
} else {
|
||||
return sampleLength !== 10;
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("model.query_plan")
|
||||
hasQueryPlan(queryPlan) {
|
||||
return !!queryPlan;
|
||||
},
|
||||
|
||||
@discourseComputed("model.query_plan")
|
||||
queryPlanHtml(queryPlan) {
|
||||
let output = `<pre class="badge-query-plan">`;
|
||||
|
||||
queryPlan.forEach((linehash) => {
|
||||
output += escapeExpression(linehash["QUERY PLAN"]);
|
||||
output += "<br>";
|
||||
});
|
||||
|
||||
output += "</pre>";
|
||||
return output;
|
||||
},
|
||||
|
||||
processedSample: map("model.sample", (grant) => {
|
||||
let i18nKey = "admin.badges.preview.grant.with";
|
||||
const i18nParams = { username: escapeExpression(grant.username) };
|
||||
|
||||
@ -28,33 +55,5 @@ export default class AdminBadgePreviewController extends Controller {
|
||||
}
|
||||
|
||||
return I18n.t(i18nKey, i18nParams);
|
||||
})
|
||||
processedSample;
|
||||
|
||||
@discourseComputed("count", "sample.length")
|
||||
countWarning(count, sampleLength) {
|
||||
if (count <= 10) {
|
||||
return sampleLength !== count;
|
||||
} else {
|
||||
return sampleLength !== 10;
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("model.query_plan")
|
||||
hasQueryPlan(queryPlan) {
|
||||
return !!queryPlan;
|
||||
}
|
||||
|
||||
@discourseComputed("model.query_plan")
|
||||
queryPlanHtml(queryPlan) {
|
||||
let output = `<pre class="badge-query-plan">`;
|
||||
|
||||
queryPlan.forEach((linehash) => {
|
||||
output += escapeExpression(linehash["QUERY PLAN"]);
|
||||
output += "<br>";
|
||||
});
|
||||
|
||||
output += "</pre>";
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1,29 +1,27 @@
|
||||
import { action } from "@ember/object";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
export default class AdminColorSchemeSelectBaseController extends Controller.extend(
|
||||
ModalFunctionality
|
||||
) {
|
||||
@controller adminCustomizeColors;
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
adminCustomizeColors: controller(),
|
||||
|
||||
selectedBaseThemeId = null;
|
||||
selectedBaseThemeId: null,
|
||||
|
||||
init() {
|
||||
super.init(...arguments);
|
||||
this._super(...arguments);
|
||||
|
||||
const defaultScheme = this.get(
|
||||
"adminCustomizeColors.baseColorSchemes.0.base_scheme_id"
|
||||
);
|
||||
this.set("selectedBaseThemeId", defaultScheme);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
selectBase() {
|
||||
this.adminCustomizeColors.send(
|
||||
"newColorSchemeWithBase",
|
||||
this.selectedBaseThemeId
|
||||
);
|
||||
this.send("closeModal");
|
||||
}
|
||||
}
|
||||
actions: {
|
||||
selectBase() {
|
||||
this.adminCustomizeColors.send(
|
||||
"newColorSchemeWithBase",
|
||||
this.selectedBaseThemeId
|
||||
);
|
||||
this.send("closeModal");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -5,19 +5,12 @@ import { inject as service } from "@ember/service";
|
||||
import I18n from "I18n";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
|
||||
export default class AdminCustomizeFormTemplateView extends Controller.extend(
|
||||
ModalFunctionality
|
||||
) {
|
||||
@service router;
|
||||
@service dialog;
|
||||
@tracked showPreview = false;
|
||||
|
||||
@action
|
||||
togglePreview() {
|
||||
this.showPreview = !this.showPreview;
|
||||
}
|
||||
|
||||
@action
|
||||
editTemplate() {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user