Version bump
This commit is contained in:
commit
c02cbd9645
76
.github/workflows/documentation.yml
vendored
Normal file
76
.github/workflows/documentation.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
name: Documentation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')"
|
||||
name: run
|
||||
runs-on: ubuntu-latest
|
||||
container: discourse/discourse_test:slim
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.email "ci@ci.invalid"
|
||||
git config --global user.name "Discourse CI"
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: |
|
||||
gem install bundler --conservative -v $(awk '/BUNDLED WITH/ { getline; gsub(/ /,""); print $0 }' Gemfile.lock)
|
||||
bundle config --local path vendor/bundle
|
||||
bundle config --local deployment true
|
||||
bundle config --local without development
|
||||
bundle install --jobs 4
|
||||
bundle clean
|
||||
|
||||
- name: Get yarn cache directory
|
||||
id: yarn-cache-dir
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v3
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Yarn install
|
||||
run: yarn install
|
||||
|
||||
- name: Check Chat documentation
|
||||
run: |
|
||||
LOAD_PLUGINS=1 bin/rake chat:doc
|
||||
|
||||
if [ ! -z "$(git status --porcelain plugins/chat/docs/)" ]; then
|
||||
echo "Chat documentation is not up to date. To resolve, run:"
|
||||
echo " LOAD_PLUGINS=1 bin/rake chat:doc"
|
||||
echo
|
||||
echo "Or manually apply the diff printed below:"
|
||||
echo "---------------------------------------------"
|
||||
git -c color.ui=always diff plugins/chat/docs/
|
||||
exit 1
|
||||
fi
|
||||
timeout-minutes: 30
|
||||
9
.github/workflows/tests.yml
vendored
9
.github/workflows/tests.yml
vendored
@ -18,9 +18,9 @@ permissions:
|
||||
jobs:
|
||||
build:
|
||||
if: "!(github.event_name == 'push' && github.repository == 'discourse/discourse-private-mirror')"
|
||||
name: ${{ matrix.target }} ${{ matrix.build_type }}
|
||||
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' || '' }}
|
||||
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,6 +38,7 @@ jobs:
|
||||
matrix:
|
||||
build_type: [backend, frontend, system, annotations]
|
||||
target: [core, plugins]
|
||||
ruby: ['3.1']
|
||||
exclude:
|
||||
- build_type: annotations
|
||||
target: plugins
|
||||
@ -68,9 +69,9 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
key: ${{ runner.os }}-${{ matrix.ruby }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gem-
|
||||
${{ runner.os }}-${{ matrix.ruby }}-gem-
|
||||
|
||||
- name: Setup gems
|
||||
run: |
|
||||
|
||||
7
.jsdoc
Normal file
7
.jsdoc
Normal file
@ -0,0 +1,7 @@
|
||||
// jsdoc doesn't accept paths starting with _ (which is the case on github runners)
|
||||
// so we need to alter the default config
|
||||
{
|
||||
"source": {
|
||||
"excludePattern": ""
|
||||
}
|
||||
}
|
||||
13
Gemfile
13
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.3.1"
|
||||
rails_version = "7.0.4.1"
|
||||
gem "actionmailer", rails_version
|
||||
gem "actionpack", rails_version
|
||||
gem "actionview", rails_version
|
||||
@ -32,8 +32,8 @@ end
|
||||
gem "json"
|
||||
|
||||
# TODO: At the moment Discourse does not work with Sprockets 4, we would need to correct internals
|
||||
# This is a desired upgrade we should get to.
|
||||
gem "sprockets", "3.7.2"
|
||||
# We intend to drop sprockets rather than upgrade to 4.x
|
||||
gem "sprockets", git: "https://github.com/rails/sprockets", branch: "3.x"
|
||||
|
||||
# this will eventually be added to rails,
|
||||
# allows us to precompile all our templates in the unicorn master
|
||||
@ -261,12 +261,7 @@ if ENV["IMPORT"] == "1"
|
||||
gem "parallel", require: false
|
||||
end
|
||||
|
||||
# workaround for openssl 3.0, see
|
||||
# https://github.com/pushpad/web-push/pull/2
|
||||
gem "web-push",
|
||||
require: false,
|
||||
git: "https://github.com/xfalcox/web-push",
|
||||
branch: "openssl-3-compat"
|
||||
gem "web-push"
|
||||
gem "colored2", require: false
|
||||
gem "maxminddb"
|
||||
|
||||
|
||||
131
Gemfile.lock
131
Gemfile.lock
@ -6,37 +6,36 @@ GIT
|
||||
mini_mime (>= 0.1.1)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/xfalcox/web-push
|
||||
revision: 369df8f475a4cd4832a7679bec16576665f24d24
|
||||
branch: openssl-3-compat
|
||||
remote: https://github.com/rails/sprockets
|
||||
revision: f4d3dae71ef29c44b75a49cfbf8032cce07b423a
|
||||
branch: 3.x
|
||||
specs:
|
||||
web-push (2.1.0)
|
||||
hkdf (~> 1.0)
|
||||
jwt (~> 2.0)
|
||||
openssl (~> 3.0)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (7.0.3.1)
|
||||
actionpack (= 7.0.3.1)
|
||||
actionview (= 7.0.3.1)
|
||||
activejob (= 7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
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.3.1)
|
||||
actionview (= 7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
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.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
actionview (7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
@ -45,15 +44,15 @@ GEM
|
||||
actionview (>= 6.0.a)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
activejob (7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
activerecord (7.0.3.1)
|
||||
activemodel (= 7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
activesupport (7.0.3.1)
|
||||
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)
|
||||
@ -111,7 +110,7 @@ GEM
|
||||
chunky_png (1.4.0)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.10)
|
||||
concurrent-ruby (1.2.0)
|
||||
connection_pool (2.3.0)
|
||||
cose (1.3.0)
|
||||
cbor (~> 0.5.9)
|
||||
@ -120,8 +119,9 @@ GEM
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
css_parser (1.13.0)
|
||||
css_parser (1.14.0)
|
||||
addressable
|
||||
date (3.3.3)
|
||||
debug_inspector (1.1.0)
|
||||
diff-lcs (1.5.0)
|
||||
diffy (3.4.2)
|
||||
@ -137,15 +137,15 @@ GEM
|
||||
ecma-re-validator (0.4.0)
|
||||
regexp_parser (~> 2.2)
|
||||
email_reply_trimmer (0.1.13)
|
||||
erubi (1.11.0)
|
||||
excon (0.96.0)
|
||||
erubi (1.12.0)
|
||||
excon (0.97.2)
|
||||
execjs (2.8.1)
|
||||
exifr (1.3.10)
|
||||
fabrication (2.30.0)
|
||||
faker (2.23.0)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
fakeweb (1.3.0)
|
||||
faraday (2.7.2)
|
||||
faraday (2.7.4)
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-net_http (3.0.2)
|
||||
@ -157,7 +157,7 @@ GEM
|
||||
ffi (1.15.5)
|
||||
fspath (3.1.2)
|
||||
gc_tracer (1.5.1)
|
||||
globalid (1.0.0)
|
||||
globalid (1.0.1)
|
||||
activesupport (>= 5.0)
|
||||
guess_html_encoding (0.0.11)
|
||||
hana (1.3.7)
|
||||
@ -215,7 +215,7 @@ GEM
|
||||
matrix (0.4.2)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (1.0.1)
|
||||
message_bus (4.3.1)
|
||||
message_bus (4.3.2)
|
||||
rack (>= 1.1.3)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.1.2)
|
||||
@ -236,7 +236,8 @@ GEM
|
||||
mustache (1.1.1)
|
||||
net-http (0.3.2)
|
||||
uri
|
||||
net-imap (0.3.1)
|
||||
net-imap (0.3.4)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
net-protocol
|
||||
@ -245,16 +246,16 @@ GEM
|
||||
net-smtp (0.3.3)
|
||||
net-protocol
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.13.10)
|
||||
nokogiri (1.14.0)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.13.10-aarch64-linux)
|
||||
nokogiri (1.14.0-aarch64-linux)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.13.10-arm64-darwin)
|
||||
nokogiri (1.14.0-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.13.10-x86_64-darwin)
|
||||
nokogiri (1.14.0-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.13.10-x86_64-linux)
|
||||
nokogiri (1.14.0-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
oauth (1.1.0)
|
||||
oauth-tty (~> 1.0, >= 1.0.1)
|
||||
@ -296,7 +297,7 @@ GEM
|
||||
openssl (> 2.0, < 3.1)
|
||||
optimist (3.0.1)
|
||||
parallel (1.22.1)
|
||||
parallel_tests (4.0.0)
|
||||
parallel_tests (4.1.0)
|
||||
parallel
|
||||
parser (3.2.0.0)
|
||||
ast (~> 2.4.1)
|
||||
@ -316,7 +317,7 @@ GEM
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
racc (1.6.2)
|
||||
rack (2.2.5)
|
||||
rack (2.2.6.2)
|
||||
rack-mini-profiler (3.0.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (3.0.5)
|
||||
@ -326,7 +327,7 @@ GEM
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.4.4)
|
||||
rails-html-sanitizer (1.5.0)
|
||||
loofah (~> 2.19, >= 2.19.1)
|
||||
rails_failover (0.8.1)
|
||||
activerecord (> 6.0, < 7.1)
|
||||
@ -335,9 +336,9 @@ GEM
|
||||
rails_multisite (4.0.1)
|
||||
activerecord (> 5.0, < 7.1)
|
||||
railties (> 5.0, < 7.1)
|
||||
railties (7.0.3.1)
|
||||
actionpack (= 7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
railties (7.0.4.1)
|
||||
actionpack (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@ -354,9 +355,9 @@ GEM
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
redis (4.8.0)
|
||||
redis-namespace (1.9.0)
|
||||
redis-namespace (1.10.0)
|
||||
redis (>= 4)
|
||||
regexp_parser (2.6.1)
|
||||
regexp_parser (2.6.2)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.5)
|
||||
@ -378,7 +379,7 @@ GEM
|
||||
rspec-html-matchers (0.10.0)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a)
|
||||
rspec-mocks (3.12.2)
|
||||
rspec-mocks (3.12.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.12.0)
|
||||
rspec-rails (6.0.1)
|
||||
@ -397,7 +398,7 @@ GEM
|
||||
json-schema (>= 2.2, < 4.0)
|
||||
railties (>= 3.1, < 7.1)
|
||||
rspec-core (>= 2.14)
|
||||
rubocop (1.43.0)
|
||||
rubocop (1.44.0)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.2.0.0)
|
||||
@ -409,11 +410,14 @@ GEM
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.24.1)
|
||||
parser (>= 3.1.1.0)
|
||||
rubocop-capybara (2.17.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-discourse (3.0.3)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.16.0)
|
||||
rubocop-rspec (2.18.1)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-capybara (~> 2.17)
|
||||
ruby-prof (1.4.5)
|
||||
ruby-progressbar (1.11.0)
|
||||
ruby-readability (0.7.0)
|
||||
@ -433,7 +437,7 @@ GEM
|
||||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
selenium-webdriver (4.7.1)
|
||||
selenium-webdriver (4.8.0)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
@ -452,9 +456,6 @@ GEM
|
||||
snaky_hash (2.0.1)
|
||||
hashie
|
||||
version_gem (~> 1.1, >= 1.1.1)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.4.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
@ -483,6 +484,10 @@ GEM
|
||||
uri (0.12.0)
|
||||
uri_template (0.7.0)
|
||||
version_gem (1.1.1)
|
||||
web-push (3.0.0)
|
||||
hkdf (~> 1.0)
|
||||
jwt (~> 2.0)
|
||||
openssl (~> 3.0)
|
||||
webdrivers (5.2.0)
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
@ -496,7 +501,7 @@ GEM
|
||||
xorcist (1.1.3)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
yaml-lint (0.0.10)
|
||||
yaml-lint (0.1.2)
|
||||
zeitwerk (2.6.6)
|
||||
|
||||
PLATFORMS
|
||||
@ -509,14 +514,14 @@ PLATFORMS
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 7.0.3.1)
|
||||
actionpack (= 7.0.3.1)
|
||||
actionview (= 7.0.3.1)
|
||||
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.3.1)
|
||||
activerecord (= 7.0.3.1)
|
||||
activesupport (= 7.0.3.1)
|
||||
activemodel (= 7.0.4.1)
|
||||
activerecord (= 7.0.4.1)
|
||||
activesupport (= 7.0.4.1)
|
||||
addressable
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
@ -601,7 +606,7 @@ DEPENDENCIES
|
||||
rack-protection
|
||||
rails_failover
|
||||
rails_multisite
|
||||
railties (= 7.0.3.1)
|
||||
railties (= 7.0.4.1)
|
||||
rake
|
||||
rb-fsevent
|
||||
rbtrace
|
||||
@ -627,7 +632,7 @@ DEPENDENCIES
|
||||
shoulda-matchers
|
||||
sidekiq
|
||||
simplecov
|
||||
sprockets (= 3.7.2)
|
||||
sprockets!
|
||||
sprockets-rails
|
||||
sshkey
|
||||
stackprof
|
||||
@ -638,7 +643,7 @@ DEPENDENCIES
|
||||
uglifier
|
||||
unf
|
||||
unicorn
|
||||
web-push!
|
||||
web-push
|
||||
webdrivers
|
||||
webmock
|
||||
webrick
|
||||
|
||||
@ -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 2.7+](https://www.ruby-lang.org/en/downloads/), [PostgreSQL 13+](https://www.postgresql.org/download/), [Redis 6.2+](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
|
||||
|
||||
@ -51,7 +51,7 @@ Discourse supports the **latest, stable releases** of all major browsers and pla
|
||||
| Microsoft Edge | | |
|
||||
| Mozilla Firefox | | |
|
||||
|
||||
Additionally, we aim to support Safari on iOS 12.5+ until January 2023 (Discourse 3.0).
|
||||
Additionally, we aim to support Safari on iOS 15.7+.
|
||||
|
||||
## Built With
|
||||
|
||||
|
||||
@ -57,7 +57,6 @@
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<div class="penalty-history">{{html-safe this.penaltyHistory}}</div>
|
||||
{{else}}
|
||||
{{#if (eq this.penaltyType "suspend")}}
|
||||
<div class="cant-suspend">{{i18n "admin.user.cant_suspend"}}</div>
|
||||
@ -65,6 +64,7 @@
|
||||
<div class="cant-silence">{{i18n "admin.user.cant_silence"}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="penalty-history">{{html-safe this.penaltyHistory}}</div>
|
||||
</ConditionalLoadingSpinner>
|
||||
</DModalBody>
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"start": "ember serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1",
|
||||
"webpack": "^5.75.0",
|
||||
@ -24,7 +24,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@embroider/test-setup": "^2.0.2",
|
||||
"@embroider/test-setup": "^2.1.0",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-cli": "~3.28.5",
|
||||
|
||||
@ -252,6 +252,11 @@ async function buildFromBootstrap(proxy, baseURL, req, response, preload) {
|
||||
url.searchParams.append("safe_mode", reqUrlSafeMode);
|
||||
}
|
||||
|
||||
const enableSidebar = forUrlSearchParams.get("enable_sidebar");
|
||||
if (enableSidebar) {
|
||||
url.searchParams.append("enable_sidebar", enableSidebar);
|
||||
}
|
||||
|
||||
const reqUrlPreviewThemeId = forUrlSearchParams.get("preview_theme_id");
|
||||
if (reqUrlPreviewThemeId) {
|
||||
url.searchParams.append("preview_theme_id", reqUrlPreviewThemeId);
|
||||
@ -458,6 +463,13 @@ to serve API requests. For example:
|
||||
baseURL = rootURL === "" ? "/" : cleanBaseURL(rootURL || baseURL);
|
||||
|
||||
const rawMiddleware = express.raw({ type: () => true, limit: "100mb" });
|
||||
const pathRestrictedRawMiddleware = (req, res, next) => {
|
||||
if (this.shouldHandleRequest(req, baseURL)) {
|
||||
return rawMiddleware(req, res, next);
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
};
|
||||
|
||||
app.use(
|
||||
"/favicon.ico",
|
||||
@ -469,9 +481,9 @@ to serve API requests. For example:
|
||||
)
|
||||
);
|
||||
|
||||
app.use(rawMiddleware, async (req, res, next) => {
|
||||
app.use(pathRestrictedRawMiddleware, async (req, res, next) => {
|
||||
try {
|
||||
if (this.shouldForwardRequest(req, baseURL)) {
|
||||
if (this.shouldHandleRequest(req, baseURL)) {
|
||||
await handleRequest(proxy, baseURL, req, res);
|
||||
} else {
|
||||
// Fixes issues when using e.g. "localhost" instead of loopback IP address
|
||||
@ -492,7 +504,7 @@ to serve API requests. For example:
|
||||
});
|
||||
},
|
||||
|
||||
shouldForwardRequest(request, baseURL) {
|
||||
shouldHandleRequest(request, baseURL) {
|
||||
if (
|
||||
[
|
||||
`${baseURL}tests/index.html`,
|
||||
@ -508,6 +520,10 @@ to serve API requests. For example:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.path.startsWith(`${baseURL}message-bus/`)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
"discourse-plugins": "1.0.0",
|
||||
"express": "^4.18.2",
|
||||
"html-entities": "^2.3.3",
|
||||
"jsdom": "^21.0.0",
|
||||
"jsdom": "^21.1.0",
|
||||
"node-fetch": "^3.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"a11y-dialog": "7.5.2",
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1"
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"@uppy/drop-target": "^2.0.1",
|
||||
"@uppy/utils": "^5.1.1",
|
||||
"@uppy/xhr-upload": "^3.0.4",
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1",
|
||||
"ember-resolver": "^8.0.3",
|
||||
@ -32,7 +32,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@embroider/test-setup": "^2.0.2",
|
||||
"@embroider/test-setup": "^2.1.0",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-cli": "~3.28.5",
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"start": "ember serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1",
|
||||
"handlebars": "^4.7.6",
|
||||
@ -24,7 +24,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@embroider/test-setup": "^2.0.2",
|
||||
"@embroider/test-setup": "^2.1.0",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-cli": "~3.28.5",
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
"repository": "",
|
||||
"dependencies": {
|
||||
"discourse-widget-hbs": "1.0.0",
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli": "~3.28.5",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1",
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
"start": "ember serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-cli-babel": "^7.26.10",
|
||||
"ember-cli-htmlbars": "^6.1.1",
|
||||
"handlebars": "^4.7.6",
|
||||
@ -24,7 +24,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@embroider/test-setup": "^2.0.2",
|
||||
"@embroider/test-setup": "^2.1.0",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/syntax": "^0.84.2",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
|
||||
@ -39,22 +39,24 @@ export default DropdownSelectBoxComponent.extend({
|
||||
});
|
||||
}
|
||||
|
||||
if (this.bulkSelection.some((m) => !m.primary)) {
|
||||
items.push({
|
||||
id: "setPrimary",
|
||||
name: I18n.t("groups.members.make_all_primary"),
|
||||
description: I18n.t("groups.members.make_all_primary_description"),
|
||||
icon: "id-card",
|
||||
});
|
||||
}
|
||||
if (this.currentUser.staff) {
|
||||
if (this.bulkSelection.some((m) => !m.primary)) {
|
||||
items.push({
|
||||
id: "setPrimary",
|
||||
name: I18n.t("groups.members.make_all_primary"),
|
||||
description: I18n.t("groups.members.make_all_primary_description"),
|
||||
icon: "id-card",
|
||||
});
|
||||
}
|
||||
|
||||
if (this.bulkSelection.some((m) => m.primary)) {
|
||||
items.push({
|
||||
id: "unsetPrimary",
|
||||
name: I18n.t("groups.members.remove_all_primary"),
|
||||
description: I18n.t("groups.members.remove_all_primary_description"),
|
||||
icon: "id-card",
|
||||
});
|
||||
if (this.bulkSelection.some((m) => m.primary)) {
|
||||
items.push({
|
||||
id: "unsetPrimary",
|
||||
name: I18n.t("groups.members.remove_all_primary"),
|
||||
description: I18n.t("groups.members.remove_all_primary_description"),
|
||||
icon: "id-card",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
|
||||
@ -106,8 +106,6 @@ export default Component.extend(ComposerUploadUppy, {
|
||||
fileUploadElementId: "file-uploader",
|
||||
mobileFileUploaderId: "mobile-file-upload",
|
||||
|
||||
// TODO (martin) Remove this once the chat plugin is using the new composerEventPrefix
|
||||
eventPrefix: "composer",
|
||||
composerEventPrefix: "composer",
|
||||
uploadType: "composer",
|
||||
uppyId: "composer-editor-uppy",
|
||||
|
||||
@ -11,7 +11,31 @@ export default Component.extend({
|
||||
|
||||
attributeBindings: ["ariaCurrent:aria-current", "title"],
|
||||
|
||||
ariaCurrent: computed("router.currentRouteName", "route", function () {
|
||||
return this.router.currentRouteName === this.route ? "page" : null;
|
||||
}),
|
||||
ariaCurrent: computed(
|
||||
"router.currentRouteName",
|
||||
"router.currentRoute.parent.name",
|
||||
"route",
|
||||
"ariaCurrentContext",
|
||||
function () {
|
||||
let ariaCurrentValue = "page";
|
||||
|
||||
// when there are multiple levels of navigation
|
||||
// we want the active parent to get `aria-current="page"`
|
||||
// and the active child to get `aria-current="location"`
|
||||
if (this.ariaCurrentContext === "subNav") {
|
||||
ariaCurrentValue = "location";
|
||||
} else if (this.ariaCurrentContext === "parentNav") {
|
||||
if (
|
||||
this.router.currentRouteName !== this.route && // not the current route
|
||||
this.router.currentRoute.parent.name.includes(this.route) // but is the current parent route
|
||||
) {
|
||||
return "page";
|
||||
}
|
||||
}
|
||||
|
||||
return this.router.currentRouteName === this.route
|
||||
? ariaCurrentValue
|
||||
: null;
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
@ -43,6 +43,15 @@ export default DropdownSelectBoxComponent.extend({
|
||||
icon: "shield-alt",
|
||||
});
|
||||
}
|
||||
} else if (this.canEditGroup && !this.member.owner) {
|
||||
items.push({
|
||||
id: "makeOwner",
|
||||
name: I18n.t("groups.members.make_owner"),
|
||||
description: I18n.t("groups.members.make_owner_description", {
|
||||
username: this.get("member.username"),
|
||||
}),
|
||||
icon: "shield-alt",
|
||||
});
|
||||
}
|
||||
|
||||
if (this.currentUser.staff) {
|
||||
|
||||
@ -1,55 +1,63 @@
|
||||
<section class="user-navigation user-navigation-primary">
|
||||
<HorizontalOverflowNav @className="main-nav nav user-nav">
|
||||
<HorizontalOverflowNav
|
||||
@className="main-nav nav user-nav"
|
||||
@ariaLabel="User primary"
|
||||
>
|
||||
{{#unless @user.profile_hidden}}
|
||||
<li class="summary">
|
||||
<LinkTo @route="user.summary">
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.summary.title"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem @route="user.summary" @class="user-nav__summary">
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.summary.title"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<DNavigationItem
|
||||
@route="userActivity"
|
||||
@class="user-nav__activity"
|
||||
@ariaCurrentContext="parentNav"
|
||||
>
|
||||
{{d-icon "stream"}}
|
||||
<span>{{i18n "user.activity_stream"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="user-activity">
|
||||
<LinkTo @route="userActivity">
|
||||
{{d-icon "stream"}}
|
||||
<span>{{i18n "user.activity_stream"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/unless}}
|
||||
|
||||
{{#if @showNotificationsTab}}
|
||||
<li class="user-notifications">
|
||||
<LinkTo @route="userNotifications">
|
||||
{{d-icon "bell" class="glyph"}}
|
||||
<span>{{i18n "user.notifications"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications"
|
||||
@class="user-nav__notifications"
|
||||
@ariaCurrentContext="parentNav"
|
||||
>
|
||||
{{d-icon "bell" class="glyph"}}
|
||||
<span>{{i18n "user.notifications"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if @showPrivateMessages}}
|
||||
<li class="private-messages">
|
||||
<LinkTo @route="userPrivateMessages">
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "user.private_messages"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages"
|
||||
@class="user-nav__personal-messages"
|
||||
@ariaCurrentContext="parentNav"
|
||||
>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "user.private_messages"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if @canInviteToForum}}
|
||||
<li class="invited">
|
||||
<LinkTo @route="userInvited">
|
||||
{{d-icon "user-plus"}}
|
||||
<span>{{i18n "user.invited.title"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userInvited"
|
||||
@class="user-nav__invites"
|
||||
@ariaCurrentContext="parentNav"
|
||||
>
|
||||
{{d-icon "user-plus"}}
|
||||
<span>{{i18n "user.invited.title"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if @showBadges}}
|
||||
<li class="badges">
|
||||
<LinkTo @route="user.badges">
|
||||
{{d-icon "certificate"}}
|
||||
<span>{{i18n "badges.title"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem @route="user.badges" @class="user-nav__badges">
|
||||
{{d-icon "certificate"}}
|
||||
<span>{{i18n "badges.title"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@ -59,16 +67,18 @@
|
||||
/>
|
||||
|
||||
{{#if @user.can_edit}}
|
||||
<li class="preferences">
|
||||
<LinkTo @route="preferences">
|
||||
{{d-icon "cog"}}
|
||||
<span>{{i18n "user.preferences"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences"
|
||||
@class="user-nav__preferences"
|
||||
@ariaCurrentContext="parentNav"
|
||||
>
|
||||
{{d-icon "cog"}}
|
||||
<span>{{i18n "user.preferences"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.site.mobileView this.currentUser.staff)}}
|
||||
<li class="admin">
|
||||
<li class="user-nav__admin">
|
||||
<a href={{@user.adminPath}}>
|
||||
{{d-icon "wrench"}}
|
||||
<span>{{i18n "admin.user.manage_user"}}</span>
|
||||
|
||||
@ -1,44 +1,77 @@
|
||||
<DNavigationItem @route="userActivity.index">
|
||||
<DNavigationItem
|
||||
@route="userActivity.index"
|
||||
@class="user-nav__activity-all"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "stream"}}
|
||||
<span>{{i18n "user.filters.all"}}</span>
|
||||
</DNavigationItem>
|
||||
<DNavigationItem @route="userActivity.topics">
|
||||
<DNavigationItem
|
||||
@route="userActivity.topics"
|
||||
@class="user-nav__activity-topics"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "list-ul"}}
|
||||
<span>{{i18n "user_action_groups.4"}}</span>
|
||||
</DNavigationItem>
|
||||
<DNavigationItem @route="userActivity.replies">
|
||||
<DNavigationItem
|
||||
@route="userActivity.replies"
|
||||
@class="user-nav__activity-replies"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "reply"}}
|
||||
<span>{{i18n "user_action_groups.5"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if @user.showRead}}
|
||||
<DNavigationItem @route="userActivity.read" @title={{i18n "user.read_help"}}>
|
||||
<DNavigationItem
|
||||
@route="userActivity.read"
|
||||
@class="user-nav__activity-read"
|
||||
@title={{i18n "user.read_help"}}
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "history"}}
|
||||
<span>{{i18n "user.read"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if @user.showDrafts}}
|
||||
<DNavigationItem @route="userActivity.drafts">
|
||||
<DNavigationItem
|
||||
@route="userActivity.drafts"
|
||||
@class="user-nav__activity-drafts"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "pencil-alt"}}
|
||||
<span>{{@draftLabel}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt @model.pending_posts_count 0)}}
|
||||
<DNavigationItem @route="userActivity.pending">
|
||||
<DNavigationItem
|
||||
@route="userActivity.pending"
|
||||
@class="user-nav__activity-pending"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "clock"}}
|
||||
<span>{{@pendingLabel}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
<DNavigationItem @route="userActivity.likesGiven">
|
||||
<DNavigationItem
|
||||
@route="userActivity.likesGiven"
|
||||
@class="user-nav__activity-likes"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "heart"}}
|
||||
<span>{{i18n "user_action_groups.1"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if @user.showBookmarks}}
|
||||
<DNavigationItem @route="userActivity.bookmarks">
|
||||
<DNavigationItem
|
||||
@route="userActivity.bookmarks"
|
||||
@class="user-nav__activity-bookmarks"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "bookmark"}}
|
||||
<span>{{i18n "user_action_groups.3"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
@ -1,39 +1,49 @@
|
||||
<li>
|
||||
<LinkTo @route="userNotifications.index">
|
||||
{{d-icon "bell"}}
|
||||
<span>{{i18n "user.filters.all"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications.index"
|
||||
@class="user-nav__notifications-all"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "bell"}}
|
||||
<span>{{i18n "user.filters.all"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li>
|
||||
<LinkTo @route="userNotifications.responses">
|
||||
{{d-icon "reply"}}
|
||||
<span>{{i18n "user_action_groups.6"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications.responses"
|
||||
@class="user-nav__notifications-responses"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "reply"}}
|
||||
<span>{{i18n "user_action_groups.6"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li>
|
||||
<LinkTo @route="userNotifications.likesReceived">
|
||||
{{d-icon "heart"}}
|
||||
<span>{{i18n "user_action_groups.2"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications.likesReceived"
|
||||
@class="user-nav__notifications-likes"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "heart"}}
|
||||
<span>{{i18n "user_action_groups.2"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if @siteSettings.enable_mentions}}
|
||||
<li>
|
||||
<LinkTo @route="userNotifications.mentions">
|
||||
{{d-icon "at"}}
|
||||
<span>{{i18n "user_action_groups.7"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications.mentions"
|
||||
@class="user-nav__notifications-mentions"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "at"}}
|
||||
<span>{{i18n "user_action_groups.7"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
<li>
|
||||
<LinkTo @route="userNotifications.edits">
|
||||
{{d-icon "pencil-alt"}}
|
||||
<span>{{i18n "user_action_groups.11"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userNotifications.edits"
|
||||
@class="user-nav__notifications-edits"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "pencil-alt"}}
|
||||
<span>{{i18n "user_action_groups.11"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<PluginOutlet
|
||||
@name="user-notifications-bottom"
|
||||
|
||||
@ -1,68 +1,86 @@
|
||||
<li class="nav-account">
|
||||
<LinkTo @route="preferences.account">
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.preferences_nav.account"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.account"
|
||||
@class="user-nav__preferences-account"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.preferences_nav.account"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="nav-security">
|
||||
<LinkTo @route="preferences.security">
|
||||
{{d-icon "lock"}}
|
||||
<span>{{i18n "user.preferences_nav.security"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.security"
|
||||
@class="user-nav__preferences-security"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "lock"}}
|
||||
<span>{{i18n "user.preferences_nav.security"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="nav-profile">
|
||||
<LinkTo @route="preferences.profile">
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.preferences_nav.profile"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.profile"
|
||||
@class="user-nav__preferences-profile"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "user"}}
|
||||
<span>{{i18n "user.preferences_nav.profile"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="nav-emails">
|
||||
<LinkTo @route="preferences.emails">
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "user.preferences_nav.emails"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.emails"
|
||||
@class="user-nav__preferences-emails"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "user.preferences_nav.emails"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="nav-notifications">
|
||||
<LinkTo @route="preferences.notifications">
|
||||
{{d-icon "bell"}}
|
||||
<span>{{i18n "user.preferences_nav.notifications"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.notifications"
|
||||
@class="user-nav__preferences-notifications"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "bell"}}
|
||||
<span>{{i18n "user.preferences_nav.notifications"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if @model.can_change_tracking_preferences}}
|
||||
<li class="nav-tracking">
|
||||
<LinkTo @route="preferences.tracking">
|
||||
{{d-icon "plus"}}
|
||||
<span>{{i18n "user.preferences_nav.tracking"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.tracking"
|
||||
@class="user-nav__preferences-tracking"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "plus"}}
|
||||
<span>{{i18n "user.preferences_nav.tracking"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
<li class="indent nav-users">
|
||||
<LinkTo @route="preferences.users">
|
||||
{{d-icon "users"}}
|
||||
<span>{{i18n "user.preferences_nav.users"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.users"
|
||||
@class="user-nav__preferences-users"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "users"}}
|
||||
<span>{{i18n "user.preferences_nav.users"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="nav-interface">
|
||||
<LinkTo @route="preferences.interface">
|
||||
{{d-icon "desktop"}}
|
||||
<span>{{i18n "user.preferences_nav.interface"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.interface"
|
||||
@class="user-nav__preferences-interface"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "desktop"}}
|
||||
<span>{{i18n "user.preferences_nav.interface"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if (not (eq @siteSettings.navigation_menu "legacy"))}}
|
||||
<li class="indent nav-sidebar">
|
||||
<LinkTo @route="preferences.sidebar">
|
||||
{{d-icon "bars"}}
|
||||
<span>{{i18n "user.preferences_nav.sidebar"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="preferences.sidebar"
|
||||
@class="user-nav__preferences-sidebar"
|
||||
@ariaCurrentContext={{@ariaCurrentContext}}
|
||||
>
|
||||
{{d-icon "bars"}}
|
||||
<span>{{i18n "user.preferences_nav.sidebar"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
|
||||
@ -134,17 +134,17 @@ export default Controller.extend({
|
||||
case "removeMembers":
|
||||
return ajax(`/groups/${this.model.id}/members.json`, {
|
||||
type: "DELETE",
|
||||
data: { user_ids: selection.map((u) => u.id).join(",") },
|
||||
data: { user_ids: selection.mapBy("id").join(",") },
|
||||
}).then(() => {
|
||||
this.model.reloadMembers(this.memberParams, true);
|
||||
this.set("isBulk", false);
|
||||
});
|
||||
|
||||
case "makeOwners":
|
||||
return ajax(`/admin/groups/${this.model.id}/owners.json`, {
|
||||
return ajax(`/groups/${this.model.id}/owners.json`, {
|
||||
type: "PUT",
|
||||
data: {
|
||||
group: { usernames: selection.map((u) => u.username).join(",") },
|
||||
usernames: selection.mapBy("username").join(","),
|
||||
},
|
||||
}).then(() => {
|
||||
selection.forEach((s) => s.set("owner", true));
|
||||
|
||||
@ -114,6 +114,17 @@ export default Controller.extend(ModalFunctionality, {
|
||||
);
|
||||
},
|
||||
|
||||
permanentlyDeleteRevisions(postId) {
|
||||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t("post.revisions.controls.destroy_confirm"),
|
||||
didConfirm: () => {
|
||||
Post.permanentlyDeleteRevisions(postId).then(() => {
|
||||
this.send("closeModal");
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
show(postId, postVersion) {
|
||||
Post.showRevision(postId, postVersion).then(() =>
|
||||
this.refresh(postId, postVersion)
|
||||
@ -162,6 +173,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
},
|
||||
|
||||
displayRevisions: gt("model.version_count", 2),
|
||||
|
||||
displayGoToFirst: propertyGreaterThan(
|
||||
"model.current_revision",
|
||||
"model.first_revision"
|
||||
@ -215,6 +227,15 @@ export default Controller.extend(ModalFunctionality, {
|
||||
return this.currentUser && this.currentUser.get("staff");
|
||||
},
|
||||
|
||||
@discourseComputed("model.previous_hidden")
|
||||
displayPermanentlyDeleteButton(previousHidden) {
|
||||
return (
|
||||
this.siteSettings.can_permanently_delete &&
|
||||
this.currentUser?.staff &&
|
||||
previousHidden
|
||||
);
|
||||
},
|
||||
|
||||
isEitherRevisionHidden: or("model.previous_hidden", "model.current_hidden"),
|
||||
|
||||
@discourseComputed(
|
||||
@ -352,6 +373,9 @@ export default Controller.extend(ModalFunctionality, {
|
||||
hideVersion() {
|
||||
this.hide(this.get("model.post_id"), this.get("model.current_revision"));
|
||||
},
|
||||
permanentlyDeleteVersions() {
|
||||
this.permanentlyDeleteRevisions(this.get("model.post_id"));
|
||||
},
|
||||
showVersion() {
|
||||
this.show(this.get("model.post_id"), this.get("model.current_revision"));
|
||||
},
|
||||
|
||||
@ -11,6 +11,7 @@ const EMAIL_LEVELS = {
|
||||
};
|
||||
|
||||
export default Controller.extend({
|
||||
subpageTitle: I18n.t("user.preferences_nav.emails"),
|
||||
emailMessagesLevelAway: equal(
|
||||
"model.user_option.email_messages_level",
|
||||
EMAIL_LEVELS.ONLY_WHEN_AWAY
|
||||
|
||||
@ -36,6 +36,7 @@ export default Controller.extend({
|
||||
preferencesController: controller("preferences"),
|
||||
makeColorSchemeDefault: true,
|
||||
canPreviewColorScheme: propertyEqual("model.id", "currentUser.id"),
|
||||
subpageTitle: I18n.t("user.preferences_nav.interface"),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
@ -5,6 +5,8 @@ import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend({
|
||||
subpageTitle: I18n.t("user.preferences_nav.notifications"),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import { inject as service } from "@ember/service";
|
||||
|
||||
export default Controller.extend({
|
||||
dialog: service(),
|
||||
subpageTitle: I18n.t("user.preferences_nav.profile"),
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.saveAttrNames = [
|
||||
|
||||
@ -15,7 +15,7 @@ const DEFAULT_AUTH_TOKENS_COUNT = 2;
|
||||
|
||||
export default Controller.extend(CanCheckEmails, {
|
||||
passwordProgress: null,
|
||||
|
||||
subpageTitle: I18n.t("user.preferences_nav.security"),
|
||||
showAllAuthTokens: false,
|
||||
|
||||
@discourseComputed("model.is_anonymous")
|
||||
|
||||
@ -12,6 +12,7 @@ export default class extends Controller {
|
||||
@tracked saved = false;
|
||||
@tracked selectedSidebarCategories = [];
|
||||
@tracked selectedSidebarTagNames = [];
|
||||
subpageTitle = I18n.t("user.preferences_nav.sidebar");
|
||||
|
||||
saveAttrNames = [
|
||||
"sidebar_category_ids",
|
||||
|
||||
@ -86,8 +86,7 @@ export default {
|
||||
messageBus.baseUrl =
|
||||
siteSettings.long_polling_base_url.replace(/\/$/, "") + "/";
|
||||
|
||||
messageBus.enableChunkedEncoding =
|
||||
isProduction() && siteSettings.enable_chunked_encoding;
|
||||
messageBus.enableChunkedEncoding = siteSettings.enable_chunked_encoding;
|
||||
|
||||
if (messageBus.baseUrl !== "/") {
|
||||
messageBus.ajax = function (opts) {
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
import I18n from "I18n";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
|
||||
function setupMessage(api) {
|
||||
const isSafari = navigator.vendor === "Apple Computer, Inc.";
|
||||
if (!isSafari) {
|
||||
return;
|
||||
}
|
||||
|
||||
let safariMajorVersion = navigator.userAgent.match(/Version\/(\d+)\./)?.[1];
|
||||
safariMajorVersion = safariMajorVersion
|
||||
? parseInt(safariMajorVersion, 10)
|
||||
: null;
|
||||
|
||||
if (safariMajorVersion && safariMajorVersion <= 13) {
|
||||
api.addGlobalNotice(
|
||||
I18n.t("safari_13_warning"),
|
||||
"browser-deprecation-warning",
|
||||
{ dismissable: true, dismissDuration: moment.duration(1, "week") }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "safari-13-deprecation",
|
||||
|
||||
initialize() {
|
||||
withPluginApi("0.8.37", setupMessage);
|
||||
},
|
||||
};
|
||||
@ -5,7 +5,6 @@ import User from "discourse/models/user";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import getURL, { samePrefix } from "discourse-common/lib/get-url";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import { selectedText } from "discourse/lib/utilities";
|
||||
import { wantsNewWindow } from "discourse/lib/intercept-click";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
@ -80,14 +79,6 @@ export default {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cancel click if triggered as part of selection.
|
||||
const selection = window.getSelection();
|
||||
if (selection.type === "Range" || selection.rangeCount > 0) {
|
||||
if (selectedText() !== "") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const link = e.currentTarget;
|
||||
const tracking = isValidLink(link);
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import I18n from "I18n";
|
||||
import renderTag from "discourse/lib/render-tag";
|
||||
|
||||
let callbacks = null;
|
||||
@ -56,7 +57,8 @@ export default function (topic, params) {
|
||||
}
|
||||
|
||||
if (customHtml || (tags && tags.length > 0)) {
|
||||
buffer = "<div class='discourse-tags'>";
|
||||
buffer = `<div class='discourse-tags' role='list'
|
||||
aria-label=${I18n.t("tagging.tags")}>`;
|
||||
if (tags) {
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
buffer +=
|
||||
|
||||
@ -74,7 +74,7 @@ export default Mixin.create(UploadDebugging, {
|
||||
}
|
||||
},
|
||||
|
||||
// TODO (martin) This and _onPreProcessComplete will need to be tweaked
|
||||
// NOTE: This and _onPreProcessComplete will need to be tweaked
|
||||
// if we ever add support for "determinate" preprocessors for uppy, which
|
||||
// means the progress will have a value rather than a started/complete
|
||||
// state ("indeterminate").
|
||||
|
||||
@ -31,7 +31,6 @@ export default Mixin.create({
|
||||
|
||||
_instrumentUploadTimings() {
|
||||
if (!this._performanceApiSupport()) {
|
||||
// TODO (martin) (2021-01-23) Check if FireFox fixed this yet.
|
||||
warn(
|
||||
"Some browsers do not return a PerformanceMeasure when calling performance.mark, disabling instrumentation. See https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure#return_value and https://bugzilla.mozilla.org/show_bug.cgi?id=1724645",
|
||||
{ id: "discourse.upload-debugging" }
|
||||
|
||||
@ -148,9 +148,9 @@ const Group = RestModel.extend({
|
||||
},
|
||||
|
||||
async addOwners(usernames, filter, notifyUsers) {
|
||||
const response = await ajax(`/admin/groups/${this.id}/owners.json`, {
|
||||
const response = await ajax(`/groups/${this.id}/owners.json`, {
|
||||
type: "PUT",
|
||||
data: { group: { usernames, notify_users: notifyUsers } },
|
||||
data: { usernames, notify_users: notifyUsers },
|
||||
});
|
||||
|
||||
if (filter) {
|
||||
|
||||
@ -461,6 +461,12 @@ Post.reopenClass({
|
||||
});
|
||||
},
|
||||
|
||||
permanentlyDeleteRevisions(postId) {
|
||||
return ajax(`/posts/${postId}/revisions/permanently_delete`, {
|
||||
type: "DELETE",
|
||||
});
|
||||
},
|
||||
|
||||
showRevision(postId, version) {
|
||||
return ajax(`/posts/${postId}/revisions/${version}/show`, {
|
||||
type: "PUT",
|
||||
|
||||
@ -471,6 +471,10 @@ const Topic = RestModel.extend({
|
||||
!deleted_by.staff &&
|
||||
!deleted_by.groups.some(
|
||||
(group) => group.name === this.category.reviewable_by_group_name
|
||||
) &&
|
||||
!(
|
||||
this.siteSettings.tl4_delete_posts_and_topics &&
|
||||
deleted_by.trust_level >= 4
|
||||
)
|
||||
) {
|
||||
DiscourseURL.redirectTo("/");
|
||||
|
||||
@ -2,6 +2,7 @@ import RestrictedUserRoute from "discourse/routes/restricted-user";
|
||||
import UserBadge from "discourse/models/user-badge";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default RestrictedUserRoute.extend({
|
||||
showFooter: true,
|
||||
@ -32,6 +33,7 @@ export default RestrictedUserRoute.extend({
|
||||
newPrimaryGroupInput: user.get("primary_group_id"),
|
||||
newFlairGroupId: user.get("flair_group_id"),
|
||||
newStatus: user.status,
|
||||
subpageTitle: I18n.t("user.preferences_nav.account"),
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -1,7 +1,19 @@
|
||||
import RestrictedUserRoute from "discourse/routes/restricted-user";
|
||||
import I18n from "I18n";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default RestrictedUserRoute.extend({
|
||||
router: service(),
|
||||
|
||||
model() {
|
||||
return this.modelFor("user");
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
let controller = this.controllerFor(this.router.currentRouteName);
|
||||
let subpageTitle = controller?.subpageTitle;
|
||||
return subpageTitle
|
||||
? `${subpageTitle} - ${I18n.t("user.preferences")}`
|
||||
: I18n.t("user.preferences");
|
||||
},
|
||||
});
|
||||
|
||||
@ -136,7 +136,21 @@ export default DiscourseRoute.extend(FilterModeMixin, {
|
||||
noSubcategories,
|
||||
loading: false,
|
||||
});
|
||||
this.searchService.set("searchContext", model.tag.searchContext);
|
||||
|
||||
if (model.category || model.additionalTags) {
|
||||
const tagIntersectionSearchContext = {
|
||||
type: "tagIntersection",
|
||||
tagId: model.tag.id,
|
||||
tag: model.tag,
|
||||
additionalTags: model.additionalTags || null,
|
||||
categoryId: model.category?.id || null,
|
||||
category: model.category || null,
|
||||
};
|
||||
|
||||
this.searchService.set("searchContext", tagIntersectionSearchContext);
|
||||
} else {
|
||||
this.searchService.set("searchContext", model.tag.searchContext);
|
||||
}
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
|
||||
@ -2,6 +2,7 @@ import { action } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { Promise } from "rsvp";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
queryParams: {
|
||||
@ -50,6 +51,10 @@ export default DiscourseRoute.extend({
|
||||
this.render("user_bookmarks");
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.3");
|
||||
},
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
this.controllerFor("user-activity")._showFooter();
|
||||
|
||||
@ -38,6 +38,10 @@ export default DiscourseRoute.extend({
|
||||
this.appEvents.off("draft:destroyed", this, this.refresh);
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.15");
|
||||
},
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
this.controllerFor("user-activity")._showFooter();
|
||||
|
||||
@ -25,4 +25,8 @@ export default UserActivityStreamRoute.extend({
|
||||
|
||||
return { title, body };
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.filters.all");
|
||||
},
|
||||
});
|
||||
|
||||
@ -25,6 +25,10 @@ export default UserActivityStreamRoute.extend({
|
||||
return { title, body };
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.1");
|
||||
},
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
this.controllerFor("application").set("showFooter", true);
|
||||
|
||||
@ -42,6 +42,10 @@ export default UserTopicListRoute.extend({
|
||||
return { title, body };
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return `${I18n.t("user.read")}`;
|
||||
},
|
||||
|
||||
@action
|
||||
triggerRefresh() {
|
||||
this.refresh();
|
||||
|
||||
@ -29,6 +29,10 @@ export default UserActivityStreamRoute.extend({
|
||||
return { title, body };
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.5");
|
||||
},
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
this.controllerFor("application").set("showFooter", true);
|
||||
|
||||
@ -50,6 +50,10 @@ export default UserTopicListRoute.extend({
|
||||
return { title, body };
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.4");
|
||||
},
|
||||
|
||||
@action
|
||||
triggerRefresh() {
|
||||
this.refresh();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model() {
|
||||
@ -19,4 +20,8 @@ export default DiscourseRoute.extend({
|
||||
setupController(controller, user) {
|
||||
this.controllerFor("user-activity").set("model", user);
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.activity_stream");
|
||||
},
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@ import DiscourseRoute from "discourse/routes/discourse";
|
||||
import UserBadge from "discourse/models/user-badge";
|
||||
import ViewingActionType from "discourse/mixins/viewing-action-type";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend(ViewingActionType, {
|
||||
model() {
|
||||
@ -20,6 +21,10 @@ export default DiscourseRoute.extend(ViewingActionType, {
|
||||
this.render("user/badges");
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("badges.title");
|
||||
},
|
||||
|
||||
@action
|
||||
didTransition() {
|
||||
this.controllerFor("application").set("showFooter", true);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import Invite from "discourse/models/invite";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
model(params) {
|
||||
@ -27,6 +28,10 @@ export default DiscourseRoute.extend({
|
||||
});
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.invited." + this.inviteFilter + "_tab");
|
||||
},
|
||||
|
||||
@action
|
||||
triggerRefresh() {
|
||||
this.refresh();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
setupController(controller) {
|
||||
@ -10,4 +11,8 @@ export default DiscourseRoute.extend({
|
||||
can_see_invite_details,
|
||||
});
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.invited.title");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import UserAction from "discourse/models/user-action";
|
||||
import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default UserActivityStreamRoute.extend({
|
||||
userActionType: UserAction.TYPES["edits"],
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.11");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
controllerName: "user-notifications",
|
||||
@ -6,6 +7,10 @@ export default DiscourseRoute.extend({
|
||||
this.render("user/notifications-index");
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.filters.all");
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
if (!model) {
|
||||
this.transitionTo("userNotifications.responses");
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import UserAction from "discourse/models/user-action";
|
||||
import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default UserActivityStreamRoute.extend({
|
||||
userActionType: UserAction.TYPES["likes_received"],
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.1");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import UserAction from "discourse/models/user-action";
|
||||
import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default UserActivityStreamRoute.extend({
|
||||
userActionType: UserAction.TYPES["mentions"],
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.7");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import UserAction from "discourse/models/user-action";
|
||||
import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default UserActivityStreamRoute.extend({
|
||||
userActionType: UserAction.TYPES["replies"],
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user_action_groups.6");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import ViewingActionType from "discourse/mixins/viewing-action-type";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend(ViewingActionType, {
|
||||
controllerName: "user-notifications",
|
||||
@ -31,4 +32,8 @@ export default DiscourseRoute.extend(ViewingActionType, {
|
||||
controller.set("user", this.modelFor("user"));
|
||||
this.viewingActionType(-1);
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.notifications");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
showFooter: true,
|
||||
@ -11,4 +12,8 @@ export default DiscourseRoute.extend({
|
||||
|
||||
return user.summary();
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("user.summary.title");
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import I18n from "I18n";
|
||||
import User from "discourse/models/user";
|
||||
import { action } from "@ember/object";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
@ -98,9 +97,7 @@ export default DiscourseRoute.extend({
|
||||
|
||||
titleToken() {
|
||||
const username = this.modelFor("user").username;
|
||||
if (username) {
|
||||
return [I18n.t("user.profile"), username];
|
||||
}
|
||||
return username ? username : null;
|
||||
},
|
||||
|
||||
@action
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<div class="badge-title">
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
<form class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
|
||||
@ -181,20 +181,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{#if this.siteSettings.tagging_enabled}}
|
||||
<section class="field minimum-required-tags">
|
||||
<label for="category-minimum-tags">
|
||||
{{i18n "category.minimum_required_tags"}}
|
||||
</label>
|
||||
<TextField
|
||||
@value={{this.category.minimum_required_tags}}
|
||||
@id="category-minimum-tags"
|
||||
@type="number"
|
||||
@min="0"
|
||||
/>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
<section class="field num-auto-bump-daily">
|
||||
<label for="category-number-daily-bump">
|
||||
{{i18n "category.num_auto_bump_daily"}}
|
||||
@ -378,4 +364,4 @@
|
||||
@name="category-custom-settings"
|
||||
@args={{hash category=this.category}}
|
||||
@tagName="section"
|
||||
/>
|
||||
/>
|
||||
|
||||
@ -1,3 +1,14 @@
|
||||
<section class="field minimum-required-tags">
|
||||
<label for="category-minimum-tags">
|
||||
{{i18n "category.minimum_required_tags"}}
|
||||
</label>
|
||||
<TextField
|
||||
@value={{this.category.minimum_required_tags}}
|
||||
@id="category-minimum-tags"
|
||||
@type="number"
|
||||
@min="0"
|
||||
/>
|
||||
</section>
|
||||
<section class="field allowed-tags">
|
||||
<label>{{i18n "category.tags_allowed_tags"}}</label>
|
||||
<TagChooser
|
||||
@ -71,4 +82,4 @@
|
||||
@class="add-required-tag-group"
|
||||
/>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
name="message"
|
||||
class="flag-message"
|
||||
placeholder={{this.customPlaceholder}}
|
||||
aria-label={{i18n "flagging.notify_user_textarea_label"}}
|
||||
@value={{this.message}}
|
||||
/>
|
||||
<div
|
||||
@ -48,6 +49,7 @@
|
||||
name="message"
|
||||
class="flag-message"
|
||||
placeholder={{this.customPlaceholder}}
|
||||
aria-label={{i18n "flagging.notify_moderators_textarea_label"}}
|
||||
@value={{this.message}}
|
||||
/>
|
||||
<div
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
{{! template-lint-disable no-down-event-binding }}
|
||||
{{! template-lint-disable no-invalid-interactive }}
|
||||
|
||||
<div class="horizontal-overflow-nav {{if this.hasScroll 'has-scroll'}}">
|
||||
<nav
|
||||
class="horizontal-overflow-nav {{if this.hasScroll 'has-scroll'}}"
|
||||
aria-label={{@ariaLabel}}
|
||||
>
|
||||
{{#if this.hasScroll}}
|
||||
<a
|
||||
role="button"
|
||||
@ -43,4 +46,4 @@
|
||||
{{d-icon "chevron-right"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</nav>
|
||||
@ -111,7 +111,9 @@
|
||||
{{#if this.hasStatus}}
|
||||
<h3 class="user-status">
|
||||
{{html-safe this.userStatusEmoji}}
|
||||
{{this.user.status.description}}
|
||||
<span class="user-status__description">
|
||||
{{this.user.status.description}}
|
||||
</span>
|
||||
{{format-date this.user.status.ends_at format="tiny"}}
|
||||
</h3>
|
||||
{{/if}}
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
<BulkGroupMemberDropdown
|
||||
@bulkSelection={{this.bulkSelection}}
|
||||
@canAdminGroup={{this.model.can_admin_group}}
|
||||
@canEditGroup={{this.model.can_edit_group}}
|
||||
@onChange={{action "actOnSelection" this.bulkSelection}}
|
||||
/>
|
||||
{{/if}}
|
||||
@ -148,6 +149,7 @@
|
||||
<GroupMemberDropdown
|
||||
@member={{m}}
|
||||
@canAdminGroup={{this.model.can_admin_group}}
|
||||
@canEditGroup={{this.model.can_edit_group}}
|
||||
@onChange={{action "actOnGroup" m}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
@ -16,6 +16,6 @@
|
||||
<PluginOutlet @name="group-activity-bottom" @connectorTagName="li" />
|
||||
</MobileNav>
|
||||
</section>
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{outlet}}
|
||||
</section>
|
||||
@ -12,6 +12,6 @@
|
||||
{{/each}}
|
||||
</MobileNav>
|
||||
</section>
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{outlet}}
|
||||
</section>
|
||||
@ -12,6 +12,6 @@
|
||||
</li>
|
||||
</MobileNav>
|
||||
</section>
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{outlet}}
|
||||
</section>
|
||||
@ -1,4 +1,4 @@
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{#if this.model.permissions}}
|
||||
<label class="group-category-permissions-desc">
|
||||
{{i18n "groups.permissions.description"}}
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
<GroupMemberDropdown
|
||||
@member={{user}}
|
||||
@canAdminGroup={{this.model.can_admin_group}}
|
||||
@canEditGroup={{this.model.can_edit_group}}
|
||||
@onChange={{action "actOnGroup" user}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
@ -250,6 +250,16 @@
|
||||
@disabled={{this.loading}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.displayPermanentlyDeleteButton}}
|
||||
<DButton
|
||||
@action={{action "permanentlyDeleteVersions"}}
|
||||
@icon="far-trash-alt"
|
||||
@label="post.revisions.controls.destroy"
|
||||
@class="btn-danger"
|
||||
@disabled={{this.loading}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
{{i18n "groups.membership_request.reason"}}
|
||||
</label>
|
||||
|
||||
<ExpandingTextArea @value={{this.reason}} />
|
||||
<ExpandingTextArea @value={{this.reason}} @maxlength="280" />
|
||||
</div>
|
||||
</DModalBody>
|
||||
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
{{#if this.currentUser.redesigned_user_page_nav_enabled}}
|
||||
<DSection @pageClass="user-preferences" />
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav>
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - preferences">
|
||||
<UserNav::PreferencesNav
|
||||
@currentUser={{this.currentUser}}
|
||||
@model={{this.model}}
|
||||
@siteSettings={{this.siteSettings}}
|
||||
@ariaCurrentContext="subNav"
|
||||
/>
|
||||
</HorizontalOverflowNav>
|
||||
</div>
|
||||
@ -103,7 +104,7 @@
|
||||
</DSection>
|
||||
{{/if}}
|
||||
|
||||
<section class="user-content user-preferences">
|
||||
<section class="user-content user-preferences" id="user-content">
|
||||
<PluginOutlet
|
||||
@name="above-user-preferences"
|
||||
@tagName="span"
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
{{#if this.canInviteToForum}}
|
||||
<LoadMore
|
||||
@class="user-content"
|
||||
@id="user-content"
|
||||
@selector=".user-invite-list tr"
|
||||
@action={{action "loadMore"}}
|
||||
>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<DSection @pageClass="user-invites" />
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav>
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - invites">
|
||||
<NavItem
|
||||
@route="userInvited.show"
|
||||
@routeParam="pending"
|
||||
|
||||
@ -1,43 +1,45 @@
|
||||
<UserNav::MessagesSecondaryNav>
|
||||
<li class="messages-group-latest">
|
||||
<LinkTo @route="userPrivateMessages.group.index" @model={{this.groupName}}>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "categories.latest"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.group.index"
|
||||
@class="user-nav__messages-group-latest"
|
||||
@model={{this.groupName}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "categories.latest"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if this.viewingSelf}}
|
||||
<li class="messages-group-new">
|
||||
<LinkTo
|
||||
@route="userPrivateMessages.group.new"
|
||||
@model={{this.groupName}}
|
||||
class="new"
|
||||
>
|
||||
{{d-icon "exclamation-circle"}}
|
||||
<span>{{this.newLinkText}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.group.new"
|
||||
@model={{this.groupName}}
|
||||
@class="user-nav__messages-group-new"
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "exclamation-circle"}}
|
||||
<span>{{this.newLinkText}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="messages-group-unread">
|
||||
<LinkTo
|
||||
@route="userPrivateMessages.group.unread"
|
||||
@model={{this.groupName}}
|
||||
class="unread"
|
||||
>
|
||||
{{d-icon "plus-circle"}}
|
||||
<span>{{this.unreadLinkText}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.group.unread"
|
||||
@model={{this.groupName}}
|
||||
@class="user-nav__messages-group-unread"
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "plus-circle"}}
|
||||
<span>{{this.unreadLinkText}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="messages-group-archive">
|
||||
<LinkTo
|
||||
@route="userPrivateMessages.group.archive"
|
||||
@model={{this.groupName}}
|
||||
>
|
||||
{{d-icon "archive"}}
|
||||
<span>{{i18n "user.messages.archive"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.group.archive"
|
||||
@class="user-nav__messages-group-archive"
|
||||
@model={{this.groupName}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "archive"}}
|
||||
<span>{{i18n "user.messages.archive"}}</span>
|
||||
</DNavigationItem>
|
||||
{{/if}}
|
||||
</UserNav::MessagesSecondaryNav>
|
||||
|
||||
|
||||
@ -5,50 +5,59 @@
|
||||
{{/if}}
|
||||
|
||||
<UserNav::MessagesSecondaryNav>
|
||||
<li class="messages-latest">
|
||||
<LinkTo @route="userPrivateMessages.user.index" @model={{this.model}}>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "categories.latest"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.user.index"
|
||||
@class="user-nav__messages-latest"
|
||||
@model={{this.model}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "envelope"}}
|
||||
<span>{{i18n "categories.latest"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="messages-sent">
|
||||
<LinkTo @route="userPrivateMessages.user.sent" @model={{this.model}}>
|
||||
{{d-icon "reply"}}
|
||||
<span>{{i18n "user.messages.sent"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.user.sent"
|
||||
@class="user-nav__messages-sent"
|
||||
@model={{this.model}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "reply"}}
|
||||
<span>{{i18n "user.messages.sent"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
{{#if this.viewingSelf}}
|
||||
<li class="messages-new">
|
||||
<LinkTo
|
||||
@route="userPrivateMessages.user.new"
|
||||
@model={{this.model}}
|
||||
class="new"
|
||||
>
|
||||
{{d-icon "exclamation-circle"}}
|
||||
<span>{{this.newLinkText}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.user.new"
|
||||
@class="user-nav__messages-new"
|
||||
@model={{this.model}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "exclamation-circle"}}
|
||||
<span>{{this.newLinkText}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.user.unread"
|
||||
@class="user-nav__messages-unread"
|
||||
@model={{this.model}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "plus-circle"}}
|
||||
<span>{{this.unreadLinkText}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
<li class="messages-unread">
|
||||
<LinkTo
|
||||
@route="userPrivateMessages.user.unread"
|
||||
@model={{this.model}}
|
||||
class="unread"
|
||||
>
|
||||
{{d-icon "plus-circle"}}
|
||||
<span>{{this.unreadLinkText}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
<li class="messages-archive">
|
||||
<LinkTo @route="userPrivateMessages.user.archive" @model={{this.model}}>
|
||||
{{d-icon "archive"}}
|
||||
<span>{{i18n "user.messages.archive"}}</span>
|
||||
</LinkTo>
|
||||
</li>
|
||||
<DNavigationItem
|
||||
@route="userPrivateMessages.user.archive"
|
||||
@class="user-nav__messages-archive"
|
||||
@model={{this.model}}
|
||||
@ariaCurrentContext="subNav"
|
||||
>
|
||||
{{d-icon "archive"}}
|
||||
<span>{{i18n "user.messages.archive"}}</span>
|
||||
</DNavigationItem>
|
||||
|
||||
</UserNav::MessagesSecondaryNav>
|
||||
|
||||
{{outlet}}
|
||||
@ -10,6 +10,9 @@
|
||||
{{this.primaryGroup}}"
|
||||
>
|
||||
<DSection @class="user-main">
|
||||
<a href="#user-content" id="skip-link" class="skip-link__user-nav">
|
||||
{{i18n "skip_user_nav"}}
|
||||
</a>
|
||||
<section
|
||||
class="{{if this.collapsedInfo 'collapsed-info'}}
|
||||
about
|
||||
@ -111,65 +114,12 @@
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
<UserProfileAvatar @user={{this.model}} @tagName="" />
|
||||
<section class="controls">
|
||||
<ul>
|
||||
{{#if this.model.can_send_private_message_to_user}}
|
||||
<li>
|
||||
<DButton
|
||||
@class="btn-primary compose-pm"
|
||||
@action={{route-action "composePrivateMessage" this.model}}
|
||||
@icon="envelope"
|
||||
@label="user.private_message"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.canMuteOrIgnoreUser}}
|
||||
<li>
|
||||
<UserNotificationsDropdown
|
||||
@user={{this.model}}
|
||||
@value={{this.userNotificationLevel}}
|
||||
@updateNotificationLevel={{action
|
||||
"updateNotificationLevel"
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.displayTopLevelAdminButton}}
|
||||
<li><a
|
||||
href={{this.model.adminPath}}
|
||||
class="btn btn-default"
|
||||
>{{d-icon "wrench"}}<span class="d-button-label">{{i18n
|
||||
"admin.user.show_admin_profile"
|
||||
}}</span></a></li>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="user-profile-controls"
|
||||
@connectorTagName="li"
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
|
||||
{{#if this.canExpandProfile}}
|
||||
<li>
|
||||
<DButton
|
||||
@ariaExpanded={{this.collapsedInfoState.isExpanded}}
|
||||
@ariaLabel={{this.collapsedInfoState.ariaLabel}}
|
||||
@ariaControls="collapsed-info-panel"
|
||||
@class="btn-default"
|
||||
@label={{concat "user." this.collapsedInfoState.label}}
|
||||
@icon={{this.collapsedInfoState.icon}}
|
||||
@action={{action this.collapsedInfoState.action}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<div class="primary-textual">
|
||||
<div class="user-profile-names">
|
||||
<h1 class={{if this.nameFirst "full-name" "username"}}>
|
||||
<div
|
||||
class="{{if this.nameFirst 'full-name' 'username'}}
|
||||
user-profile-names__primary"
|
||||
>
|
||||
{{if
|
||||
this.nameFirst
|
||||
this.model.name
|
||||
@ -179,15 +129,22 @@
|
||||
{{#if this.model.status}}
|
||||
<UserStatusMessage @status={{this.model.status}} />
|
||||
{{/if}}
|
||||
</h1>
|
||||
<h2 class={{if this.nameFirst "username" "full-name"}}>{{#if
|
||||
</div>
|
||||
<div
|
||||
class="{{if this.nameFirst 'username' 'full-name'}}
|
||||
user-profile-names__secondary"
|
||||
>{{#if
|
||||
this.nameFirst
|
||||
}}{{this.model.username}}{{else}}{{this.model.name}}{{/if}}</h2>
|
||||
}}{{this.model.username}}{{else}}{{this.model.name}}{{/if}}</div>
|
||||
{{#if this.model.staged}}
|
||||
<h2 class="staged">{{i18n "user.staged"}}</h2>
|
||||
<div class="staged user-profile-names__secondary">{{i18n
|
||||
"user.staged"
|
||||
}}</div>
|
||||
{{/if}}
|
||||
{{#if this.model.title}}
|
||||
<h3>{{this.model.title}}</h3>
|
||||
<div
|
||||
class="user-profile-names__title"
|
||||
>{{this.model.title}}</div>
|
||||
{{/if}}
|
||||
<PluginOutlet
|
||||
@name="user-post-names"
|
||||
@ -198,9 +155,10 @@
|
||||
</div>
|
||||
|
||||
{{#if this.showFeaturedTopic}}
|
||||
<h3 class="featured-topic">
|
||||
<span>{{i18n "user.featured_topic"}}</span>
|
||||
<LinkTo
|
||||
<div class="featured-topic user-profile__featured-topic">
|
||||
<span title={{i18n "user.featured_topic"}}>
|
||||
{{d-icon "book"~}}
|
||||
</span><LinkTo
|
||||
@route="topic"
|
||||
@models={{array
|
||||
this.model.featured_topic.slug
|
||||
@ -209,19 +167,20 @@
|
||||
>{{html-safe
|
||||
(replace-emoji this.model.featured_topic.fancy_title)
|
||||
}}</LinkTo>
|
||||
</h3>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<h3 class="location-and-website">
|
||||
<div
|
||||
class="location-and-website user-profile__location-and-website"
|
||||
>
|
||||
{{#if this.model.location}}<div
|
||||
class="user-profile-location"
|
||||
>{{d-icon "map-marker-alt"}}
|
||||
>{{d-icon "map-marker-alt"~}}
|
||||
{{this.model.location}}</div>{{/if}}
|
||||
{{#if this.model.website_name}}
|
||||
<div class="user-profile-website">
|
||||
{{d-icon "globe"}}
|
||||
{{#if this.linkWebsite}}
|
||||
{{! template-lint-disable }}
|
||||
<div class="user-profile-website">{{d-icon "globe"~}}
|
||||
{{#if this.linkWebsite~}}
|
||||
{{~! template-lint-disable ~}}
|
||||
<a
|
||||
href={{this.model.website}}
|
||||
rel="noopener {{unless
|
||||
@ -243,7 +202,7 @@
|
||||
@connectorTagName="div"
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="bio">
|
||||
{{#if this.model.suspended}}
|
||||
@ -310,6 +269,62 @@
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section class="controls">
|
||||
<ul>
|
||||
{{#if this.model.can_send_private_message_to_user}}
|
||||
<li>
|
||||
<DButton
|
||||
@class="btn-primary compose-pm"
|
||||
@action={{route-action "composePrivateMessage" this.model}}
|
||||
@icon="envelope"
|
||||
@label="user.private_message"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.canMuteOrIgnoreUser}}
|
||||
<li>
|
||||
<UserNotificationsDropdown
|
||||
@user={{this.model}}
|
||||
@value={{this.userNotificationLevel}}
|
||||
@updateNotificationLevel={{action
|
||||
"updateNotificationLevel"
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.displayTopLevelAdminButton}}
|
||||
<li><a
|
||||
href={{this.model.adminPath}}
|
||||
class="btn btn-default"
|
||||
>{{d-icon "wrench"}}<span class="d-button-label">{{i18n
|
||||
"admin.user.show_admin_profile"
|
||||
}}</span></a></li>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="user-profile-controls"
|
||||
@connectorTagName="li"
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
|
||||
{{#if this.canExpandProfile}}
|
||||
<li>
|
||||
<DButton
|
||||
@ariaExpanded={{this.collapsedInfoState.isExpanded}}
|
||||
@ariaLabel={{this.collapsedInfoState.ariaLabel}}
|
||||
@ariaControls="collapsed-info-panel"
|
||||
@class="btn-default"
|
||||
@label={{concat "user." this.collapsedInfoState.label}}
|
||||
@icon={{this.collapsedInfoState.icon}}
|
||||
@action={{action this.collapsedInfoState.action}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
<PluginOutlet
|
||||
@name="user-profile-above-collapsed-info"
|
||||
@ -402,7 +417,6 @@
|
||||
</dl>
|
||||
<PluginOutlet
|
||||
@name="user-profile-secondary"
|
||||
@tagName="span"
|
||||
@connectorTagName="div"
|
||||
@args={{hash model=this.model}}
|
||||
/>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<DSection @pageClass="user-activity" />
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav>
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - activity">
|
||||
<UserNav::ActivityNav
|
||||
@user={{this.user}}
|
||||
@viewingSelf={{this.viewingSelf}}
|
||||
@ -10,6 +10,7 @@
|
||||
@siteSettings={{this.siteSettings}}
|
||||
@draftLabel={{this.draftLabel}}
|
||||
@pendingLabel={{this.pendingLabel}}
|
||||
@ariaCurrentContext="subNav"
|
||||
/>
|
||||
</HorizontalOverflowNav>
|
||||
</div>
|
||||
@ -88,6 +89,6 @@
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{outlet}}
|
||||
</section>
|
||||
@ -1,4 +1,4 @@
|
||||
<DSection @pageClass="user-badges" @class="user-content">
|
||||
<DSection @pageClass="user-badges" @class="user-content" id="user-content">
|
||||
<p class="favorite-count">
|
||||
{{i18n
|
||||
"badges.favorite_count"
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
<HorizontalOverflowNav
|
||||
@className="messages-nav"
|
||||
@ariaLabel="User secondary - messages"
|
||||
id="user-navigation-secondary__horizontal-nav"
|
||||
/>
|
||||
|
||||
@ -183,7 +184,7 @@
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
{{#unless this.currentUser.redesigned_user_page_nav_enabled}}
|
||||
<div class="list-actions">
|
||||
{{#if this.site.mobileView}}
|
||||
|
||||
@ -2,10 +2,11 @@
|
||||
<DSection @pageClass="user-notifications" />
|
||||
|
||||
<div class="user-navigation user-navigation-secondary">
|
||||
<HorizontalOverflowNav>
|
||||
<HorizontalOverflowNav @ariaLabel="User secondary - notifications">
|
||||
<UserNav::NotificationsNav
|
||||
@model={{this.model}}
|
||||
@siteSettings={{this.siteSettings}}
|
||||
@ariaCurrentContext="subNav"
|
||||
/>
|
||||
</HorizontalOverflowNav>
|
||||
|
||||
@ -79,7 +80,7 @@
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<section class="user-content">
|
||||
<section class="user-content" id="user-content">
|
||||
<LoadMore
|
||||
@class="notification-history user-stream"
|
||||
@selector=".user-stream .notification"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<DSection @pageClass="user-summary" @tagName="">
|
||||
<div class="user-content">
|
||||
<div class="user-content" id="user-content">
|
||||
<PluginOutlet
|
||||
@name="above-user-summary-stats"
|
||||
@args={{hash model=this.model user=this.user}}
|
||||
|
||||
@ -70,7 +70,7 @@ createWidgetFrom(QuickAccessPanel, "quick-access-bookmarks", {
|
||||
href,
|
||||
title: bookmark.name,
|
||||
content: bookmark.title,
|
||||
username: bookmark.user.username,
|
||||
username: bookmark.user?.username,
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -415,13 +415,42 @@ createWidget("search-menu-assistant", {
|
||||
|
||||
const content = [];
|
||||
const { suggestionKeyword, term } = attrs;
|
||||
let prefix = term?.split(suggestionKeyword)[0].trim() || "";
|
||||
|
||||
if (prefix.length) {
|
||||
prefix = `${prefix} `;
|
||||
let prefix;
|
||||
if (suggestionKeyword !== "+") {
|
||||
prefix = term?.split(suggestionKeyword)[0].trim() || "";
|
||||
|
||||
if (prefix.length) {
|
||||
prefix = `${prefix} `;
|
||||
}
|
||||
}
|
||||
|
||||
switch (suggestionKeyword) {
|
||||
case "+":
|
||||
attrs.results.forEach((item) => {
|
||||
if (item.additionalTags) {
|
||||
prefix = term?.split(" ").slice(0, -1).join(" ").trim() || "";
|
||||
} else {
|
||||
prefix = term?.split("#")[0].trim() || "";
|
||||
}
|
||||
|
||||
if (prefix.length) {
|
||||
prefix = `${prefix} `;
|
||||
}
|
||||
|
||||
content.push(
|
||||
this.attach("search-menu-assistant-item", {
|
||||
prefix,
|
||||
tag: item.tagName,
|
||||
additionalTags: item.additionalTags,
|
||||
category: item.category,
|
||||
slug: term,
|
||||
withInLabel: attrs.withInLabel,
|
||||
isIntersection: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
break;
|
||||
case "#":
|
||||
attrs.results.forEach((item) => {
|
||||
if (item.model) {
|
||||
@ -572,6 +601,36 @@ createWidget("search-menu-initial-options", {
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "tagIntersection":
|
||||
let tagTerm;
|
||||
if (ctx.additionalTags) {
|
||||
const tags = [ctx.tagId, ...ctx.additionalTags];
|
||||
tagTerm = `${term} tags:${tags.join("+")}`;
|
||||
} else {
|
||||
tagTerm = `${term} #${ctx.tagId}`;
|
||||
}
|
||||
let suggestionOptions = {
|
||||
tagName: ctx.tagId,
|
||||
additionalTags: ctx.additionalTags,
|
||||
};
|
||||
if (ctx.category) {
|
||||
const categorySlug = ctx.category.parentCategory
|
||||
? `#${ctx.category.parentCategory.slug}:${ctx.category.slug}`
|
||||
: `#${ctx.category.slug}`;
|
||||
suggestionOptions.categoryName = categorySlug;
|
||||
suggestionOptions.category = ctx.category;
|
||||
tagTerm = tagTerm + ` ${categorySlug}`;
|
||||
}
|
||||
|
||||
content.push(
|
||||
this.attach("search-menu-assistant", {
|
||||
term: tagTerm,
|
||||
suggestionKeyword: "+",
|
||||
results: [suggestionOptions],
|
||||
withInLabel: true,
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "user":
|
||||
content.push(
|
||||
this.attach("search-menu-assistant-item", {
|
||||
@ -617,7 +676,7 @@ createWidget("search-menu-initial-options", {
|
||||
slug: term,
|
||||
extraHint: I18n.t("search.enter_hint"),
|
||||
label: [
|
||||
h("span.keyword", `${term} `),
|
||||
h("span.keyword", `${term}`),
|
||||
opts.withLabel
|
||||
? h("span.label-suffix", I18n.t("search.in_topics_posts"))
|
||||
: null,
|
||||
@ -677,11 +736,20 @@ createWidget("search-menu-assistant-item", {
|
||||
link: false,
|
||||
})
|
||||
);
|
||||
} else if (attrs.tag) {
|
||||
attributes.href = getURL(`/tag/${attrs.tag}`);
|
||||
|
||||
content.push(iconNode("tag"));
|
||||
content.push(h("span.search-item-tag", attrs.tag));
|
||||
// category and tag combination
|
||||
if (attrs.tag && attrs.isIntersection) {
|
||||
attributes.href = getURL(`/tag/${attrs.tag}`);
|
||||
content.push(h("span.search-item-tag", [iconNode("tag"), attrs.tag]));
|
||||
}
|
||||
} else if (attrs.tag) {
|
||||
if (attrs.isIntersection && attrs.additionalTags?.length) {
|
||||
const tags = [attrs.tag, ...attrs.additionalTags];
|
||||
content.push(h("span.search-item-tag", `tags:${tags.join("+")}`));
|
||||
} else {
|
||||
attributes.href = getURL(`/tag/${attrs.tag}`);
|
||||
content.push(h("span.search-item-tag", [iconNode("tag"), attrs.tag]));
|
||||
}
|
||||
} else if (attrs.user) {
|
||||
const userResult = [
|
||||
avatarImg("small", {
|
||||
|
||||
@ -10,8 +10,7 @@ const browsers = [
|
||||
];
|
||||
|
||||
if (isCI || isProduction) {
|
||||
// https://meta.discourse.org/t/224747
|
||||
browsers.push("Safari 12");
|
||||
browsers.push("Safari 15");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@ -17,13 +17,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/standalone": "^7.20.12",
|
||||
"@babel/standalone": "^7.20.13",
|
||||
"@discourse/backburner.js": "^2.7.1-0",
|
||||
"@discourse/itsatrap": "^2.0.10",
|
||||
"@ember-compat/tracked-built-ins": "^0.9.1",
|
||||
"@ember/jquery": "^2.0.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@ember/render-modifiers": "^2.0.4",
|
||||
"@ember/render-modifiers": "^2.0.5",
|
||||
"@ember/test-helpers": "^2.9.3",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/syntax": "^0.84.2",
|
||||
@ -49,7 +49,7 @@
|
||||
"discourse-hbr": "1.0.0",
|
||||
"discourse-plugins": "1.0.0",
|
||||
"discourse-widget-hbs": "1.0.0",
|
||||
"ember-auto-import": "^2.5.0",
|
||||
"ember-auto-import": "^2.6.0",
|
||||
"ember-auto-import-chunks-json-generator": "^1.0.0",
|
||||
"ember-buffered-proxy": "^2.1.1",
|
||||
"ember-cached-decorator-polyfill": "^1.0.1",
|
||||
@ -69,25 +69,25 @@
|
||||
"ember-modifier": "^4.0.0",
|
||||
"ember-on-resize-modifier": "^1.1.0",
|
||||
"ember-qunit": "^6.1.1",
|
||||
"ember-rfc176-data": "^0.3.17",
|
||||
"ember-rfc176-data": "^0.3.18",
|
||||
"ember-source": "~3.28.11",
|
||||
"ember-test-selectors": "^6.0.0",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-plugin-qunit": "^7.3.4",
|
||||
"handlebars": "^4.7.7",
|
||||
"html-entities": "^2.3.3",
|
||||
"imports-loader": "^4.0.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^21.0.0",
|
||||
"jsdom": "^21.1.0",
|
||||
"loader.js": "^4.7.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"message-bus-client": "^4.3.0",
|
||||
"message-bus-client": "^4.3.2",
|
||||
"messageformat": "0.1.5",
|
||||
"pretender": "^3.4.7",
|
||||
"pretty-text": "1.0.0",
|
||||
"qunit": "^2.19.3",
|
||||
"qunit": "^2.19.4",
|
||||
"qunit-dom": "^2.0.0",
|
||||
"sass": "^1.57.0",
|
||||
"sass": "^1.57.1",
|
||||
"select-kit": "1.0.0",
|
||||
"sinon": "^15.0.1",
|
||||
"source-map": "^0.7.4",
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
/* eslint-disable no-var */ // `let` is not supported in very old browsers
|
||||
|
||||
(function () {
|
||||
if (!window.WeakMap || !window.Promise || typeof globalThis === "undefined") {
|
||||
if (
|
||||
!window.WeakMap ||
|
||||
!window.Promise ||
|
||||
typeof globalThis === "undefined" ||
|
||||
!String.prototype.replaceAll ||
|
||||
!CSS.supports ||
|
||||
!CSS.supports("aspect-ratio: 1")
|
||||
) {
|
||||
window.unsupportedBrowser = true;
|
||||
} else {
|
||||
// Some implementations of `WeakMap.prototype.has` do not accept false
|
||||
|
||||
@ -77,6 +77,8 @@ acceptance("Category Edit", function (needs) {
|
||||
test("Editing required tag groups", async function (assert) {
|
||||
await visit("/c/bug/edit/tags");
|
||||
|
||||
assert.ok(exists(".minimum-required-tags"));
|
||||
|
||||
assert.ok(exists(".required-tag-groups"));
|
||||
assert.strictEqual(count(".required-tag-group-row"), 0);
|
||||
|
||||
|
||||
@ -1269,7 +1269,7 @@ acceptance("Composer - Default category", function (needs) {
|
||||
name: "General",
|
||||
slug: "general",
|
||||
permission: 1,
|
||||
ltopic_template: null,
|
||||
topic_template: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
@ -1306,7 +1306,7 @@ acceptance("Composer - Uncategorized category", function (needs) {
|
||||
name: "General",
|
||||
slug: "general",
|
||||
permission: 1,
|
||||
ltopic_template: null,
|
||||
topic_template: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
@ -1337,7 +1337,7 @@ acceptance("Composer - default category not set", function (needs) {
|
||||
name: "General",
|
||||
slug: "general",
|
||||
permission: 1,
|
||||
ltopic_template: null,
|
||||
topic_template: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
|
||||
@ -39,7 +39,7 @@ acceptance("Group Members", function (needs) {
|
||||
needs.user();
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.put("/admin/groups/47/owners.json", () => {
|
||||
server.put("/groups/47/owners.json", () => {
|
||||
return helper.response({ success: true });
|
||||
});
|
||||
});
|
||||
@ -72,10 +72,9 @@ acceptance("Group Members", function (needs) {
|
||||
);
|
||||
});
|
||||
|
||||
test("Shows bulk actions", async function (assert) {
|
||||
test("Shows bulk actions as an admin user", async function (assert) {
|
||||
await visit("/g/discourse");
|
||||
|
||||
assert.ok(exists("button.bulk-select"));
|
||||
await click("button.bulk-select");
|
||||
|
||||
await click(queryAll("input.bulk-select")[0]);
|
||||
@ -83,7 +82,50 @@ acceptance("Group Members", function (needs) {
|
||||
|
||||
const memberDropdown = selectKit(".bulk-group-member-dropdown");
|
||||
await memberDropdown.expand();
|
||||
await memberDropdown.selectRowByValue("makeOwners");
|
||||
|
||||
assert.ok(
|
||||
exists('[data-value="removeMembers"]'),
|
||||
"it includes remove member option"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists('[data-value="makeOwners"]'),
|
||||
"it includes make owners option"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists('[data-value="setPrimary"]'),
|
||||
"it includes set primary option"
|
||||
);
|
||||
});
|
||||
|
||||
test("Shows bulk actions as a group owner", async function (assert) {
|
||||
updateCurrentUser({ moderator: false, admin: false });
|
||||
|
||||
await visit("/g/discourse");
|
||||
|
||||
await click("button.bulk-select");
|
||||
|
||||
await click(queryAll("input.bulk-select")[0]);
|
||||
await click(queryAll("input.bulk-select")[1]);
|
||||
|
||||
const memberDropdown = selectKit(".bulk-group-member-dropdown");
|
||||
await memberDropdown.expand();
|
||||
|
||||
assert.ok(
|
||||
exists('[data-value="removeMembers"]'),
|
||||
"it includes remove member option"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists('[data-value="makeOwners"]'),
|
||||
"it includes make owners option"
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists('[data-value="setPrimary"]'),
|
||||
"it does not include set primary (staff only) option"
|
||||
);
|
||||
});
|
||||
|
||||
test("Bulk actions - Menu, Select all and Clear all buttons", async function (assert) {
|
||||
|
||||
@ -73,7 +73,7 @@ acceptance("Search - Anonymous", function (needs) {
|
||||
query(
|
||||
".search-menu .results ul.search-menu-initial-options li:first-child .search-item-slug"
|
||||
).innerText.trim(),
|
||||
`dev ${I18n.t("search.in_topics_posts")}`,
|
||||
`dev${I18n.t("search.in_topics_posts")}`,
|
||||
"shows topic search as first dropdown item"
|
||||
);
|
||||
|
||||
@ -757,6 +757,47 @@ acceptance("Search - assistant", function (needs) {
|
||||
return helper.response(searchFixtures["search/query"]);
|
||||
});
|
||||
|
||||
server.get("/tag/dev/notifications", () => {
|
||||
return helper.response({
|
||||
tag_notification: { id: "dev", notification_level: 2 },
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/tags/c/bug/1/dev/l/latest.json", () => {
|
||||
return helper.response({
|
||||
users: [],
|
||||
primary_groups: [],
|
||||
topic_list: {
|
||||
can_create_topic: true,
|
||||
draft: null,
|
||||
draft_key: "new_topic",
|
||||
draft_sequence: 1,
|
||||
per_page: 30,
|
||||
tags: [
|
||||
{
|
||||
id: 1,
|
||||
name: "dev",
|
||||
topic_count: 1,
|
||||
},
|
||||
],
|
||||
topics: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/tags/intersection/dev/foo.json", () => {
|
||||
return helper.response({
|
||||
topic_list: {
|
||||
can_create_topic: true,
|
||||
draft: null,
|
||||
draft_key: "new_topic",
|
||||
draft_sequence: 1,
|
||||
per_page: 30,
|
||||
topics: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/u/search/users", () => {
|
||||
return helper.response({
|
||||
users: [
|
||||
@ -810,13 +851,92 @@ acceptance("Search - assistant", function (needs) {
|
||||
query(
|
||||
".search-menu .results ul.search-menu-assistant .search-item-prefix"
|
||||
).innerText,
|
||||
"sam "
|
||||
"sam"
|
||||
);
|
||||
|
||||
await click(firstCategory);
|
||||
assert.strictEqual(query("#search-term").value, `sam #${firstResultSlug}`);
|
||||
});
|
||||
|
||||
test("Shows category / tag combination shortcut when both are present", async function (assert) {
|
||||
await visit("/tags/c/bug/dev");
|
||||
await click("#search-button");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .category-name")
|
||||
.innerText,
|
||||
"bug",
|
||||
"Category is displayed"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .search-item-tag")
|
||||
.innerText,
|
||||
"dev",
|
||||
"Tag is displayed"
|
||||
);
|
||||
});
|
||||
|
||||
test("Updates tag / category combination search suggestion when typing", async function (assert) {
|
||||
await visit("/tags/c/bug/dev");
|
||||
await click("#search-button");
|
||||
await fillIn("#search-term", "foo bar");
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".search-menu .results ul.search-menu-assistant .search-item-prefix"
|
||||
).innerText,
|
||||
"foo bar",
|
||||
"Input is applied to search query"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .category-name")
|
||||
.innerText,
|
||||
"bug"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .search-item-tag")
|
||||
.innerText,
|
||||
"dev",
|
||||
"Tag is displayed"
|
||||
);
|
||||
});
|
||||
|
||||
test("Shows tag combination shortcut when visiting tag intersection", async function (assert) {
|
||||
await visit("/tags/intersection/dev/foo");
|
||||
await click("#search-button");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .search-item-tag")
|
||||
.innerText,
|
||||
"tags:dev+foo",
|
||||
"Tags are displayed"
|
||||
);
|
||||
});
|
||||
|
||||
test("Updates tag intersection search suggestion when typing", async function (assert) {
|
||||
await visit("/tags/intersection/dev/foo");
|
||||
await click("#search-button");
|
||||
await fillIn("#search-term", "foo bar");
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".search-menu .results ul.search-menu-assistant .search-item-prefix"
|
||||
).innerText,
|
||||
"foo bar",
|
||||
"Input is applied to search query"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-menu .results ul.search-menu-assistant .search-item-tag")
|
||||
.innerText,
|
||||
"tags:dev+foo",
|
||||
"Tags are displayed"
|
||||
);
|
||||
});
|
||||
|
||||
test("shows in: shortcuts", async function (assert) {
|
||||
await visit("/");
|
||||
await click("#search-button");
|
||||
|
||||
@ -346,17 +346,31 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
await publishUnreadToMessageBus({ topicId: 1 });
|
||||
await publishNewToMessageBus({ topicId: 2 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(".user-nav__messages-new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".user-nav__messages-unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("incoming new messages while viewing new", async function (assert) {
|
||||
@ -364,11 +378,19 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
|
||||
await publishNewToMessageBus({ topicId: 1 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
|
||||
assert.ok(exists(".show-mores"), "displays the topic incoming info");
|
||||
});
|
||||
@ -378,11 +400,19 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
|
||||
await publishUnreadToMessageBus();
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
|
||||
assert.ok(exists(".show-mores"), "displays the topic incoming info");
|
||||
});
|
||||
@ -393,33 +423,65 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
await publishUnreadToMessageBus({ groupIds: [14], topicId: 1 });
|
||||
await publishNewToMessageBus({ groupIds: [14], topicId: 2 });
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".messages-nav .user-nav__messages-group-unread"
|
||||
).innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-group-new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.ok(exists(".show-mores"), "displays the topic incoming info");
|
||||
assert.ok(exists(".show-mores"), "displays the topic incoming info");
|
||||
|
||||
await visit("/u/charlie/messages/unread");
|
||||
await visit("/u/charlie/messages/unread");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new_with_count", { count: 1 }),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.ok(exists(".show-mores"), "displays the topic incoming info");
|
||||
|
||||
await visit("/u/charlie/messages/unread");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("incoming messages is not tracked on non user messages route", async function (assert) {
|
||||
@ -452,11 +514,19 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
await click(".btn.dismiss-read");
|
||||
await click("#dismiss-read-confirm");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(".user-nav__messages-unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.unread").innerText.trim(),
|
||||
I18n.t("user.messages.unread"),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
count(".topic-list-item"),
|
||||
@ -518,11 +588,19 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
|
||||
await click(".btn.dismiss-read");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav .user-nav__messages-new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
} else {
|
||||
assert.strictEqual(
|
||||
query(".messages-nav li a.new").innerText.trim(),
|
||||
I18n.t("user.messages.new"),
|
||||
"displays the right count"
|
||||
);
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
count(".topic-list-item"),
|
||||
@ -701,7 +779,11 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
"User personal inbox is selected in dropdown"
|
||||
);
|
||||
|
||||
await click(".messages-sent");
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
await click(".user-nav__messages-sent");
|
||||
} else {
|
||||
await click(".messages-sent");
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
messagesDropdown.header().name(),
|
||||
@ -724,7 +806,11 @@ function testUserPrivateMessagesWithGroupMessages(needs, customUserProps) {
|
||||
"Group inbox is selected in dropdown"
|
||||
);
|
||||
|
||||
await click(".messages-group-new");
|
||||
if (customUserProps?.redesigned_user_page_nav_enabled) {
|
||||
await click(".user-nav__messages-group-new");
|
||||
} else {
|
||||
await click(".messages-group-new");
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
messagesDropdown.header().name(),
|
||||
|
||||
@ -393,6 +393,24 @@ module("Integration | Component | select-kit/single-select", function (hooks) {
|
||||
);
|
||||
});
|
||||
|
||||
test("row index", async function (assert) {
|
||||
this.setProperties({
|
||||
content: [
|
||||
{ id: 1, name: "john" },
|
||||
{ id: 2, name: "jane" },
|
||||
],
|
||||
value: null,
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`<SingleSelect @value={{this.value}} @content={{this.content}} />`
|
||||
);
|
||||
await this.subject.expand();
|
||||
|
||||
assert.dom('.select-kit-row[data-index="0"][data-value="1"]').exists();
|
||||
assert.dom('.select-kit-row[data-index="1"][data-value="2"]').exists();
|
||||
});
|
||||
|
||||
test("options.verticalOffset", async function (assert) {
|
||||
setDefaultState(this, { verticalOffset: -50 });
|
||||
await render(hbs`
|
||||
@ -411,4 +429,17 @@ module("Integration | Component | select-kit/single-select", function (hooks) {
|
||||
|
||||
assert.ok(header.bottom > body.top, "it correctly offsets the body");
|
||||
});
|
||||
|
||||
test("options.expandedOnInsert", async function (assert) {
|
||||
setDefaultState(this);
|
||||
await render(hbs`
|
||||
<SingleSelect
|
||||
@value={{this.value}}
|
||||
@content={{this.content}}
|
||||
@options={{hash expandedOnInsert=true}}
|
||||
/>
|
||||
`);
|
||||
|
||||
assert.dom(".single-select.is-expanded").exists();
|
||||
});
|
||||
});
|
||||
|
||||
@ -32,5 +32,21 @@ module(
|
||||
const contentDiv = query(CONTENT_DIV_SELECTOR);
|
||||
assert.strictEqual(contentDiv.innerText, '"quote"');
|
||||
});
|
||||
|
||||
test("Renders the notification content with no username when username is not present", async function (assert) {
|
||||
this.set("args", {
|
||||
content: "content",
|
||||
username: undefined,
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`<MountWidget @widget="quick-access-item" @args={{this.args}} />`
|
||||
);
|
||||
|
||||
const contentDiv = query(CONTENT_DIV_SELECTOR);
|
||||
const usernameSpan = query("li a div span");
|
||||
assert.strictEqual(contentDiv.innerText, "content");
|
||||
assert.strictEqual(usernameSpan.innerText, "");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { module, test } from "qunit";
|
||||
import { module, test, todo } from "qunit";
|
||||
import EmberObject from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
@ -87,4 +87,33 @@ module("Unit | Utility | plugin-api", function (hooks) {
|
||||
assert.strictEqual(thingy.keep, "hey!");
|
||||
assert.strictEqual(thingy.prop, "g'day");
|
||||
});
|
||||
|
||||
todo("modifyClass works with getters", function (assert) {
|
||||
let Base = EmberObject.extend({
|
||||
get foo() {
|
||||
throw new Error("base getter called");
|
||||
},
|
||||
});
|
||||
|
||||
getOwner(this).register("test-class:main", Base, {
|
||||
instantiate: false,
|
||||
});
|
||||
|
||||
// Performing this lookup triggers `factory._onLookup`. In DEBUG builds, that invokes injectedPropertyAssertion()
|
||||
// https://github.com/emberjs/ember.js/blob/36505f1b42/packages/%40ember/-internals/runtime/lib/system/core_object.js#L1144-L1163
|
||||
// Which in turn invokes `factory.proto()`.
|
||||
// This puts things in a state which will trigger https://github.com/emberjs/ember.js/issues/18860 when a native getter is overridden.
|
||||
withPluginApi("1.1.0", (api) => {
|
||||
api.modifyClass("test-class:main", {
|
||||
get foo() {
|
||||
return "modified getter";
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const obj = Base.create();
|
||||
assert.true(true, "no error thrown while merging mixin with getter");
|
||||
|
||||
assert.strictEqual(obj.foo, "modified getter", "returns correct result");
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user