Version bump
This commit is contained in:
commit
6777a465ea
@ -10,8 +10,8 @@ lib/highlight_js/
|
||||
plugins/**/lib/javascripts/locale
|
||||
public/
|
||||
vendor/
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/fixtures
|
||||
test/javascripts/helpers/assertions.js
|
||||
app/assets/javascripts/discourse/tests/test_helper.js
|
||||
app/assets/javascripts/discourse/tests/fixtures
|
||||
app/assets/javascripts/discourse/tests/helpers/assertions.js
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
@ -2,5 +2,12 @@
|
||||
"extends": "eslint-config-discourse",
|
||||
"rules": {
|
||||
"discourse-ember/global-ember": 2
|
||||
},
|
||||
"globals": {
|
||||
"moduleFor": "off",
|
||||
"moduleForComponent": "off",
|
||||
"testStart": "off",
|
||||
"testDone": "off",
|
||||
"sinon": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,3 +43,9 @@ bf88410126f73aab47b7e694e3c5b46453cec1b6
|
||||
|
||||
# REFACTOR: Support bundling our `admin` section as an ember addon
|
||||
ce3fe2f4c4ddf166949ee3cec3d9ecbf9108ab52
|
||||
|
||||
# REFACTOR: Move qunit tests to a different directory structure
|
||||
bc97c79a35d8acd283d4d8b79aa079bce9d127c6
|
||||
|
||||
# REFACTOR: Move javascript tests inside discourse app
|
||||
23f24bfb510edb25b18b6a0d5485270c88df9b24
|
||||
|
||||
21
.github/workflows/ci.yml
vendored
21
.github/workflows/ci.yml
vendored
@ -91,9 +91,10 @@ jobs:
|
||||
gem install bundler -v 2.1.4 --no-doc
|
||||
bundle config deployment 'true'
|
||||
bundle config without 'development'
|
||||
bundle config path vendor/bundle
|
||||
|
||||
- name: Bundler cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v2
|
||||
id: bundler-cache
|
||||
with:
|
||||
path: vendor/bundle
|
||||
@ -109,7 +110,7 @@ jobs:
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v2
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir.outputs.dir }}
|
||||
@ -146,7 +147,7 @@ jobs:
|
||||
|
||||
- name: ESLint (core)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern app/assets/javascripts test/javascripts
|
||||
run: yarn eslint --ext .js,.js.es6 --no-error-on-unmatched-pattern app/assets/javascripts
|
||||
|
||||
- name: ESLint (core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
@ -163,7 +164,6 @@ jobs:
|
||||
yarn prettier --list-different \
|
||||
"app/assets/stylesheets/**/*.scss" \
|
||||
"app/assets/javascripts/**/*.{js,es6}" \
|
||||
"test/javascripts/**/*.{js,es6}" \
|
||||
"plugins/**/assets/stylesheets/**/*.scss" \
|
||||
"plugins/**/assets/javascripts/**/*.{js,es6}"
|
||||
|
||||
@ -175,6 +175,19 @@ jobs:
|
||||
"plugins/**/assets/stylesheets/**/*.scss" \
|
||||
"plugins/**/assets/javascripts/**/*.{js,es6}"
|
||||
|
||||
- name: Ember template lint (core and core plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: |
|
||||
yarn ember-template-lint \
|
||||
app/assets/javascripts \
|
||||
plugins/**/assets/javascripts
|
||||
|
||||
- name: Ember template lint (all plugins)
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'PLUGINS'
|
||||
run: |
|
||||
yarn ember-template-lint \
|
||||
plugins/**/assets/javascripts
|
||||
|
||||
- name: Core English locale
|
||||
if: env.BUILD_TYPE == 'LINT' && env.TARGET == 'CORE'
|
||||
run: bundle exec ruby script/i18n_lint.rb "config/**/locales/{client,server}.en.yml"
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -53,6 +53,7 @@ bootsnap-compile-cache/
|
||||
!/plugins/discourse-nginx-performance-report
|
||||
!/plugins/discourse-narrative-bot
|
||||
!/plugins/discourse-presence
|
||||
!/plugins/styleguide
|
||||
!/plugins/discourse-local-dates
|
||||
/plugins/*/auto_generated/
|
||||
|
||||
|
||||
@ -18,8 +18,9 @@ lib/highlight_js/
|
||||
plugins/**/lib/javascripts/locale
|
||||
public/
|
||||
vendor/
|
||||
test/javascripts/test_helper.js
|
||||
test/javascripts/fixtures
|
||||
test/javascripts/helpers/assertions.js
|
||||
app/assets/javascripts/discourse/tests/test_helper.js
|
||||
app/assets/javascripts/discourse/tests/fixtures
|
||||
app/assets/javascripts/discourse/tests/helpers/assertions.js
|
||||
node_modules/
|
||||
dist/
|
||||
**/*.rb
|
||||
|
||||
32
Gemfile.lock
32
Gemfile.lock
@ -66,7 +66,7 @@ GEM
|
||||
barber (0.12.2)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
execjs (>= 1.2, < 3)
|
||||
better_errors (2.8.1)
|
||||
better_errors (2.8.3)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
@ -105,7 +105,7 @@ GEM
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
discourse-ember-source (3.12.2.2)
|
||||
discourse-fonts (0.0.3)
|
||||
discourse-fonts (0.0.5)
|
||||
discourse_image_optim (0.26.2)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
fspath (~> 3.0)
|
||||
@ -180,14 +180,14 @@ GEM
|
||||
mini_mime (>= 0.1.1)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (0.9.14)
|
||||
message_bus (3.3.2)
|
||||
message_bus (3.3.4)
|
||||
rack (>= 1.1.3)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
mini_racer (0.3.1)
|
||||
libv8 (~> 8.4.255)
|
||||
mini_scheduler (0.12.2)
|
||||
mini_scheduler (0.12.3)
|
||||
sidekiq
|
||||
mini_sql (0.3)
|
||||
mini_suffix (0.3.0)
|
||||
@ -249,7 +249,7 @@ GEM
|
||||
parallel (1.19.2)
|
||||
parallel_tests (3.3.0)
|
||||
parallel
|
||||
parser (2.7.1.5)
|
||||
parser (2.7.2.0)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.2.3)
|
||||
progress (3.5.2)
|
||||
@ -262,7 +262,7 @@ GEM
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.0.0)
|
||||
puma (5.0.2)
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
rack (2.2.3)
|
||||
@ -303,12 +303,12 @@ GEM
|
||||
redis (4.2.2)
|
||||
redis-namespace (1.8.0)
|
||||
redis (>= 3.0.4)
|
||||
regexp_parser (1.8.0)
|
||||
regexp_parser (1.8.2)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.4)
|
||||
rinku (2.0.6)
|
||||
rotp (6.1.0)
|
||||
rotp (6.2.0)
|
||||
rqrcode (1.1.2)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
@ -317,12 +317,12 @@ GEM
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.2)
|
||||
rspec-core (3.9.3)
|
||||
rspec-support (~> 3.9.3)
|
||||
rspec-expectations (3.9.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-html-matchers (0.9.2)
|
||||
rspec-html-matchers (0.9.4)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a, < 4)
|
||||
rspec-mocks (3.9.1)
|
||||
@ -342,16 +342,16 @@ GEM
|
||||
json-schema (~> 2.2)
|
||||
railties (>= 3.1, < 7.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (0.91.1)
|
||||
rubocop (0.93.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.7)
|
||||
regexp_parser (>= 1.8)
|
||||
rexml
|
||||
rubocop-ast (>= 0.4.0, < 1.0)
|
||||
rubocop-ast (>= 0.6.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (0.5.0)
|
||||
rubocop-ast (0.8.0)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.3.2)
|
||||
rubocop (>= 0.69.0)
|
||||
@ -415,7 +415,7 @@ GEM
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.13.0)
|
||||
webmock (3.9.1)
|
||||
webmock (3.9.2)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
import Controller from "@ember/controller";
|
||||
import EmailLog from "admin/models/email-log";
|
||||
import EmberObject from "@ember/object";
|
||||
|
||||
export default Controller.extend({
|
||||
loading: false,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.set("filter", EmberObject.create());
|
||||
},
|
||||
loadLogs(sourceModel, loadMore) {
|
||||
if ((loadMore && this.loading) || this.get("model.allLoaded")) {
|
||||
return;
|
||||
@ -13,8 +18,14 @@ export default Controller.extend({
|
||||
|
||||
sourceModel = sourceModel || EmailLog;
|
||||
|
||||
let args = {};
|
||||
Object.keys(this.filter).forEach((k) => {
|
||||
if (this.filter[k]) {
|
||||
args[k] = this.filter[k];
|
||||
}
|
||||
});
|
||||
return sourceModel
|
||||
.findAll(this.filter, loadMore ? this.get("model.length") : null)
|
||||
.findAll(args, loadMore ? this.get("model.length") : null)
|
||||
.then((logs) => {
|
||||
if (this.model && loadMore && logs.length < 50) {
|
||||
this.model.set("allLoaded", true);
|
||||
|
||||
@ -7,7 +7,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
@observes("model.value")
|
||||
_setup() {
|
||||
const value = this.get("model.value");
|
||||
this.set("images", value && value.length ? value.split("\n") : []);
|
||||
this.set("images", value && value.length ? value.split("|") : []);
|
||||
},
|
||||
|
||||
actions: {
|
||||
@ -20,7 +20,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
},
|
||||
|
||||
close() {
|
||||
this.save(this.images.join("\n"));
|
||||
this.save(this.images.join("|"));
|
||||
this.send("closeModal");
|
||||
},
|
||||
},
|
||||
|
||||
@ -14,7 +14,7 @@ export default Mixin.create({
|
||||
|
||||
@discourseComputed("period")
|
||||
startDate(period) {
|
||||
let fullDay = moment().locale("en").utc().subtract(1, "day");
|
||||
let fullDay = moment().locale("en").utc().endOf("day");
|
||||
|
||||
switch (period) {
|
||||
case "yearly":
|
||||
@ -24,7 +24,7 @@ export default Mixin.create({
|
||||
return fullDay.subtract(3, "month").startOf("day");
|
||||
break;
|
||||
case "weekly":
|
||||
return fullDay.subtract(1, "week").startOf("day");
|
||||
return fullDay.subtract(6, "days").startOf("day");
|
||||
break;
|
||||
case "monthly":
|
||||
return fullDay.subtract(1, "month").startOf("day");
|
||||
@ -46,7 +46,7 @@ export default Mixin.create({
|
||||
|
||||
@discourseComputed()
|
||||
endDate() {
|
||||
return moment().locale("en").utc().subtract(1, "day").endOf("day");
|
||||
return moment().locale("en").utc().endOf("day");
|
||||
},
|
||||
|
||||
@discourseComputed()
|
||||
|
||||
@ -139,8 +139,8 @@ const AdminUser = User.extend({
|
||||
bootbox.hideAll();
|
||||
let error;
|
||||
AdminUser.find(user.get("id")).then((u) => user.setProperties(u));
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
error = e.responseJSON.errors[0];
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
error = e.jqXHR.responseJSON.errors[0];
|
||||
}
|
||||
error = error || I18n.t("admin.user.delete_posts_failed");
|
||||
bootbox.alert(error);
|
||||
@ -236,8 +236,8 @@ const AdminUser = User.extend({
|
||||
.then(() => window.location.reload())
|
||||
.catch((e) => {
|
||||
let error;
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
error = e.responseJSON.errors[0];
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
error = e.jqXHR.responseJSON.errors[0];
|
||||
}
|
||||
error =
|
||||
error ||
|
||||
@ -260,8 +260,8 @@ const AdminUser = User.extend({
|
||||
.then(() => window.location.reload())
|
||||
.catch((e) => {
|
||||
let error;
|
||||
if (e.responseJSON && e.responseJSON.errors) {
|
||||
error = e.responseJSON.errors[0];
|
||||
if (e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors) {
|
||||
error = e.jqXHR.responseJSON.errors[0];
|
||||
}
|
||||
error =
|
||||
error ||
|
||||
|
||||
@ -8,6 +8,6 @@ export default DiscourseRoute.extend({
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.set("model", model);
|
||||
controller.set("filter", { status: this.status });
|
||||
controller.set("filter.status", this.status);
|
||||
},
|
||||
});
|
||||
|
||||
@ -55,26 +55,26 @@
|
||||
|
||||
<div class="metadata control-unit">
|
||||
{{#if model.remote_theme}}
|
||||
{{#if model.remote_theme.remote_url}}
|
||||
{{#if sourceIsHttp}}
|
||||
<a class="remote-url" href={{remoteThemeLink}}>{{i18n "admin.customize.theme.source_url"}}{{d-icon "link"}}</a>
|
||||
{{else}}
|
||||
<div class="remote-url"><code>{{model.remote_theme.remote_url}}</code></div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if model.remote_theme.about_url}}
|
||||
<a class="url about-url" href={{model.remote_theme.about_url}}>{{i18n "admin.customize.theme.about_theme"}}{{d-icon "link"}}</a>
|
||||
{{/if}}
|
||||
{{#if model.remote_theme.license_url}}
|
||||
<a class="url license-url" href={{model.remote_theme.license_url}}>{{i18n "admin.customize.theme.license"}}{{d-icon "link"}}</a>
|
||||
{{#if model.remote_theme.remote_url}}
|
||||
{{#if sourceIsHttp}}
|
||||
<a class="remote-url" href={{remoteThemeLink}}>{{i18n "admin.customize.theme.source_url"}}{{d-icon "link"}}</a>
|
||||
{{else}}
|
||||
<div class="remote-url"><code>{{model.remote_theme.remote_url}}</code></div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if model.remote_theme.about_url}}
|
||||
<a class="url about-url" href={{model.remote_theme.about_url}}>{{i18n "admin.customize.theme.about_theme"}}{{d-icon "link"}}</a>
|
||||
{{/if}}
|
||||
{{#if model.remote_theme.license_url}}
|
||||
<a class="url license-url" href={{model.remote_theme.license_url}}>{{i18n "admin.customize.theme.license"}}{{d-icon "link"}}</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if model.description}}
|
||||
<span class="theme-description">{{model.description}}</span>
|
||||
{{/if}}
|
||||
{{#if model.description}}
|
||||
<span class="theme-description">{{model.description}}</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if model.remote_theme.authors}}<span class="authors"><span class="heading">{{i18n "admin.customize.theme.authors"}}</span> {{model.remote_theme.authors}}</span>{{/if}}
|
||||
{{#if model.remote_theme.theme_version}}<span class="version"><span class="heading">{{i18n "admin.customize.theme.version"}}</span> {{model.remote_theme.theme_version}}</span>{{/if}}
|
||||
{{#if model.remote_theme.authors}}<span class="authors"><span class="heading">{{i18n "admin.customize.theme.authors"}}</span> {{model.remote_theme.authors}}</span>{{/if}}
|
||||
{{#if model.remote_theme.theme_version}}<span class="version"><span class="heading">{{i18n "admin.customize.theme.version"}}</span> {{model.remote_theme.theme_version}}</span>{{/if}}
|
||||
|
||||
<div class="control-unit">
|
||||
{{#if model.remote_theme.is_git}}
|
||||
@ -119,16 +119,15 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<span class="heading">{{i18n "admin.customize.theme.creator"}}</span>
|
||||
<span>
|
||||
{{#user-link user=model.user}}
|
||||
{{format-username model.user.username}}
|
||||
{{/user-link}}
|
||||
</span>
|
||||
<span class="heading">{{i18n "admin.customize.theme.creator"}}</span>
|
||||
<span>
|
||||
{{#user-link user=model.user}}
|
||||
{{format-username model.user.username}}
|
||||
{{/user-link}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
||||
{{#unless model.component}}
|
||||
<div class="control-unit">
|
||||
{{inline-edit-checkbox action=(action "applyDefault") labelKey="admin.customize.theme.is_default" checked=model.default}}
|
||||
@ -136,7 +135,6 @@
|
||||
</div>
|
||||
{{/unless}}
|
||||
|
||||
|
||||
{{#unless model.component}}
|
||||
{{#d-section class="form-horizontal theme settings control-unit"}}
|
||||
<div class="row setting">
|
||||
@ -253,7 +251,7 @@
|
||||
<div class="mini-title">{{i18n "admin.customize.theme.theme_settings"}}</div>
|
||||
{{#d-section class="form-horizontal theme settings control-unit"}}
|
||||
{{#each settings as |setting|}}
|
||||
{{theme-setting-editor setting=setting model=model class="theme-setting"}}
|
||||
{{theme-setting-editor setting=setting model=model class="theme-setting control-unit"}}
|
||||
{{/each}}
|
||||
{{/d-section}}
|
||||
</div>
|
||||
@ -271,7 +269,7 @@
|
||||
{{/if}}
|
||||
|
||||
<div class="theme-controls">
|
||||
|
||||
|
||||
<a href={{previewUrl}} title={{i18n "admin.customize.explain_preview"}} rel="noopener noreferrer" target="_blank" class="btn btn-default">{{d-icon "desktop"}}{{i18n "admin.customize.theme.preview"}}</a>
|
||||
<a class="btn btn-default export" rel="noopener noreferrer" target="_blank" href={{downloadUrl}}>{{d-icon "download"}} {{i18n "admin.export_json.button_text"}}</a>
|
||||
|
||||
|
||||
@ -10,7 +10,11 @@
|
||||
{{i18n "admin.dashboard.community_health"}}
|
||||
</a>
|
||||
</h2>
|
||||
{{period-chooser period=period action=(action "changePeriod") content=availablePeriods fullDay=true}}
|
||||
{{period-chooser
|
||||
period=period
|
||||
action=(action "changePeriod")
|
||||
content=availablePeriods
|
||||
fullDay=false}}
|
||||
</div>
|
||||
|
||||
<div class="section-body">
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
period=period
|
||||
action=(action "changePeriod")
|
||||
content=availablePeriods
|
||||
fullDay=true}}
|
||||
fullDay=false}}
|
||||
</div>
|
||||
|
||||
<div class="section-body">
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { moduleForComponent } from "ember-qunit";
|
||||
import EmberObject from "@ember/object";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import componentTest from "helpers/component-test";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import componentTest from "discourse/tests/helpers/component-test";
|
||||
|
||||
moduleForComponent("group-list", { integration: true });
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { moduleForComponent } from "ember-qunit";
|
||||
import I18n from "I18n";
|
||||
import componentTest from "helpers/component-test";
|
||||
import componentTest from "discourse/tests/helpers/component-test";
|
||||
import Theme from "admin/models/theme";
|
||||
|
||||
moduleForComponent("themes-list-item", { integration: true });
|
||||
@ -1,5 +1,6 @@
|
||||
import { moduleForComponent } from "ember-qunit";
|
||||
import I18n from "I18n";
|
||||
import componentTest from "helpers/component-test";
|
||||
import componentTest from "discourse/tests/helpers/component-test";
|
||||
import Theme, { THEMES, COMPONENTS } from "admin/models/theme";
|
||||
|
||||
moduleForComponent("themes-list", { integration: true });
|
||||
@ -1,3 +1,5 @@
|
||||
import { moduleFor } from "ember-qunit";
|
||||
import { test } from "qunit";
|
||||
import { mapRoutes } from "discourse/mapping-router";
|
||||
import Theme from "admin/models/theme";
|
||||
|
||||
@ -8,7 +10,7 @@ moduleFor("controller:admin-customize-themes-show", {
|
||||
needs: ["controller:adminUser"],
|
||||
});
|
||||
|
||||
QUnit.test("can display source url for remote themes", function (assert) {
|
||||
test("can display source url for remote themes", function (assert) {
|
||||
const repoUrl = "https://github.com/discourse/discourse-brand-header.git";
|
||||
const remoteTheme = Theme.create({
|
||||
id: 2,
|
||||
@ -29,9 +31,7 @@ QUnit.test("can display source url for remote themes", function (assert) {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("can display source url for remote theme branches", function (
|
||||
assert
|
||||
) {
|
||||
test("can display source url for remote theme branches", function (assert) {
|
||||
const remoteTheme = Theme.create({
|
||||
id: 2,
|
||||
default: true,
|
||||
@ -1,3 +1,5 @@
|
||||
import { moduleFor } from "ember-qunit";
|
||||
import { test } from "qunit";
|
||||
import { mapRoutes } from "discourse/mapping-router";
|
||||
import Theme from "admin/models/theme";
|
||||
|
||||
@ -8,7 +10,7 @@ moduleFor("controller:admin-customize-themes", {
|
||||
needs: ["controller:adminUser"],
|
||||
});
|
||||
|
||||
QUnit.test("can list themes correctly", function (assert) {
|
||||
test("can list themes correctly", function (assert) {
|
||||
const defaultTheme = Theme.create({ id: 2, default: true, name: "default" });
|
||||
const userTheme = Theme.create({
|
||||
id: 3,
|
||||
@ -1,3 +1,5 @@
|
||||
import { moduleFor } from "ember-qunit";
|
||||
import { test } from "qunit";
|
||||
import Badge from "discourse/models/badge";
|
||||
import { mapRoutes } from "discourse/mapping-router";
|
||||
|
||||
@ -8,7 +10,7 @@ moduleFor("controller:admin-user-badges", {
|
||||
needs: ["controller:adminUser"],
|
||||
});
|
||||
|
||||
QUnit.test("grantableBadges", function (assert) {
|
||||
test("grantableBadges", function (assert) {
|
||||
const badgeFirst = Badge.create({
|
||||
id: 3,
|
||||
name: "A Badge",
|
||||
@ -1,8 +1,9 @@
|
||||
import { test, module } from "qunit";
|
||||
import Theme from "admin/models/theme";
|
||||
|
||||
QUnit.module("model:theme");
|
||||
module("model:theme");
|
||||
|
||||
QUnit.test("can add an upload correctly", function (assert) {
|
||||
test("can add an upload correctly", function (assert) {
|
||||
let theme = Theme.create();
|
||||
|
||||
assert.equal(
|
||||
@ -7,6 +7,11 @@ var define, requirejs;
|
||||
"discourse-common/utils/decorators",
|
||||
"discourse/lib/raw-templates": "discourse-common/lib/raw-templates",
|
||||
"preload-store": "discourse/lib/preload-store",
|
||||
"fixtures/user_fixtures": "discourse/tests/fixtures/user-fixtures",
|
||||
};
|
||||
var ALIAS_PREPEND = {
|
||||
fixtures: "discourse/tests/",
|
||||
helpers: "discourse/tests/",
|
||||
};
|
||||
|
||||
// In future versions of ember we don't need this
|
||||
@ -141,6 +146,9 @@ var define, requirejs;
|
||||
"@ember/object/internals": {
|
||||
guidFor: Ember.guidFor,
|
||||
},
|
||||
"@ember/test-helpers": {
|
||||
setResolver: window.setResolver,
|
||||
},
|
||||
I18n: {
|
||||
// eslint-disable-next-line
|
||||
default: I18n,
|
||||
@ -301,9 +309,13 @@ var define, requirejs;
|
||||
function transformForAliases(name) {
|
||||
var alias = ALIASES[name];
|
||||
if (!alias) {
|
||||
return name;
|
||||
var segment = name.split("/")[0];
|
||||
var prepend = ALIAS_PREPEND[segment];
|
||||
if (!prepend) {
|
||||
return name;
|
||||
}
|
||||
alias = prepend + name;
|
||||
}
|
||||
|
||||
deprecatedModule(name, alias);
|
||||
return alias;
|
||||
}
|
||||
|
||||
@ -94,6 +94,8 @@ export default Component.extend({
|
||||
|
||||
if (action) {
|
||||
if (typeof action === "string") {
|
||||
// Note: This is deprecated in new Embers and needs to be removed in the future.
|
||||
// There is already a warning in the console.
|
||||
this.sendAction("action", this.actionParam);
|
||||
} else if (typeof action === "object" && action.value) {
|
||||
action.value(this.actionParam);
|
||||
|
||||
@ -2,6 +2,8 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
hide: false,
|
||||
|
||||
@discourseComputed("banner.html")
|
||||
content(bannerHtml) {
|
||||
const $div = $("<div>");
|
||||
@ -30,7 +32,7 @@ export default Component.extend({
|
||||
if (this.user) {
|
||||
this.user.dismissBanner(this.get("banner.key"));
|
||||
} else {
|
||||
this.set("visible", false);
|
||||
this.set("hide", true);
|
||||
this.keyValueStore.set({
|
||||
key: "dismissed_banner_key",
|
||||
value: this.get("banner.key"),
|
||||
|
||||
@ -5,10 +5,10 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||
export default Component.extend({
|
||||
tagName: "span",
|
||||
|
||||
@discourseComputed("text")
|
||||
@discourseComputed("text", "textParams")
|
||||
translatedText(text) {
|
||||
if (text) {
|
||||
return I18n.t(text);
|
||||
return I18n.t(...arguments);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -19,6 +19,12 @@ function getQuoteTitle(element) {
|
||||
if (!titleEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleLink = titleEl.querySelector("a:not(.back)");
|
||||
if (titleLink) {
|
||||
return titleLink.textContent.trim();
|
||||
}
|
||||
|
||||
return titleEl.textContent.trim().replace(/:$/, "");
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,8 @@ const REGEXP_CATEGORY_PREFIX = /^(category:|#)/gi;
|
||||
const REGEXP_TAGS_PREFIX = /^(tags?:|#(?=[a-z0-9\-]+::tag))/gi;
|
||||
const REGEXP_IN_PREFIX = /^(in|with):/gi;
|
||||
const REGEXP_STATUS_PREFIX = /^status:/gi;
|
||||
const REGEXP_MIN_POST_COUNT_PREFIX = /^min_post_count:/gi;
|
||||
const REGEXP_MIN_POSTS_PREFIX = /^min_posts:/gi;
|
||||
const REGEXP_MAX_POSTS_PREFIX = /^max_posts:/gi;
|
||||
const REGEXP_MIN_VIEWS_PREFIX = /^min_views:/gi;
|
||||
const REGEXP_MAX_VIEWS_PREFIX = /^max_views:/gi;
|
||||
const REGEXP_POST_TIME_PREFIX = /^(before|after):/gi;
|
||||
@ -94,7 +95,8 @@ export default Component.extend({
|
||||
all_tags: false,
|
||||
},
|
||||
status: null,
|
||||
min_post_count: null,
|
||||
min_posts: null,
|
||||
max_posts: null,
|
||||
min_views: null,
|
||||
max_views: null,
|
||||
time: {
|
||||
@ -162,8 +164,13 @@ export default Component.extend({
|
||||
this.setSearchedTermValueForPostTime();
|
||||
|
||||
this.setSearchedTermValue(
|
||||
"searchedTerms.min_post_count",
|
||||
REGEXP_MIN_POST_COUNT_PREFIX
|
||||
"searchedTerms.min_posts",
|
||||
REGEXP_MIN_POSTS_PREFIX
|
||||
);
|
||||
|
||||
this.setSearchedTermValue(
|
||||
"searchedTerms.max_posts",
|
||||
REGEXP_MAX_POSTS_PREFIX
|
||||
);
|
||||
|
||||
this.setSearchedTermValue(
|
||||
@ -355,10 +362,16 @@ export default Component.extend({
|
||||
|
||||
@action
|
||||
onChangeSearchTermMinPostCount(value) {
|
||||
this.set("searchedTerms.min_post_count", value.length ? value : null);
|
||||
this.set("searchedTerms.min_posts", value.length ? value : null);
|
||||
this._updateSearchTermForMinPostCount();
|
||||
},
|
||||
|
||||
@action
|
||||
onChangeSearchTermMaxPostCount(value) {
|
||||
this.set("searchedTerms.max_posts", value.length ? value : null);
|
||||
this._updateSearchTermForMaxPostCount();
|
||||
},
|
||||
|
||||
@action
|
||||
onChangeSearchTermMinViews(value) {
|
||||
this.set("searchedTerms.min_views", value.length ? value : null);
|
||||
@ -632,18 +645,40 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
_updateSearchTermForMinPostCount() {
|
||||
const match = this.filterBlocks(REGEXP_MIN_POST_COUNT_PREFIX);
|
||||
const postsCountFilter = this.get("searchedTerms.min_post_count");
|
||||
const match = this.filterBlocks(REGEXP_MIN_POSTS_PREFIX);
|
||||
const postsCountFilter = this.get("searchedTerms.min_posts");
|
||||
let searchTerm = this.searchTerm || "";
|
||||
|
||||
if (postsCountFilter) {
|
||||
if (match.length !== 0) {
|
||||
searchTerm = searchTerm.replace(
|
||||
match[0],
|
||||
`min_post_count:${postsCountFilter}`
|
||||
`min_posts:${postsCountFilter}`
|
||||
);
|
||||
} else {
|
||||
searchTerm += ` min_post_count:${postsCountFilter}`;
|
||||
searchTerm += ` min_posts:${postsCountFilter}`;
|
||||
}
|
||||
|
||||
this._updateSearchTerm(searchTerm);
|
||||
} else if (match.length !== 0) {
|
||||
searchTerm = searchTerm.replace(match[0], "");
|
||||
this._updateSearchTerm(searchTerm);
|
||||
}
|
||||
},
|
||||
|
||||
_updateSearchTermForMaxPostCount() {
|
||||
const match = this.filterBlocks(REGEXP_MAX_POSTS_PREFIX);
|
||||
const postsCountFilter = this.get("searchedTerms.max_posts");
|
||||
let searchTerm = this.searchTerm || "";
|
||||
|
||||
if (postsCountFilter) {
|
||||
if (match.length !== 0) {
|
||||
searchTerm = searchTerm.replace(
|
||||
match[0],
|
||||
`max_posts:${postsCountFilter}`
|
||||
);
|
||||
} else {
|
||||
searchTerm += ` max_posts:${postsCountFilter}`;
|
||||
}
|
||||
|
||||
this._updateSearchTerm(searchTerm);
|
||||
|
||||
@ -4,32 +4,109 @@ import { isEmpty } from "@ember/utils";
|
||||
import Component from "@ember/component";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
import Group from "discourse/models/group";
|
||||
import bootbox from "bootbox";
|
||||
|
||||
export default Component.extend(bufferedProperty("model"), {
|
||||
tagName: "",
|
||||
allGroups: null,
|
||||
|
||||
@discourseComputed("buffered.isSaving", "buffered.name", "buffered.tag_names")
|
||||
savingDisabled(isSaving, name, tagNames) {
|
||||
return isSaving || isEmpty(name) || isEmpty(tagNames);
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.setGroupOptions();
|
||||
},
|
||||
|
||||
setGroupOptions() {
|
||||
Group.findAll().then((groups) => {
|
||||
this.set("allGroups", groups);
|
||||
});
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"buffered.isSaving",
|
||||
"buffered.name",
|
||||
"buffered.tag_names",
|
||||
"buffered.permissions"
|
||||
)
|
||||
savingDisabled(isSaving, name, tagNames, permissions) {
|
||||
return (
|
||||
isSaving ||
|
||||
isEmpty(name) ||
|
||||
isEmpty(tagNames) ||
|
||||
(!this.everyoneSelected(permissions) &&
|
||||
isEmpty(this.selectedGroupNames(permissions)))
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed("buffered.permissions")
|
||||
showPrivateChooser(permissions) {
|
||||
if (!permissions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return permissions.everyone !== PermissionType.READONLY;
|
||||
},
|
||||
|
||||
@discourseComputed("buffered.permissions", "allGroups")
|
||||
selectedGroupIds(permissions, allGroups) {
|
||||
if (!permissions || !allGroups) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const selectedGroupNames = Object.keys(permissions);
|
||||
let groupIds = [];
|
||||
allGroups.forEach((group) => {
|
||||
if (selectedGroupNames.includes(group.name)) {
|
||||
groupIds.push(group.id);
|
||||
}
|
||||
});
|
||||
|
||||
return groupIds;
|
||||
},
|
||||
|
||||
everyoneSelected(permissions) {
|
||||
if (!permissions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return permissions.everyone === PermissionType.FULL;
|
||||
},
|
||||
|
||||
selectedGroupNames(permissions) {
|
||||
if (!permissions) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Object.keys(permissions).filter((name) => name !== "everyone");
|
||||
},
|
||||
|
||||
actions: {
|
||||
setPermissions(permissionName) {
|
||||
setPermissionsType(permissionName) {
|
||||
let updatedPermissions = Object.assign(
|
||||
{},
|
||||
this.buffered.get("permissions")
|
||||
);
|
||||
|
||||
if (permissionName === "private") {
|
||||
this.buffered.set("permissions", {
|
||||
staff: PermissionType.FULL,
|
||||
});
|
||||
delete updatedPermissions.everyone;
|
||||
} else if (permissionName === "visible") {
|
||||
this.buffered.set("permissions", {
|
||||
staff: PermissionType.FULL,
|
||||
everyone: PermissionType.READONLY,
|
||||
});
|
||||
updatedPermissions.everyone = PermissionType.READONLY;
|
||||
} else {
|
||||
this.buffered.set("permissions", {
|
||||
everyone: PermissionType.FULL,
|
||||
});
|
||||
updatedPermissions.everyone = PermissionType.FULL;
|
||||
}
|
||||
|
||||
this.buffered.set("permissions", updatedPermissions);
|
||||
},
|
||||
|
||||
setPermissionsGroups(groupIds) {
|
||||
let permissions = {};
|
||||
this.allGroups.forEach((group) => {
|
||||
if (groupIds.includes(group.id)) {
|
||||
permissions[group.name] = PermissionType.FULL;
|
||||
}
|
||||
});
|
||||
|
||||
this.buffered.set("permissions", permissions);
|
||||
},
|
||||
|
||||
save() {
|
||||
@ -41,6 +118,14 @@ export default Component.extend(bufferedProperty("model"), {
|
||||
"permissions"
|
||||
);
|
||||
|
||||
// If 'everyone' is set to full, we can remove any groups.
|
||||
if (
|
||||
!attrs.permissions ||
|
||||
attrs.permissions.everyone === PermissionType.FULL
|
||||
) {
|
||||
attrs.permissions = { everyone: PermissionType.FULL };
|
||||
}
|
||||
|
||||
this.model.save(attrs).then(() => {
|
||||
this.commitBuffer();
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
deleteTag() {
|
||||
this.sendAction("deleteAction", this.tagInfo);
|
||||
this.deleteAction(this.tagInfo);
|
||||
},
|
||||
|
||||
unlinkSynonym(tag) {
|
||||
|
||||
@ -11,6 +11,31 @@ export default Controller.extend(ModalFunctionality, {
|
||||
gravatarBaseUrl: setting("gravatar_base_url"),
|
||||
gravatarLoginUrl: setting("gravatar_login_url"),
|
||||
|
||||
@discourseComputed(
|
||||
"siteSettings.selectable_avatars_enabled",
|
||||
"siteSettings.selectable_avatars"
|
||||
)
|
||||
selectableAvatars(enabled, list) {
|
||||
if (enabled) {
|
||||
return list ? list.split("|") : [];
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"user.avatar_template",
|
||||
"user.system_avatar_template",
|
||||
"user.gravatar_avatar_template"
|
||||
)
|
||||
selected(avatarTemplate, systemAvatarTemplate, gravatarAvatarTemplate) {
|
||||
if (avatarTemplate === systemAvatarTemplate) {
|
||||
return "system";
|
||||
} else if (avatarTemplate === gravatarAvatarTemplate) {
|
||||
return "gravatar";
|
||||
} else {
|
||||
return "custom";
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
"selected",
|
||||
"user.system_avatar_upload_id",
|
||||
@ -55,7 +80,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
|
||||
actions: {
|
||||
uploadComplete() {
|
||||
this.set("selected", "uploaded");
|
||||
this.set("selected", "custom");
|
||||
},
|
||||
|
||||
refreshGravatar() {
|
||||
|
||||
@ -229,7 +229,7 @@ export default Controller.extend(
|
||||
return this._hpPromise;
|
||||
}
|
||||
|
||||
this._hpPromise = ajax(userPath("hp.json"))
|
||||
this._hpPromise = ajax("/session/hp.json")
|
||||
.then((json) => {
|
||||
this._challengeDate = new Date();
|
||||
// remove 30 seconds for jitter, make sure this works for at least
|
||||
|
||||
@ -39,10 +39,12 @@ export function changeSort(sortBy) {
|
||||
}
|
||||
}
|
||||
|
||||
export function resetParams() {
|
||||
export function resetParams(skipParams = []) {
|
||||
let { controller } = this;
|
||||
controllerOpts.queryParams.forEach((p) => {
|
||||
controller.set(p, queryParams[p].default);
|
||||
if (!skipParams.includes(p)) {
|
||||
controller.set(p, queryParams[p].default);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ const controllerOpts = {
|
||||
router: service(),
|
||||
|
||||
period: null,
|
||||
canCreateTopicOnCategory: null,
|
||||
|
||||
canStar: alias("currentUser.id"),
|
||||
showTopicPostBadges: not("discoveryTopics.new"),
|
||||
@ -57,9 +58,9 @@ const controllerOpts = {
|
||||
return false;
|
||||
},
|
||||
|
||||
refresh() {
|
||||
refresh(options = { skipResettingParams: [] }) {
|
||||
const filter = this.get("model.filter");
|
||||
this.send("resetParams");
|
||||
this.send("resetParams", options.skipResettingParams);
|
||||
|
||||
// Don't refresh if we're still loading
|
||||
if (this.get("discovery.loading")) {
|
||||
@ -72,23 +73,36 @@ const controllerOpts = {
|
||||
this.set("discovery.loading", true);
|
||||
|
||||
this.topicTrackingState.resetTracking();
|
||||
|
||||
this.store.findFiltered("topicList", { filter }).then((list) => {
|
||||
TopicList.hideUniformCategory(list, this.category);
|
||||
|
||||
this.setProperties({ model: list });
|
||||
this.resetSelected();
|
||||
|
||||
if (this.topicTrackingState) {
|
||||
this.topicTrackingState.sync(list, filter);
|
||||
// If query params are present in the current route, we need still need to sync topic
|
||||
// tracking with the topicList without any query params. Then we set the topic
|
||||
// list to the list filtered with query params in the afterRefresh.
|
||||
const params = this.router.currentRoute.queryParams;
|
||||
if (Object.keys(params).length) {
|
||||
this.store
|
||||
.findFiltered("topicList", { filter, params })
|
||||
.then((listWithParams) => {
|
||||
this.afterRefresh(filter, list, listWithParams);
|
||||
});
|
||||
} else {
|
||||
this.afterRefresh(filter, list);
|
||||
}
|
||||
|
||||
this.send("loadingComplete");
|
||||
});
|
||||
},
|
||||
|
||||
resetNew() {
|
||||
Topic.resetNew(this.category, !this.noSubcategories).then(() =>
|
||||
this.send("refresh")
|
||||
const tracked =
|
||||
(this.router.currentRoute.queryParams["f"] ||
|
||||
this.router.currentRoute.queryParams["filter"]) === "tracked";
|
||||
|
||||
Topic.resetNew(this.category, !this.noSubcategories, tracked).then(() =>
|
||||
this.send(
|
||||
"refresh",
|
||||
tracked ? { skipResettingParams: ["filter", "f"] } : {}
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
@ -97,6 +111,17 @@ const controllerOpts = {
|
||||
},
|
||||
},
|
||||
|
||||
afterRefresh(filter, list, listModel = list) {
|
||||
this.setProperties({ model: listModel });
|
||||
this.resetSelected();
|
||||
|
||||
if (this.topicTrackingState) {
|
||||
this.topicTrackingState.sync(list, filter);
|
||||
}
|
||||
|
||||
this.send("loadingComplete");
|
||||
},
|
||||
|
||||
isFilterPage: function (filter, filterType) {
|
||||
if (!filter) {
|
||||
return false;
|
||||
@ -134,11 +159,6 @@ const controllerOpts = {
|
||||
weekly: equal("period", "weekly"),
|
||||
daily: equal("period", "daily"),
|
||||
|
||||
@discourseComputed("model")
|
||||
canCreateTopicOnCategory(model) {
|
||||
return model.can_create_topic;
|
||||
},
|
||||
|
||||
@discourseComputed("allLoaded", "model.topics.length")
|
||||
footerMessage(allLoaded, topicsLength) {
|
||||
if (!allLoaded) {
|
||||
|
||||
@ -36,7 +36,7 @@ export default Controller.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
if (!refresh && model.members.length >= model.user_count) {
|
||||
if (!refresh && model.requesters.length >= model.user_count) {
|
||||
this.set("application.showFooter", true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { searchForTerm } from "discourse/lib/search";
|
||||
import { bind } from "discourse-common/utils/decorators";
|
||||
import { prefixProtocol } from "discourse/lib/url";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
_debounced: null,
|
||||
@ -144,8 +145,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
actions: {
|
||||
ok() {
|
||||
const origLink = this.linkUrl;
|
||||
const linkUrl =
|
||||
origLink.indexOf("://") === -1 ? `http://${origLink}` : origLink;
|
||||
const linkUrl = prefixProtocol(origLink);
|
||||
const sel = this.toolbarEvent.selected;
|
||||
|
||||
if (isEmpty(linkUrl)) {
|
||||
|
||||
@ -15,6 +15,7 @@ export default Controller.extend({
|
||||
success: false,
|
||||
oldEmail: null,
|
||||
newEmail: null,
|
||||
successMessage: null,
|
||||
|
||||
newEmailEmpty: empty("newEmail"),
|
||||
|
||||
@ -77,7 +78,25 @@ export default Controller.extend({
|
||||
? this.model.addEmail(this.newEmail)
|
||||
: this.model.changeEmail(this.newEmail)
|
||||
).then(
|
||||
() => this.set("success", true),
|
||||
() => {
|
||||
this.set("success", true);
|
||||
|
||||
if (this.model.staff) {
|
||||
this.set(
|
||||
"successMessage",
|
||||
I18n.t("user.change_email.success_staff")
|
||||
);
|
||||
} else {
|
||||
if (this.currentUser.admin) {
|
||||
this.set(
|
||||
"successMessage",
|
||||
I18n.t("user.change_email.success_via_admin")
|
||||
);
|
||||
} else {
|
||||
this.set("successMessage", I18n.t("user.change_email.success"));
|
||||
}
|
||||
}
|
||||
},
|
||||
(e) => {
|
||||
this.setProperties({ error: true, saving: false });
|
||||
if (
|
||||
|
||||
@ -68,6 +68,10 @@ addBulkButton("showAppendTagTopics", "append_tags", {
|
||||
class: "btn-default",
|
||||
enabledSetting: "tagging_enabled",
|
||||
});
|
||||
addBulkButton("removeTags", "remove_tags", {
|
||||
icon: "tag",
|
||||
class: "btn-danger",
|
||||
});
|
||||
addBulkButton("deleteTopics", "delete", {
|
||||
icon: "trash-alt",
|
||||
class: "btn-danger",
|
||||
@ -201,6 +205,10 @@ export default Controller.extend(ModalFunctionality, {
|
||||
resetRead() {
|
||||
this.performAndRefresh({ type: "reset_read" });
|
||||
},
|
||||
|
||||
removeTags() {
|
||||
this.performAndRefresh({ type: "remove_tags" });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import I18n from "I18n";
|
||||
import { isPresent, isEmpty } from "@ember/utils";
|
||||
import { or, and, not, alias } from "@ember/object/computed";
|
||||
import EmberObject from "@ember/object";
|
||||
import { next, schedule } from "@ember/runloop";
|
||||
import { next, schedule, later } from "@ember/runloop";
|
||||
import Controller, { inject as controller } from "@ember/controller";
|
||||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import Composer from "discourse/models/composer";
|
||||
@ -30,6 +30,8 @@ import { deepMerge } from "discourse-common/lib/object";
|
||||
|
||||
let customPostMessageCallbacks = {};
|
||||
|
||||
const RETRIES_ON_RATE_LIMIT = 4;
|
||||
|
||||
export function resetCustomPostMessageCallbacks() {
|
||||
customPostMessageCallbacks = {};
|
||||
}
|
||||
@ -1292,6 +1294,42 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
this.model.destroy(this.currentUser);
|
||||
},
|
||||
|
||||
retryOnRateLimit(times, promise, topicId) {
|
||||
const currentTopicId = this.get("model.id");
|
||||
topicId = topicId || currentTopicId;
|
||||
if (topicId !== currentTopicId) {
|
||||
// we navigated to another topic, so skip
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.retryRateLimited || times <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
promise().catch((e) => {
|
||||
const xhr = e.jqXHR;
|
||||
if (
|
||||
xhr &&
|
||||
xhr.status === 429 &&
|
||||
xhr.responseJSON &&
|
||||
xhr.responseJSON.extras &&
|
||||
xhr.responseJSON.extras.wait_seconds
|
||||
) {
|
||||
let waitSeconds = xhr.responseJSON.extras.wait_seconds;
|
||||
if (waitSeconds < 5) {
|
||||
waitSeconds = 5;
|
||||
}
|
||||
|
||||
this.retryRateLimited = true;
|
||||
|
||||
later(() => {
|
||||
this.retryRateLimited = false;
|
||||
this.retryOnRateLimit(times - 1, promise, topicId);
|
||||
}, waitSeconds * 1000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.unsubscribe();
|
||||
|
||||
@ -1363,7 +1401,22 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
break;
|
||||
}
|
||||
case "created": {
|
||||
postStream.triggerNewPostInStream(data.id).then(() => refresh());
|
||||
this.newPostsInStream = this.newPostsInStream || [];
|
||||
this.newPostsInStream.push(data.id);
|
||||
|
||||
this.retryOnRateLimit(RETRIES_ON_RATE_LIMIT, () => {
|
||||
const postIds = this.newPostsInStream;
|
||||
this.newPostsInStream = [];
|
||||
|
||||
return postStream
|
||||
.triggerNewPostsInStream(postIds, { background: true })
|
||||
.then(() => refresh())
|
||||
.catch((e) => {
|
||||
this.newPostsInStream = postIds.concat(this.newPostsInStream);
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
|
||||
if (this.get("currentUser.id") !== data.user_id) {
|
||||
this.documentTitle.incrementBackgroundContextCount();
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ const TITLE_SUBS = {
|
||||
export default htmlHelper((period, options) => {
|
||||
const title = I18n.t("filters.top." + (TITLE_SUBS[period] || "this_week"));
|
||||
if (options.hash.showDateRange) {
|
||||
var dateString = "";
|
||||
let dateString = "";
|
||||
let finish;
|
||||
|
||||
if (options.hash.fullDay) {
|
||||
@ -41,11 +41,15 @@ export default htmlHelper((period, options) => {
|
||||
finish.format(I18n.t("dates.long_no_year_no_time"));
|
||||
break;
|
||||
case "weekly":
|
||||
let start;
|
||||
if (options.hash.fullDay) {
|
||||
start = finish.clone().subtract(1, "week");
|
||||
} else {
|
||||
start = finish.clone().subtract(6, "days");
|
||||
}
|
||||
|
||||
dateString =
|
||||
finish
|
||||
.clone()
|
||||
.subtract(1, "week")
|
||||
.format(I18n.t("dates.long_no_year_no_time")) +
|
||||
start.format(I18n.t("dates.long_no_year_no_time")) +
|
||||
" - " +
|
||||
finish.format(I18n.t("dates.long_no_year_no_time"));
|
||||
break;
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { helperContext } from "discourse-common/lib/helpers";
|
||||
|
||||
export function resolveShareUrl(url, user) {
|
||||
const badgesEnabled = helperContext().siteSettings.enable_badges;
|
||||
const userSuffix = user && badgesEnabled ? `?u=${user.username_lower}` : "";
|
||||
|
||||
return url + userSuffix;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default {
|
||||
name: "avatar-select",
|
||||
|
||||
initialize(container) {
|
||||
this.selectableAvatarsEnabled = container.lookup(
|
||||
"site-settings:main"
|
||||
).selectable_avatars_enabled;
|
||||
|
||||
container
|
||||
.lookup("service:app-events")
|
||||
.on("show-avatar-select", this, "_showAvatarSelect");
|
||||
},
|
||||
|
||||
_showAvatarSelect(user) {
|
||||
const avatarTemplate = user.avatar_template;
|
||||
let selected = "uploaded";
|
||||
|
||||
if (avatarTemplate === user.system_avatar_template) {
|
||||
selected = "system";
|
||||
} else if (avatarTemplate === user.gravatar_avatar_template) {
|
||||
selected = "gravatar";
|
||||
}
|
||||
|
||||
const modal = showModal("avatar-selector");
|
||||
modal.setProperties({ user, selected });
|
||||
|
||||
if (this.selectableAvatarsEnabled) {
|
||||
ajax("/site/selectable-avatars.json").then((avatars) =>
|
||||
modal.set("selectableAvatars", avatars)
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -61,6 +61,10 @@ import KeyboardShortcuts from "discourse/lib/keyboard-shortcuts";
|
||||
import { addFeaturedLinkMetaDecorator } from "discourse/lib/render-topic-featured-link";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import { addAdvancedSearchOptions } from "discourse/components/search-advanced-options";
|
||||
import {
|
||||
addSaveableUserField,
|
||||
addSaveableUserOptionField,
|
||||
} from "discourse/models/user";
|
||||
|
||||
// If you add any methods to the API ensure you bump up this number
|
||||
const PLUGIN_API_VERSION = "0.11.0";
|
||||
@ -1207,6 +1211,13 @@ class PluginApi {
|
||||
addAdvancedSearchOptions(options) {
|
||||
addAdvancedSearchOptions(options);
|
||||
}
|
||||
|
||||
addSaveableUserField(fieldName) {
|
||||
addSaveableUserField(fieldName);
|
||||
}
|
||||
addSaveableUserOptionField(fieldName) {
|
||||
addSaveableUserOptionField(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
let _pluginv01;
|
||||
|
||||
@ -25,7 +25,16 @@ export class Tag {
|
||||
}
|
||||
|
||||
if (this.inline) {
|
||||
text = " " + text + " ";
|
||||
const prev = this.element.prev;
|
||||
const next = this.element.next;
|
||||
|
||||
if (prev && prev.name !== "#text") {
|
||||
text = " " + text;
|
||||
}
|
||||
|
||||
if (next && next.name !== "#text") {
|
||||
text = text + " ";
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
@ -34,6 +34,7 @@ const SERVER_SIDE_ONLY = [
|
||||
/^\/admin\/logs\/watched_words\/action\/[^\/]+\/download$/,
|
||||
/^\/pub\//,
|
||||
/^\/invites\//,
|
||||
/^\/styleguide/,
|
||||
];
|
||||
|
||||
// The amount of height (in pixles) that we factor in when jumpEnd is called so
|
||||
@ -493,4 +494,10 @@ export function setURLContainer(container) {
|
||||
setOwner(_urlInstance, container);
|
||||
}
|
||||
|
||||
export function prefixProtocol(url) {
|
||||
return url.indexOf("://") === -1 && url.indexOf("mailto:") !== 0
|
||||
? "https://" + url
|
||||
: url;
|
||||
}
|
||||
|
||||
export default _urlInstance;
|
||||
|
||||
@ -22,22 +22,21 @@ export default Mixin.create({
|
||||
},
|
||||
|
||||
dismissRead(operationType, options) {
|
||||
let operation;
|
||||
if (operationType === "posts") {
|
||||
operation = { type: "dismiss_posts" };
|
||||
} else {
|
||||
operation = {
|
||||
type: "change_notification_level",
|
||||
notification_level_id: NotificationLevels.REGULAR,
|
||||
};
|
||||
}
|
||||
const operation =
|
||||
operationType === "posts"
|
||||
? { type: "dismiss_posts" }
|
||||
: {
|
||||
type: "change_notification_level",
|
||||
notification_level_id: NotificationLevels.REGULAR,
|
||||
};
|
||||
|
||||
let promise;
|
||||
if (this.selected.length > 0) {
|
||||
promise = Topic.bulkOperation(this.selected, operation);
|
||||
} else {
|
||||
promise = Topic.bulkOperationByFilter("unread", operation, options);
|
||||
}
|
||||
const tracked =
|
||||
(this.router.currentRoute.queryParams["f"] ||
|
||||
this.router.currentRoute.queryParams["filter"]) === "tracked";
|
||||
|
||||
const promise = this.selected.length
|
||||
? Topic.bulkOperation(this.selected, operation, tracked)
|
||||
: Topic.bulkOperationByFilter("unread", operation, options, tracked);
|
||||
|
||||
promise.then((result) => {
|
||||
if (result && result.topic_ids) {
|
||||
@ -47,7 +46,10 @@ export default Mixin.create({
|
||||
}
|
||||
|
||||
this.send("closeModal");
|
||||
this.send("refresh");
|
||||
this.send(
|
||||
"refresh",
|
||||
tracked ? { skipResettingParams: ["filter", "f"] } : {}
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@ -113,6 +113,7 @@ const Composer = RestModel.extend({
|
||||
noBump: false,
|
||||
draftSaving: false,
|
||||
draftSaved: false,
|
||||
draftForceSave: false,
|
||||
|
||||
archetypes: reads("site.archetypes"),
|
||||
|
||||
@ -1171,7 +1172,8 @@ const Composer = RestModel.extend({
|
||||
this.draftKey,
|
||||
this.draftSequence,
|
||||
data,
|
||||
this.messageBus.clientId
|
||||
this.messageBus.clientId,
|
||||
{ forceSave: this.draftForceSave }
|
||||
)
|
||||
.then((result) => {
|
||||
if (result.draft_sequence) {
|
||||
@ -1186,6 +1188,7 @@ const Composer = RestModel.extend({
|
||||
this.setProperties({
|
||||
draftSaved: true,
|
||||
draftConflictUser: null,
|
||||
draftForceSave: false,
|
||||
});
|
||||
}
|
||||
})
|
||||
@ -1203,10 +1206,29 @@ const Composer = RestModel.extend({
|
||||
const json = e.jqXHR.responseJSON;
|
||||
draftStatus = json.errors[0];
|
||||
if (json.extras && json.extras.description) {
|
||||
bootbox.alert(json.extras.description);
|
||||
const buttons = [];
|
||||
|
||||
// ignore and force save draft
|
||||
buttons.push({
|
||||
label: I18n.t("composer.ignore"),
|
||||
class: "btn",
|
||||
callback: () => {
|
||||
this.set("draftForceSave", true);
|
||||
},
|
||||
});
|
||||
|
||||
// reload
|
||||
buttons.push({
|
||||
label: I18n.t("composer.reload"),
|
||||
class: "btn btn-primary",
|
||||
callback: () => {
|
||||
window.location.reload();
|
||||
},
|
||||
});
|
||||
|
||||
bootbox.dialog(json.extras.description, buttons);
|
||||
}
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
draftStatus: draftStatus || I18n.t("composer.drafts_offline"),
|
||||
draftConflictUser: null,
|
||||
|
||||
@ -23,11 +23,17 @@ Draft.reopenClass({
|
||||
return current;
|
||||
},
|
||||
|
||||
save(key, sequence, data, clientId) {
|
||||
save(key, sequence, data, clientId, { forceSave = false } = {}) {
|
||||
data = typeof data === "string" ? data : JSON.stringify(data);
|
||||
return ajax("/draft.json", {
|
||||
type: "POST",
|
||||
data: { draft_key: key, sequence, data, owner: clientId },
|
||||
data: {
|
||||
draft_key: key,
|
||||
sequence,
|
||||
data,
|
||||
owner: clientId,
|
||||
force_save: forceSave,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -11,6 +11,7 @@ import { loadTopicView } from "discourse/models/topic";
|
||||
import { Promise } from "rsvp";
|
||||
import User from "discourse/models/user";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
export default RestModel.extend({
|
||||
_identityMap: null,
|
||||
@ -599,15 +600,25 @@ export default RestModel.extend({
|
||||
});
|
||||
},
|
||||
|
||||
/* mainly for backwards compatability with plugins, used in quick messages plugin
|
||||
* TODO: remove July 2021
|
||||
* */
|
||||
triggerNewPostInStream(postId, opts) {
|
||||
deprecated(
|
||||
"Please use triggerNewPostsInStream, this method will be removed July 2021"
|
||||
);
|
||||
return this.triggerNewPostsInStream([postId], opts);
|
||||
},
|
||||
|
||||
/**
|
||||
Finds and adds a post to the stream by id. Typically this would happen if we receive a message
|
||||
Finds and adds posts to the stream by id. Typically this would happen if we receive a message
|
||||
from the message bus indicating there's a new post. We'll only insert it if we currently
|
||||
have no filters.
|
||||
**/
|
||||
triggerNewPostInStream(postId) {
|
||||
triggerNewPostsInStream(postIds, opts) {
|
||||
const resolved = Promise.resolve();
|
||||
|
||||
if (!postId) {
|
||||
if (!postIds || postIds.length === 0) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@ -617,27 +628,46 @@ export default RestModel.extend({
|
||||
}
|
||||
|
||||
const loadedAllPosts = this.loadedAllPosts;
|
||||
this._loadingPostIds = this._loadingPostIds || [];
|
||||
|
||||
if (this.stream.indexOf(postId) === -1) {
|
||||
this.stream.addObject(postId);
|
||||
if (loadedAllPosts) {
|
||||
this.set("loadingLastPost", true);
|
||||
return this.findPostsByIds([postId])
|
||||
.then((posts) => {
|
||||
const ignoredUsers =
|
||||
User.current() && User.current().get("ignored_users");
|
||||
posts.forEach((p) => {
|
||||
if (ignoredUsers && ignoredUsers.includes(p.username)) {
|
||||
this.stream.removeObject(postId);
|
||||
return;
|
||||
}
|
||||
this.appendPost(p);
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("loadingLastPost", false);
|
||||
});
|
||||
let missingIds = [];
|
||||
|
||||
postIds.forEach((postId) => {
|
||||
if (postId && this.stream.indexOf(postId) === -1) {
|
||||
missingIds.push(postId);
|
||||
}
|
||||
});
|
||||
|
||||
if (missingIds.length === 0) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
if (loadedAllPosts) {
|
||||
missingIds.forEach((postId) => {
|
||||
if (this._loadingPostIds.indexOf(postId) === -1) {
|
||||
this._loadingPostIds.push(postId);
|
||||
}
|
||||
});
|
||||
this.set("loadingLastPost", true);
|
||||
return this.findPostsByIds(this._loadingPostIds, opts)
|
||||
.then((posts) => {
|
||||
this._loadingPostIds = null;
|
||||
const ignoredUsers =
|
||||
User.current() && User.current().get("ignored_users");
|
||||
posts.forEach((p) => {
|
||||
if (ignoredUsers && ignoredUsers.includes(p.username)) {
|
||||
this.stream.removeObject(p.id);
|
||||
return;
|
||||
}
|
||||
this.stream.addObject(p.id);
|
||||
this.appendPost(p);
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.set("loadingLastPost", false);
|
||||
});
|
||||
} else {
|
||||
missingIds.forEach((postId) => this.stream.addObject(postId));
|
||||
}
|
||||
|
||||
return resolved;
|
||||
@ -789,11 +819,11 @@ export default RestModel.extend({
|
||||
// Get the index in the stream of a post id. (Use this for the topic progress bar.)
|
||||
progressIndexOfPostId(post) {
|
||||
const postId = post.get("id");
|
||||
const index = this.stream.indexOf(postId);
|
||||
|
||||
if (this.isMegaTopic) {
|
||||
return post.get("post_number");
|
||||
} else {
|
||||
const index = this.stream.indexOf(postId);
|
||||
return index + 1;
|
||||
}
|
||||
},
|
||||
@ -972,17 +1002,17 @@ export default RestModel.extend({
|
||||
});
|
||||
},
|
||||
|
||||
findPostsByIds(postIds) {
|
||||
findPostsByIds(postIds, opts) {
|
||||
const identityMap = this._identityMap;
|
||||
const unloaded = postIds.filter((p) => !identityMap[p]);
|
||||
|
||||
// Load our unloaded posts by id
|
||||
return this.loadIntoIdentityMap(unloaded).then(() => {
|
||||
return this.loadIntoIdentityMap(unloaded, opts).then(() => {
|
||||
return postIds.map((p) => identityMap[p]).compact();
|
||||
});
|
||||
},
|
||||
|
||||
loadIntoIdentityMap(postIds) {
|
||||
loadIntoIdentityMap(postIds, opts) {
|
||||
if (isEmpty(postIds)) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
@ -993,7 +1023,15 @@ export default RestModel.extend({
|
||||
const data = { post_ids: postIds, include_suggested: includeSuggested };
|
||||
const store = this.store;
|
||||
|
||||
return ajax(url, { data }).then((result) => {
|
||||
let headers = {};
|
||||
if (opts && opts.background) {
|
||||
headers["Discourse-Background"] = "true";
|
||||
}
|
||||
|
||||
return ajax(url, {
|
||||
data,
|
||||
headers,
|
||||
}).then((result) => {
|
||||
if (result.suggested_topics) {
|
||||
this.set("topic.suggested_topics", result.suggested_topics);
|
||||
}
|
||||
|
||||
@ -17,18 +17,13 @@ import Site from "discourse/models/site";
|
||||
import User from "discourse/models/user";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { fancyTitle } from "discourse/lib/topic-fancy-title";
|
||||
import { resolveShareUrl } from "discourse/helpers/share-url";
|
||||
|
||||
const Post = RestModel.extend({
|
||||
@discourseComputed("url")
|
||||
shareUrl(url) {
|
||||
const user = User.current();
|
||||
const userSuffix = user ? `?u=${user.username_lower}` : "";
|
||||
|
||||
if (this.firstPost) {
|
||||
return this.get("topic.url") + userSuffix;
|
||||
} else {
|
||||
return url + userSuffix;
|
||||
}
|
||||
return resolveShareUrl(url, user);
|
||||
},
|
||||
|
||||
new_user: equal("trust_level", 0),
|
||||
|
||||
@ -24,6 +24,7 @@ import Site from "discourse/models/site";
|
||||
import User from "discourse/models/user";
|
||||
import bootbox from "bootbox";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import { resolveShareUrl } from "discourse/helpers/share-url";
|
||||
|
||||
export function loadTopicView(topic, args) {
|
||||
const data = deepMerge({}, args);
|
||||
@ -242,8 +243,7 @@ const Topic = RestModel.extend({
|
||||
@discourseComputed("url")
|
||||
shareUrl(url) {
|
||||
const user = User.current();
|
||||
const userQueryString = user ? `?u=${user.get("username_lower")}` : "";
|
||||
return `${url}${userQueryString}`;
|
||||
return resolveShareUrl(url, user);
|
||||
},
|
||||
|
||||
printUrl: fmt("url", "%@/print"),
|
||||
@ -799,18 +799,21 @@ Topic.reopenClass({
|
||||
return promise;
|
||||
},
|
||||
|
||||
bulkOperation(topics, operation) {
|
||||
bulkOperation(topics, operation, tracked) {
|
||||
const data = {
|
||||
topic_ids: topics.mapBy("id"),
|
||||
operation,
|
||||
tracked,
|
||||
};
|
||||
|
||||
return ajax("/topics/bulk", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
topic_ids: topics.map((t) => t.get("id")),
|
||||
operation,
|
||||
},
|
||||
data,
|
||||
});
|
||||
},
|
||||
|
||||
bulkOperationByFilter(filter, operation, options) {
|
||||
let data = { filter, operation };
|
||||
bulkOperationByFilter(filter, operation, options, tracked) {
|
||||
const data = { filter, operation, tracked };
|
||||
|
||||
if (options) {
|
||||
if (options.categoryId) {
|
||||
@ -830,10 +833,12 @@ Topic.reopenClass({
|
||||
});
|
||||
},
|
||||
|
||||
resetNew(category, include_subcategories) {
|
||||
const data = category
|
||||
? { category_id: category.id, include_subcategories }
|
||||
: {};
|
||||
resetNew(category, include_subcategories, tracked = false) {
|
||||
const data = { tracked };
|
||||
if (category) {
|
||||
data.category_id = category.id;
|
||||
data.include_subcategories = include_subcategories;
|
||||
}
|
||||
return ajax("/topics/reset-new", { type: "PUT", data });
|
||||
},
|
||||
|
||||
|
||||
@ -41,6 +41,68 @@ export const SECOND_FACTOR_METHODS = {
|
||||
|
||||
const isForever = (dt) => moment().diff(dt, "years") < -500;
|
||||
|
||||
let userFields = [
|
||||
"bio_raw",
|
||||
"website",
|
||||
"location",
|
||||
"name",
|
||||
"title",
|
||||
"locale",
|
||||
"custom_fields",
|
||||
"user_fields",
|
||||
"muted_usernames",
|
||||
"ignored_usernames",
|
||||
"allowed_pm_usernames",
|
||||
"profile_background_upload_url",
|
||||
"card_background_upload_url",
|
||||
"muted_tags",
|
||||
"tracked_tags",
|
||||
"watched_tags",
|
||||
"watching_first_post_tags",
|
||||
"date_of_birth",
|
||||
"primary_group_id",
|
||||
];
|
||||
|
||||
export function addSaveableUserField(fieldName) {
|
||||
userFields.push(fieldName);
|
||||
}
|
||||
|
||||
let userOptionFields = [
|
||||
"mailing_list_mode",
|
||||
"mailing_list_mode_frequency",
|
||||
"external_links_in_new_tab",
|
||||
"email_digests",
|
||||
"email_in_reply_to",
|
||||
"email_messages_level",
|
||||
"email_level",
|
||||
"email_previous_replies",
|
||||
"color_scheme_id",
|
||||
"dark_scheme_id",
|
||||
"dynamic_favicon",
|
||||
"enable_quoting",
|
||||
"enable_defer",
|
||||
"automatically_unpin_topics",
|
||||
"digest_after_minutes",
|
||||
"new_topic_duration_minutes",
|
||||
"auto_track_topics_after_msecs",
|
||||
"notification_level_when_replying",
|
||||
"like_notification_frequency",
|
||||
"include_tl0_in_digests",
|
||||
"theme_ids",
|
||||
"allow_private_messages",
|
||||
"enable_allowed_pm_users",
|
||||
"homepage_id",
|
||||
"hide_profile_and_presence",
|
||||
"text_size",
|
||||
"title_count_mode",
|
||||
"timezone",
|
||||
"skip_new_user_tips",
|
||||
];
|
||||
|
||||
export function addSaveableUserOptionField(fieldName) {
|
||||
userOptionFields.push(fieldName);
|
||||
}
|
||||
|
||||
const User = RestModel.extend({
|
||||
hasPMs: gt("private_messages_stats.all", 0),
|
||||
hasStartedPMs: gt("private_messages_stats.mine", 0),
|
||||
@ -267,64 +329,10 @@ const User = RestModel.extend({
|
||||
},
|
||||
|
||||
save(fields) {
|
||||
let userFields = [
|
||||
"bio_raw",
|
||||
"website",
|
||||
"location",
|
||||
"name",
|
||||
"title",
|
||||
"locale",
|
||||
"custom_fields",
|
||||
"user_fields",
|
||||
"muted_usernames",
|
||||
"ignored_usernames",
|
||||
"allowed_pm_usernames",
|
||||
"profile_background_upload_url",
|
||||
"card_background_upload_url",
|
||||
"muted_tags",
|
||||
"tracked_tags",
|
||||
"watched_tags",
|
||||
"watching_first_post_tags",
|
||||
"date_of_birth",
|
||||
"primary_group_id",
|
||||
];
|
||||
|
||||
const data = this.getProperties(
|
||||
userFields.filter((uf) => !fields || fields.indexOf(uf) !== -1)
|
||||
);
|
||||
|
||||
let userOptionFields = [
|
||||
"mailing_list_mode",
|
||||
"mailing_list_mode_frequency",
|
||||
"external_links_in_new_tab",
|
||||
"email_digests",
|
||||
"email_in_reply_to",
|
||||
"email_messages_level",
|
||||
"email_level",
|
||||
"email_previous_replies",
|
||||
"color_scheme_id",
|
||||
"dark_scheme_id",
|
||||
"dynamic_favicon",
|
||||
"enable_quoting",
|
||||
"enable_defer",
|
||||
"automatically_unpin_topics",
|
||||
"digest_after_minutes",
|
||||
"new_topic_duration_minutes",
|
||||
"auto_track_topics_after_msecs",
|
||||
"notification_level_when_replying",
|
||||
"like_notification_frequency",
|
||||
"include_tl0_in_digests",
|
||||
"theme_ids",
|
||||
"allow_private_messages",
|
||||
"enable_allowed_pm_users",
|
||||
"homepage_id",
|
||||
"hide_profile_and_presence",
|
||||
"text_size",
|
||||
"title_count_mode",
|
||||
"timezone",
|
||||
"skip_new_user_tips",
|
||||
];
|
||||
|
||||
if (fields) {
|
||||
userOptionFields = userOptionFields.filter(
|
||||
(uo) => fields.indexOf(uo) !== -1
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import UserBadge from "discourse/models/user-badge";
|
||||
import RestrictedUserRoute from "discourse/routes/restricted-user";
|
||||
|
||||
@ -33,7 +34,7 @@ export default RestrictedUserRoute.extend({
|
||||
|
||||
actions: {
|
||||
showAvatarSelector(user) {
|
||||
this.appEvents.trigger("show-avatar-select", user);
|
||||
showModal("avatar-selector").setProperties({ user });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -44,6 +44,7 @@ export default Service.extend({
|
||||
this.notificationCount = 0;
|
||||
}
|
||||
this.appEvents.trigger("discourse:focus-changed", session.hasFocus);
|
||||
this._renderFavicon();
|
||||
this._renderTitle();
|
||||
},
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{{#if shouldShow}}
|
||||
<div class="row">
|
||||
<div class="alert alert-info category-read-only-banner">
|
||||
{{category.read_only_banner}}
|
||||
{{html-safe category.read_only_banner}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{{#if visible}}
|
||||
<div class="row">
|
||||
<div id="banner" class={{overlay}}>
|
||||
{{d-button icon="times" action="dismiss" class="btn btn-flat close" title="banner.close"}}
|
||||
{{d-button icon="times" action=(action "dismiss") class="btn btn-flat close" title="banner.close"}}
|
||||
<div id="banner-content">
|
||||
{{html-safe content}}
|
||||
{{#if currentUser.staff}}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
hasGroups=hasGroups
|
||||
usernames=emailOrUsername
|
||||
placeholderKey=placeholderKey
|
||||
allowEmails=true
|
||||
allowEmails=canInviteViaEmail
|
||||
class="invite-user-input"
|
||||
autocomplete="discourse"
|
||||
value=emailOrUsername
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
</span>
|
||||
{{d-button
|
||||
icon="times"
|
||||
action="dismiss"
|
||||
action=(action "dismiss")
|
||||
class="btn btn-flat close" title="banner.close"
|
||||
}}
|
||||
</div>
|
||||
|
||||
@ -4,12 +4,13 @@
|
||||
<span>
|
||||
{{discourse-linked-text
|
||||
action=(action "turnOn")
|
||||
translatedText=(i18n "pwa.install_banner" title=siteSettings.title)
|
||||
text="pwa.install_banner"
|
||||
textParams=(hash title=siteSettings.title)
|
||||
}}
|
||||
</span>
|
||||
{{d-button
|
||||
icon="times"
|
||||
action="dismiss"
|
||||
action=(action "dismiss")
|
||||
class="btn btn-flat close"
|
||||
title="banner.close"
|
||||
}}
|
||||
|
||||
@ -148,45 +148,64 @@
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group pull-left">
|
||||
|
||||
<div class="count-group control-group pull-left">
|
||||
<label class="control-label" for="search-min-post-count">{{i18n "search.advanced.post.count.label"}}</label>
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.min_post_count)
|
||||
class="input-small"
|
||||
id="search-min-post-count"
|
||||
input=(action "onChangeSearchTermMinPostCount" value="target.value")
|
||||
}}
|
||||
<div class="count pull-left">
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.min_posts)
|
||||
class="input-small"
|
||||
id="search-min-post-count"
|
||||
input=(action "onChangeSearchTermMinPostCount" value="target.value")
|
||||
placeholder=(i18n "search.advanced.post.min.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<span class="count-dash">—</span>
|
||||
<div class="count pull-right">
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.max_posts)
|
||||
class="input-small"
|
||||
id="search-max-post-count"
|
||||
input=(action "onChangeSearchTermMaxPostCount" value="target.value")
|
||||
placeholder=(i18n "search.advanced.post.max.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-min-views">{{i18n "search.advanced.min_views.label"}}</label>
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.min_views)
|
||||
class="input-small"
|
||||
id="search-min-views"
|
||||
input=(action "onChangeSearchTermMinViews" value="target.value")
|
||||
}}
|
||||
<div class="count-group control-group pull-left">
|
||||
<label class="control-label">{{i18n "search.advanced.views.label"}}</label>
|
||||
<div class="count pull-left">
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.min_views)
|
||||
class="input-small"
|
||||
id="search-min-views"
|
||||
input=(action "onChangeSearchTermMinViews" value="target.value")
|
||||
placeholder=(i18n "search.advanced.min_views.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<span class="count-dash">—</span>
|
||||
<div class="count pull-right">
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.max_views)
|
||||
class="input-small"
|
||||
id="search-max-views"
|
||||
input=(action "onChangeSearchTermMaxViews" value="target.value")
|
||||
placeholder=(i18n "search.advanced.max_views.placeholder")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group pull-left">
|
||||
<label class="control-label" for="search-max-views">{{i18n "search.advanced.max_views.label"}}</label>
|
||||
<div class="controls">
|
||||
{{input
|
||||
type="number"
|
||||
value=(readonly searchedTerms.max_views)
|
||||
class="input-small"
|
||||
id="search-max-views"
|
||||
input=(action "onChangeSearchTermMaxViews" value="target.value")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{plugin-outlet name="advanced-search-options-below" args=(hash searchedTerms=searchedTerms onChangeSearchedTermField=onChangeSearchedTermField) tagName=""}}
|
||||
|
||||
@ -34,6 +34,12 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{d-button action="close" class="btn btn-flat close" icon="times" aria-label="share.close" title="share.close"}}
|
||||
{{d-button
|
||||
action=(action "close")
|
||||
class="btn btn-flat close"
|
||||
icon="times"
|
||||
aria-label="share.close"
|
||||
title="share.close"
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
value="public"
|
||||
id="public-permission"
|
||||
selection=buffered.permissionName
|
||||
onChange=(action "setPermissions")}}
|
||||
onChange=(action "setPermissionsType")}}
|
||||
|
||||
<label class="radio" for="public-permission">
|
||||
{{i18n "tagging.groups.everyone_can_use"}}
|
||||
@ -51,11 +51,20 @@
|
||||
value="visible"
|
||||
id="visible-permission"
|
||||
selection=buffered.permissionName
|
||||
onChange=(action "setPermissions")}}
|
||||
onChange=(action "setPermissionsType")}}
|
||||
|
||||
<label class="radio" for="visible-permission">
|
||||
{{i18n "tagging.groups.usable_only_by_staff"}}
|
||||
{{i18n "tagging.groups.usable_only_by_groups"}}
|
||||
</label>
|
||||
|
||||
<div class="group-access-control {{if showPrivateChooser "hidden"}}">
|
||||
{{group-chooser
|
||||
content=allGroups
|
||||
value=selectedGroupIds
|
||||
labelProperty="name"
|
||||
onChange=(action "setPermissionsGroups")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{radio-button
|
||||
@ -64,12 +73,20 @@
|
||||
value="private"
|
||||
id="private-permission"
|
||||
selection=buffered.permissionName
|
||||
onChange=(action "setPermissions")}}
|
||||
onChange=(action "setPermissionsType")}}
|
||||
|
||||
<label class="radio" for="private-permission">
|
||||
{{i18n "tagging.groups.visible_only_to_staff"}}
|
||||
{{i18n "tagging.groups.visible_only_to_groups"}}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="group-access-control {{unless showPrivateChooser "hidden"}}">
|
||||
{{group-chooser
|
||||
content=allGroups
|
||||
value=selectedGroupIds
|
||||
labelProperty="name"
|
||||
onChange=(action "setPermissionsGroups")}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{d-button
|
||||
|
||||
@ -11,13 +11,7 @@
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<div class="instructions">
|
||||
<p>
|
||||
{{#if model.staff}}
|
||||
{{i18n "user.change_email.success_staff"}}
|
||||
{{else}}
|
||||
{{i18n "user.change_email.success"}}
|
||||
{{/if}}
|
||||
</p>
|
||||
<p>{{ successMessage }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -135,7 +135,9 @@
|
||||
{{#if siteSettings.automatically_unpin_topics}}
|
||||
{{preference-checkbox labelKey="user.automatically_unpin_topics" checked=model.user_option.automatically_unpin_topics class="pref-auto-unpin"}}
|
||||
{{/if}}
|
||||
{{preference-checkbox labelKey="user.hide_profile_and_presence" checked=model.user_option.hide_profile_and_presence class="pref-hide-profile"}}
|
||||
{{#if siteSettings.allow_users_to_hide_profile}}
|
||||
{{preference-checkbox labelKey="user.hide_profile_and_presence" checked=model.user_option.hide_profile_and_presence class="pref-hide-profile"}}
|
||||
{{/if}}
|
||||
{{#if isiPad}}
|
||||
{{preference-checkbox labelKey="user.enable_physical_keyboard" checked=disableSafariHacks class="pref-safari-hacks"}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{{#d-section tagName="" pageClass="tags" bodyClass=(concat "tag-" tag.id)}}
|
||||
{{#d-section tagName="" pageClass="tags" bodyClass=(concat "tag-" tag.id (if category.slug (concat " category-" category.slug)) "")}}
|
||||
<div class="container">
|
||||
{{discourse-banner user=currentUser banner=site.banner}}
|
||||
</div>
|
||||
|
||||
@ -145,5 +145,9 @@
|
||||
{{/if}}
|
||||
</section>
|
||||
{{/load-more}}
|
||||
{{else}}
|
||||
<div class="alert alert-error invite-error">
|
||||
{{model.error}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/d-section}}
|
||||
|
||||
@ -97,14 +97,18 @@ export default createWidget("link", {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
click(e) {
|
||||
if (this.attrs.attributes && this.attrs.attributes.target === "_blank") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantsNewWindow(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (this.attrs.action) {
|
||||
|
||||
@ -27,8 +27,8 @@ createWidget("user-menu-links", {
|
||||
return {
|
||||
label: "user.preferences",
|
||||
className: "user-preferences-link",
|
||||
icon: "cog",
|
||||
href: `${this.attrs.path}/preferences`,
|
||||
icon: "user",
|
||||
href: `${this.attrs.path}/summary`,
|
||||
action: UserMenuAction.QUICK_ACCESS,
|
||||
actionParam: QuickAccess.PROFILE,
|
||||
};
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
acceptance("About");
|
||||
|
||||
QUnit.test("viewing", async (assert) => {
|
||||
test("viewing", async (assert) => {
|
||||
await visit("/about");
|
||||
|
||||
assert.ok($("body.about-page").length, "has body class");
|
||||
@ -1,9 +1,10 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
|
||||
acceptance("Account Created");
|
||||
|
||||
QUnit.test("account created - message", async (assert) => {
|
||||
test("account created - message", async (assert) => {
|
||||
PreloadStore.store("accountCreated", {
|
||||
message: "Hello World",
|
||||
});
|
||||
@ -18,7 +19,7 @@ QUnit.test("account created - message", async (assert) => {
|
||||
assert.notOk(exists(".activation-controls"));
|
||||
});
|
||||
|
||||
QUnit.test("account created - resend email", async (assert) => {
|
||||
test("account created - resend email", async (assert) => {
|
||||
PreloadStore.store("accountCreated", {
|
||||
message: "Hello World",
|
||||
username: "eviltrout",
|
||||
@ -42,7 +43,7 @@ QUnit.test("account created - resend email", async (assert) => {
|
||||
assert.equal(email, "eviltrout@example.com");
|
||||
});
|
||||
|
||||
QUnit.test("account created - update email - cancel", async (assert) => {
|
||||
test("account created - update email - cancel", async (assert) => {
|
||||
PreloadStore.store("accountCreated", {
|
||||
message: "Hello World",
|
||||
username: "eviltrout",
|
||||
@ -62,7 +63,7 @@ QUnit.test("account created - update email - cancel", async (assert) => {
|
||||
assert.equal(currentPath(), "account-created.index");
|
||||
});
|
||||
|
||||
QUnit.test("account created - update email - submit", async (assert) => {
|
||||
test("account created - update email - submit", async (assert) => {
|
||||
PreloadStore.store("accountCreated", {
|
||||
message: "Hello World",
|
||||
username: "eviltrout",
|
||||
@ -1,5 +1,6 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import pretender from "helpers/create-pretender";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
|
||||
acceptance("Admin - Emails", { loggedIn: true });
|
||||
|
||||
@ -16,7 +17,7 @@ Hello, this is a test!
|
||||
|
||||
This part should be elided.`.trim();
|
||||
|
||||
QUnit.test("shows selected and elided text", async (assert) => {
|
||||
test("shows selected and elided text", async (assert) => {
|
||||
pretender.post("/admin/email/advanced-test", () => {
|
||||
return [
|
||||
200,
|
||||
@ -1,7 +1,8 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { skip } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
acceptance("Admin - Search Log Term", { loggedIn: true });
|
||||
|
||||
QUnit.skip("show search log term details", async (assert) => {
|
||||
skip("show search log term details", async (assert) => {
|
||||
await visit("/admin/logs/search_logs/term?term=ruby");
|
||||
|
||||
assert.ok($("div.search-logs-filter").length, "has the search type filter");
|
||||
@ -1,7 +1,8 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { skip } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
acceptance("Admin - Search Logs", { loggedIn: true });
|
||||
|
||||
QUnit.skip("show search logs", async (assert) => {
|
||||
skip("show search logs", async (assert) => {
|
||||
await visit("/admin/logs/search_logs");
|
||||
|
||||
assert.ok($("table.search-logs-list.grid").length, "has the div class");
|
||||
@ -1,5 +1,6 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import siteSettingFixture from "fixtures/site_settings";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import siteSettingFixture from "discourse/tests/fixtures/site-settings";
|
||||
|
||||
var titleOverride = undefined;
|
||||
|
||||
@ -29,7 +30,7 @@ acceptance("Admin - Site Settings", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("upload site setting", async (assert) => {
|
||||
test("upload site setting", async (assert) => {
|
||||
await visit("/admin/site_settings");
|
||||
|
||||
assert.ok(
|
||||
@ -40,7 +41,7 @@ QUnit.test("upload site setting", async (assert) => {
|
||||
assert.ok(exists(".row.setting.upload .undo"), "undo button is present");
|
||||
});
|
||||
|
||||
QUnit.test("changing value updates dirty state", async (assert) => {
|
||||
test("changing value updates dirty state", async (assert) => {
|
||||
await visit("/admin/site_settings");
|
||||
await fillIn("#setting-filter", " title ");
|
||||
assert.equal(count(".row.setting"), 1, "filter returns 1 site setting");
|
||||
@ -87,24 +88,21 @@ QUnit.test("changing value updates dirty state", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"always shows filtered site settings if a filter is set",
|
||||
async (assert) => {
|
||||
await visit("/admin/site_settings");
|
||||
await fillIn("#setting-filter", "title");
|
||||
assert.equal(count(".row.setting"), 1);
|
||||
test("always shows filtered site settings if a filter is set", async (assert) => {
|
||||
await visit("/admin/site_settings");
|
||||
await fillIn("#setting-filter", "title");
|
||||
assert.equal(count(".row.setting"), 1);
|
||||
|
||||
// navigate away to the "Dashboard" page
|
||||
await click(".nav.nav-pills li:nth-child(1) a");
|
||||
assert.equal(count(".row.setting"), 0);
|
||||
// navigate away to the "Dashboard" page
|
||||
await click(".nav.nav-pills li:nth-child(1) a");
|
||||
assert.equal(count(".row.setting"), 0);
|
||||
|
||||
// navigate back to the "Settings" page
|
||||
await click(".nav.nav-pills li:nth-child(2) a");
|
||||
assert.equal(count(".row.setting"), 1);
|
||||
}
|
||||
);
|
||||
// navigate back to the "Settings" page
|
||||
await click(".nav.nav-pills li:nth-child(2) a");
|
||||
assert.equal(count(".row.setting"), 1);
|
||||
});
|
||||
|
||||
QUnit.test("filter settings by plugin name", async (assert) => {
|
||||
test("filter settings by plugin name", async (assert) => {
|
||||
await visit("/admin/site_settings");
|
||||
|
||||
await fillIn("#setting-filter", "plugin:discourse-logo");
|
||||
@ -115,12 +113,12 @@ QUnit.test("filter settings by plugin name", async (assert) => {
|
||||
assert.equal(count(".row.setting"), 0);
|
||||
});
|
||||
|
||||
QUnit.test("category name is preserved", async (assert) => {
|
||||
test("category name is preserved", async (assert) => {
|
||||
await visit("admin/site_settings/category/basic?filter=menu");
|
||||
assert.equal(currentURL(), "admin/site_settings/category/basic?filter=menu");
|
||||
});
|
||||
|
||||
QUnit.test("shows all_results if current category has none", async (assert) => {
|
||||
test("shows all_results if current category has none", async (assert) => {
|
||||
await visit("admin/site_settings");
|
||||
|
||||
await click(".admin-nav .basic a");
|
||||
@ -1,8 +1,9 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - Site Texts", { loggedIn: true });
|
||||
|
||||
QUnit.test("search for a key", async (assert) => {
|
||||
test("search for a key", async (assert) => {
|
||||
await visit("/admin/customize/site_texts");
|
||||
|
||||
await fillIn(".site-text-search", "Test");
|
||||
@ -23,7 +24,7 @@ QUnit.test("search for a key", async (assert) => {
|
||||
assert.ok(exists(".site-text.overridden"));
|
||||
});
|
||||
|
||||
QUnit.test("edit and revert a site text by key", async (assert) => {
|
||||
test("edit and revert a site text by key", async (assert) => {
|
||||
await visit("/admin/customize/site_texts/site.test");
|
||||
|
||||
assert.equal(find(".title h3").text(), "site.test");
|
||||
@ -1,5 +1,6 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - Suspend User", {
|
||||
loggedIn: true,
|
||||
@ -23,7 +24,7 @@ acceptance("Admin - Suspend User", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("suspend a user - cancel", async (assert) => {
|
||||
test("suspend a user - cancel", async (assert) => {
|
||||
await visit("/admin/users/1234/regular");
|
||||
await click(".suspend-user");
|
||||
|
||||
@ -34,7 +35,7 @@ QUnit.test("suspend a user - cancel", async (assert) => {
|
||||
assert.equal(find(".suspend-user-modal:visible").length, 0);
|
||||
});
|
||||
|
||||
QUnit.test("suspend a user - cancel with input", async (assert) => {
|
||||
test("suspend a user - cancel with input", async (assert) => {
|
||||
await visit("/admin/users/1234/regular");
|
||||
await click(".suspend-user");
|
||||
|
||||
@ -61,7 +62,7 @@ QUnit.test("suspend a user - cancel with input", async (assert) => {
|
||||
assert.equal(find(".bootbox.modal:visible").length, 0);
|
||||
});
|
||||
|
||||
QUnit.test("suspend, then unsuspend a user", async (assert) => {
|
||||
test("suspend, then unsuspend a user", async (assert) => {
|
||||
const suspendUntilCombobox = selectKit(".suspend-until .combobox");
|
||||
|
||||
await visit("/admin/flags/active");
|
||||
@ -1,8 +1,9 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - Users Badges", { loggedIn: true });
|
||||
|
||||
QUnit.test("lists badges", async (assert) => {
|
||||
test("lists badges", async (assert) => {
|
||||
await visit("/admin/users/1/eviltrout/badges");
|
||||
|
||||
assert.ok(exists(`span[data-badge-name="Badge 8"]`));
|
||||
@ -1,5 +1,6 @@
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - User Emails", { loggedIn: true });
|
||||
|
||||
@ -31,13 +32,13 @@ const assertMultipleSecondary = (assert, firstEmail, secondEmail) => {
|
||||
);
|
||||
};
|
||||
|
||||
QUnit.test("viewing self without secondary emails", async (assert) => {
|
||||
test("viewing self without secondary emails", async (assert) => {
|
||||
await visit("/admin/users/1/eviltrout");
|
||||
|
||||
assertNoSecondary(assert);
|
||||
});
|
||||
|
||||
QUnit.test("viewing self with multiple secondary emails", async (assert) => {
|
||||
test("viewing self with multiple secondary emails", async (assert) => {
|
||||
await visit("/admin/users/3/markvanlan");
|
||||
|
||||
assert.equal(
|
||||
@ -53,14 +54,14 @@ QUnit.test("viewing self with multiple secondary emails", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("viewing another user with no secondary email", async (assert) => {
|
||||
test("viewing another user with no secondary email", async (assert) => {
|
||||
await visit("/admin/users/1234/regular");
|
||||
await click(`.display-row.secondary-emails button`);
|
||||
|
||||
assertNoSecondary(assert);
|
||||
});
|
||||
|
||||
QUnit.test("viewing another account with secondary emails", async (assert) => {
|
||||
test("viewing another account with secondary emails", async (assert) => {
|
||||
await visit("/admin/users/1235/regular1");
|
||||
await click(`.display-row.secondary-emails button`);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import pretender from "helpers/create-pretender";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
|
||||
acceptance("Admin - User Index", {
|
||||
loggedIn: true,
|
||||
@ -34,7 +35,7 @@ acceptance("Admin - User Index", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("can edit username", async (assert) => {
|
||||
test("can edit username", async (assert) => {
|
||||
pretender.put("/users/sam/preferences/username", () => [
|
||||
200,
|
||||
{
|
||||
@ -60,7 +61,7 @@ QUnit.test("can edit username", async (assert) => {
|
||||
assert.equal(find(".display-row.username .value").text().trim(), "new-sam");
|
||||
});
|
||||
|
||||
QUnit.test("will clear unsaved groups when switching user", async (assert) => {
|
||||
test("will clear unsaved groups when switching user", async (assert) => {
|
||||
await visit("/admin/users/2/sam");
|
||||
|
||||
assert.equal(
|
||||
@ -1,16 +1,17 @@
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Admin - Users List", { loggedIn: true });
|
||||
|
||||
QUnit.test("lists users", async (assert) => {
|
||||
test("lists users", async (assert) => {
|
||||
await visit("/admin/users/list/active");
|
||||
|
||||
assert.ok(exists(".users-list .user"));
|
||||
assert.ok(!exists(".user:eq(0) .email small"), "escapes email");
|
||||
});
|
||||
|
||||
QUnit.test("sorts users", async (assert) => {
|
||||
test("sorts users", async (assert) => {
|
||||
await visit("/admin/users/list/active");
|
||||
|
||||
assert.ok(exists(".users-list .user"));
|
||||
@ -34,7 +35,7 @@ QUnit.test("sorts users", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("toggles email visibility", async (assert) => {
|
||||
test("toggles email visibility", async (assert) => {
|
||||
await visit("/admin/users/list/active");
|
||||
|
||||
assert.ok(exists(".users-list .user"));
|
||||
@ -56,7 +57,7 @@ QUnit.test("toggles email visibility", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("switching tabs", async (assert) => {
|
||||
test("switching tabs", async (assert) => {
|
||||
const activeUser = "eviltrout";
|
||||
const suspectUser = "sam";
|
||||
const activeTitle = I18n.t("admin.users.titles.active");
|
||||
@ -1,7 +1,8 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
acceptance("Admin - Watched Words", { loggedIn: true });
|
||||
|
||||
QUnit.test("list words in groups", async (assert) => {
|
||||
test("list words in groups", async (assert) => {
|
||||
await visit("/admin/logs/watched_words/action/block");
|
||||
|
||||
assert.ok(exists(".watched-words-list"));
|
||||
@ -38,7 +39,7 @@ QUnit.test("list words in groups", async (assert) => {
|
||||
assert.ok(!exists(".watched-words-list .watched-word"), "Empty word list.");
|
||||
});
|
||||
|
||||
QUnit.test("add words", async (assert) => {
|
||||
test("add words", async (assert) => {
|
||||
await visit("/admin/logs/watched_words/action/block");
|
||||
|
||||
click(".show-words-checkbox");
|
||||
@ -55,7 +56,7 @@ QUnit.test("add words", async (assert) => {
|
||||
assert.equal(found.length, 1);
|
||||
});
|
||||
|
||||
QUnit.test("remove words", async (assert) => {
|
||||
test("remove words", async (assert) => {
|
||||
await visit("/admin/logs/watched_words/action/block");
|
||||
await click(".show-words-checkbox");
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
acceptance("Auth Complete", {
|
||||
beforeEach() {
|
||||
const node = document.createElement("meta");
|
||||
@ -16,7 +17,7 @@ acceptance("Auth Complete", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("when login not required", async (assert) => {
|
||||
test("when login not required", async (assert) => {
|
||||
await visit("/");
|
||||
|
||||
assert.equal(currentPath(), "discovery.latest", "it stays on the homepage");
|
||||
@ -27,7 +28,7 @@ QUnit.test("when login not required", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("when login required", async function (assert) {
|
||||
test("when login required", async function (assert) {
|
||||
this.siteSettings.login_required = true;
|
||||
await visit("/");
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Badges", { loggedIn: true });
|
||||
|
||||
QUnit.test("Visit Badge Pages", async (assert) => {
|
||||
test("Visit Badge Pages", async (assert) => {
|
||||
await visit("/badges");
|
||||
|
||||
assert.ok($("body.badges-page").length, "has body class");
|
||||
@ -16,7 +17,7 @@ QUnit.test("Visit Badge Pages", async (assert) => {
|
||||
assert.ok(!exists(".badge-card:eq(0) script"));
|
||||
});
|
||||
|
||||
QUnit.test("shows correct badge titles to choose from", async (assert) => {
|
||||
test("shows correct badge titles to choose from", async (assert) => {
|
||||
const availableBadgeTitles = selectKit(".select-kit");
|
||||
await visit("/badges/50/custombadge");
|
||||
await availableBadgeTitles.expand();
|
||||
@ -1,12 +1,15 @@
|
||||
import { skip } from "qunit";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
loggedInUser,
|
||||
acceptanceUseFakeClock,
|
||||
} from "helpers/qunit-helpers";
|
||||
import pretender from "helpers/create-pretender";
|
||||
import { parsePostData } from "helpers/create-pretender";
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import pretender, {
|
||||
parsePostData,
|
||||
} from "discourse/tests/helpers/create-pretender";
|
||||
|
||||
acceptance("Bookmarking", {
|
||||
loggedIn: true,
|
||||
@ -235,25 +238,22 @@ acceptance("Bookmarking - Mobile", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.skip(
|
||||
"Editing a bookmark that has a Later Today reminder, and it is before 6pm today",
|
||||
async (assert) => {
|
||||
await acceptanceUseFakeClock("2020-05-04T13:00:00", async () => {
|
||||
mockSuccessfulBookmarkPost(assert);
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await openBookmarkModal();
|
||||
await fillIn("input#bookmark-name", "Test name");
|
||||
await click("#tap_tile_later_today");
|
||||
await openEditBookmarkModal();
|
||||
assert.not(
|
||||
exists("#bookmark-custom-date > input"),
|
||||
"it does not show the custom date input"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#tap_tile_later_today.active"),
|
||||
"it preselects Later Today"
|
||||
);
|
||||
assert.verifySteps(["later_today"]);
|
||||
});
|
||||
}
|
||||
);
|
||||
skip("Editing a bookmark that has a Later Today reminder, and it is before 6pm today", async (assert) => {
|
||||
await acceptanceUseFakeClock("2020-05-04T13:00:00", async () => {
|
||||
mockSuccessfulBookmarkPost(assert);
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await openBookmarkModal();
|
||||
await fillIn("input#bookmark-name", "Test name");
|
||||
await click("#tap_tile_later_today");
|
||||
await openEditBookmarkModal();
|
||||
assert.not(
|
||||
exists("#bookmark-custom-date > input"),
|
||||
"it does not show the custom date input"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#tap_tile_later_today.active"),
|
||||
"it preselects Later Today"
|
||||
);
|
||||
assert.verifySteps(["later_today"]);
|
||||
});
|
||||
});
|
||||
@ -1,5 +1,6 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import DiscoveryFixtures from "fixtures/discovery_fixtures";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import DiscoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
||||
|
||||
acceptance("Category Banners", {
|
||||
pretend(server, helper) {
|
||||
@ -29,13 +30,13 @@ acceptance("Category Banners", {
|
||||
slug: "test-read-only-with-banner",
|
||||
permission: null,
|
||||
read_only_banner:
|
||||
"You need to video yourself doing the secret handshake to post here",
|
||||
"You need to video yourself <div class='inner'>doing</div> the secret handshake to post here",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("Does not display category banners when not set", async (assert) => {
|
||||
test("Does not display category banners when not set", async (assert) => {
|
||||
await visit("/c/test-read-only-without-banner");
|
||||
|
||||
await click("#create-topic");
|
||||
@ -46,7 +47,7 @@ QUnit.test("Does not display category banners when not set", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Displays category banners when set", async (assert) => {
|
||||
test("Displays category banners when set", async (assert) => {
|
||||
await visit("/c/test-read-only-with-banner");
|
||||
|
||||
await click("#create-topic");
|
||||
@ -55,6 +56,10 @@ QUnit.test("Displays category banners when set", async (assert) => {
|
||||
await click(".modal-footer>.btn-primary");
|
||||
assert.ok(!visible(".bootbox.modal"), "it closes the modal");
|
||||
assert.ok(visible(".category-read-only-banner"), "it shows a banner");
|
||||
assert.ok(
|
||||
find(".category-read-only-banner .inner").length === 1,
|
||||
"it allows staff to embed html in the message"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Anonymous Category Banners", {
|
||||
@ -80,7 +85,7 @@ acceptance("Anonymous Category Banners", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("Does not display category banners when set", async (assert) => {
|
||||
test("Does not display category banners when set", async (assert) => {
|
||||
await visit("/c/test-read-only-with-banner");
|
||||
assert.ok(
|
||||
!visible(".category-read-only-banner"),
|
||||
@ -0,0 +1,27 @@
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("CategoryChooser", {
|
||||
loggedIn: true,
|
||||
settings: {
|
||||
allow_uncategorized_topics: false,
|
||||
},
|
||||
});
|
||||
|
||||
test("does not display uncategorized if not allowed", async (assert) => {
|
||||
const categoryChooser = selectKit(".category-chooser");
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
await categoryChooser.expand();
|
||||
|
||||
assert.ok(categoryChooser.rowByIndex(0).name() !== "uncategorized");
|
||||
});
|
||||
|
||||
test("prefill category when category_id is set", async (assert) => {
|
||||
await visit("/new-topic?category_id=1");
|
||||
|
||||
assert.equal(selectKit(".category-chooser").header().value(), 1);
|
||||
});
|
||||
@ -1,11 +1,12 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Category Edit - security", {
|
||||
loggedIn: true,
|
||||
});
|
||||
|
||||
QUnit.test("default", async (assert) => {
|
||||
test("default", async (assert) => {
|
||||
await visit("/c/bug");
|
||||
|
||||
await click(".edit-category");
|
||||
@ -20,7 +21,7 @@ QUnit.test("default", async (assert) => {
|
||||
assert.equal(permission, "Create / Reply / See");
|
||||
});
|
||||
|
||||
QUnit.test("removing a permission", async (assert) => {
|
||||
test("removing a permission", async (assert) => {
|
||||
const availableGroups = selectKit(".available-groups");
|
||||
|
||||
await visit("/c/bug");
|
||||
@ -46,7 +47,7 @@ QUnit.test("removing a permission", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("adding a permission", async (assert) => {
|
||||
test("adding a permission", async (assert) => {
|
||||
const availableGroups = selectKit(".available-groups");
|
||||
const permissionSelector = selectKit(".permission-selector");
|
||||
|
||||
@ -72,7 +73,7 @@ QUnit.test("adding a permission", async (assert) => {
|
||||
assert.equal(permission, "Reply / See");
|
||||
});
|
||||
|
||||
QUnit.test("adding a previously removed permission", async (assert) => {
|
||||
test("adding a previously removed permission", async (assert) => {
|
||||
const availableGroups = selectKit(".available-groups");
|
||||
|
||||
await visit("/c/bug");
|
||||
@ -1,13 +1,15 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { skip } from "qunit";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Category Edit", {
|
||||
loggedIn: true,
|
||||
settings: { email_in: true },
|
||||
});
|
||||
|
||||
QUnit.test("Can open the category modal", async (assert) => {
|
||||
test("Can open the category modal", async (assert) => {
|
||||
await visit("/c/bug");
|
||||
|
||||
await click(".edit-category");
|
||||
@ -17,7 +19,7 @@ QUnit.test("Can open the category modal", async (assert) => {
|
||||
assert.ok(!visible(".d-modal"), "it closes the modal");
|
||||
});
|
||||
|
||||
QUnit.test("Editing the category", async (assert) => {
|
||||
test("Editing the category", async (assert) => {
|
||||
await visit("/c/bug");
|
||||
|
||||
await click(".edit-category");
|
||||
@ -46,7 +48,7 @@ QUnit.test("Editing the category", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.skip("Edit the description without loosing progress", async (assert) => {
|
||||
skip("Edit the description without loosing progress", async (assert) => {
|
||||
let win = { focus: function () {} };
|
||||
let windowOpen = sandbox.stub(window, "open").returns(win);
|
||||
sandbox.stub(win, "focus");
|
||||
@ -61,7 +63,7 @@ QUnit.skip("Edit the description without loosing progress", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Error Saving", async (assert) => {
|
||||
test("Error Saving", async (assert) => {
|
||||
await visit("/c/bug");
|
||||
|
||||
await click(".edit-category");
|
||||
@ -72,7 +74,7 @@ QUnit.test("Error Saving", async (assert) => {
|
||||
assert.equal(find("#modal-alert").html(), "duplicate email");
|
||||
});
|
||||
|
||||
QUnit.test("Subcategory list settings", async (assert) => {
|
||||
test("Subcategory list settings", async (assert) => {
|
||||
const categoryChooser = selectKit(
|
||||
".edit-category-tab-general .category-chooser"
|
||||
);
|
||||
@ -1,9 +1,10 @@
|
||||
import pretender from "helpers/create-pretender";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Click Track", {});
|
||||
|
||||
QUnit.test("Do not track mentions", async (assert) => {
|
||||
test("Do not track mentions", async (assert) => {
|
||||
pretender.post("/clicks/track", () => assert.ok(false));
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -1,6 +1,10 @@
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { _clearSnapshots } from "select-kit/components/composer-actions";
|
||||
import { toggleCheckDraftPopup } from "discourse/controllers/composer";
|
||||
import Draft from "discourse/models/draft";
|
||||
@ -14,27 +18,262 @@ acceptance("Composer Actions", {
|
||||
site: {
|
||||
can_tag_topics: true,
|
||||
},
|
||||
pretend(server) {
|
||||
server.get("/t/130.json", () => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{
|
||||
post_stream: {
|
||||
posts: [
|
||||
{
|
||||
id: 133,
|
||||
name: null,
|
||||
username: "bianca",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
created_at: "2020-07-05T09:28:36.371Z",
|
||||
cooked:
|
||||
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas a varius ipsum. Nunc euismod, metus non vulputate malesuada, ligula metus pharetra tortor, vel sodales arcu lacus sed mauris. Nam semper, orci vitae fringilla placerat, dui tellus convallis felis, ultricies laoreet sapien mi et metus. Mauris facilisis, mi fermentum rhoncus feugiat, dolor est vehicula leo, id porta leo ex non enim. In a ligula vel tellus commodo scelerisque non in ex. Pellentesque semper leo quam, nec varius est viverra eget. Donec vehicula sem et massa faucibus tempus.</p>",
|
||||
post_number: 1,
|
||||
post_type: 1,
|
||||
updated_at: "2020-07-05T09:28:36.371Z",
|
||||
reply_count: 0,
|
||||
reply_to_post_number: null,
|
||||
quote_count: 0,
|
||||
incoming_link_count: 0,
|
||||
reads: 1,
|
||||
readers_count: 0,
|
||||
score: 0,
|
||||
yours: true,
|
||||
topic_id: 130,
|
||||
topic_slug: "lorem-ipsum-dolor-sit-amet",
|
||||
display_username: null,
|
||||
primary_group_name: null,
|
||||
primary_group_flair_url: null,
|
||||
primary_group_flair_bg_color: null,
|
||||
primary_group_flair_color: null,
|
||||
version: 1,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
can_recover: false,
|
||||
can_wiki: true,
|
||||
read: true,
|
||||
user_title: "Tester",
|
||||
title_is_group: false,
|
||||
actions_summary: [
|
||||
{
|
||||
id: 3,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
can_act: true,
|
||||
},
|
||||
],
|
||||
moderator: false,
|
||||
admin: true,
|
||||
staff: true,
|
||||
user_id: 1,
|
||||
hidden: false,
|
||||
trust_level: 0,
|
||||
deleted_at: null,
|
||||
user_deleted: false,
|
||||
edit_reason: null,
|
||||
can_view_edit_history: true,
|
||||
wiki: false,
|
||||
reviewable_id: 0,
|
||||
reviewable_score_count: 0,
|
||||
reviewable_score_pending_count: 0,
|
||||
},
|
||||
],
|
||||
stream: [133],
|
||||
},
|
||||
timeline_lookup: [[1, 0]],
|
||||
related_messages: [],
|
||||
suggested_topics: [],
|
||||
id: 130,
|
||||
title: "Lorem ipsum dolor sit amet",
|
||||
fancy_title: "Lorem ipsum dolor sit amet",
|
||||
posts_count: 1,
|
||||
created_at: "2020-07-05T09:28:36.260Z",
|
||||
views: 1,
|
||||
reply_count: 0,
|
||||
like_count: 0,
|
||||
last_posted_at: "2020-07-05T09:28:36.371Z",
|
||||
visible: true,
|
||||
closed: false,
|
||||
archived: false,
|
||||
has_summary: false,
|
||||
archetype: "private_message",
|
||||
slug: "lorem-ipsum-dolor-sit-amet",
|
||||
category_id: null,
|
||||
word_count: 86,
|
||||
deleted_at: null,
|
||||
user_id: 1,
|
||||
featured_link: null,
|
||||
pinned_globally: false,
|
||||
pinned_at: null,
|
||||
pinned_until: null,
|
||||
image_url: null,
|
||||
draft: null,
|
||||
draft_key: "topic_130",
|
||||
draft_sequence: 0,
|
||||
posted: true,
|
||||
unpinned: null,
|
||||
pinned: false,
|
||||
current_post_number: 1,
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: 1,
|
||||
last_read_post_id: 133,
|
||||
deleted_by: null,
|
||||
has_deleted: false,
|
||||
actions_summary: [
|
||||
{
|
||||
id: 4,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
],
|
||||
chunk_size: 20,
|
||||
bookmarked: false,
|
||||
message_archived: false,
|
||||
topic_timer: null,
|
||||
message_bus_last_id: 5,
|
||||
participant_count: 1,
|
||||
pm_with_non_human_user: false,
|
||||
show_read_indicator: false,
|
||||
requested_group_name: null,
|
||||
thumbnails: null,
|
||||
tags_disable_ads: false,
|
||||
details: {
|
||||
notification_level: 3,
|
||||
notifications_reason_id: 1,
|
||||
can_move_posts: true,
|
||||
can_edit: true,
|
||||
can_delete: true,
|
||||
can_remove_allowed_users: true,
|
||||
can_invite_to: true,
|
||||
can_invite_via_email: true,
|
||||
can_create_post: true,
|
||||
can_reply_as_new_topic: true,
|
||||
can_flag_topic: true,
|
||||
can_convert_topic: true,
|
||||
can_review_topic: true,
|
||||
can_remove_self_id: 1,
|
||||
participants: [
|
||||
{
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
post_count: 1,
|
||||
primary_group_name: null,
|
||||
primary_group_flair_url: null,
|
||||
primary_group_flair_color: null,
|
||||
primary_group_flair_bg_color: null,
|
||||
},
|
||||
],
|
||||
allowed_users: [
|
||||
{
|
||||
id: 7,
|
||||
username: "foo",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/f/b19c9b/{size}.png",
|
||||
},
|
||||
],
|
||||
created_by: {
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
},
|
||||
last_poster: {
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
},
|
||||
allowed_groups: [
|
||||
{
|
||||
id: 43,
|
||||
automatic: false,
|
||||
name: "foo_group",
|
||||
user_count: 4,
|
||||
mentionable_level: 0,
|
||||
messageable_level: 99,
|
||||
visibility_level: 0,
|
||||
automatic_membership_email_domains: "",
|
||||
primary_group: false,
|
||||
title: null,
|
||||
grant_trust_level: null,
|
||||
incoming_email: null,
|
||||
has_messages: true,
|
||||
flair_url: null,
|
||||
flair_bg_color: "",
|
||||
flair_color: "",
|
||||
bio_raw: null,
|
||||
bio_cooked: null,
|
||||
bio_excerpt: null,
|
||||
public_admission: false,
|
||||
public_exit: false,
|
||||
allow_membership_requests: false,
|
||||
full_name: null,
|
||||
default_notification_level: 3,
|
||||
membership_request_template: null,
|
||||
members_visibility_level: 0,
|
||||
can_see_members: true,
|
||||
publish_read_state: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"creating new topic and then reply_as_private_message keeps attributes",
|
||||
async (assert) => {
|
||||
await visit("/");
|
||||
await click("button#create-topic");
|
||||
test("creating new topic and then reply_as_private_message keeps attributes", async (assert) => {
|
||||
await visit("/");
|
||||
await click("button#create-topic");
|
||||
|
||||
await fillIn("#reply-title", "this is the title");
|
||||
await fillIn(".d-editor-input", "this is the reply");
|
||||
await fillIn("#reply-title", "this is the title");
|
||||
await fillIn(".d-editor-input", "this is the reply");
|
||||
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_private_message");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_private_message");
|
||||
|
||||
assert.ok(find("#reply-title").val(), "this is the title");
|
||||
assert.ok(find(".d-editor-input").val(), "this is the reply");
|
||||
}
|
||||
);
|
||||
assert.ok(find("#reply-title").val(), "this is the title");
|
||||
assert.ok(find(".d-editor-input").val(), "this is the reply");
|
||||
});
|
||||
|
||||
QUnit.test("replying to post", async (assert) => {
|
||||
test("replying to post", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -52,7 +291,7 @@ QUnit.test("replying to post", async (assert) => {
|
||||
assert.equal(composerActions.rowByIndex(5).value(), undefined);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - reply_as_private_message", async (assert) => {
|
||||
test("replying to post - reply_as_private_message", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -67,7 +306,7 @@ QUnit.test("replying to post - reply_as_private_message", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - reply_to_topic", async (assert) => {
|
||||
test("replying to post - reply_to_topic", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -94,7 +333,7 @@ QUnit.test("replying to post - reply_to_topic", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - toggle_whisper", async (assert) => {
|
||||
test("replying to post - toggle_whisper", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -112,7 +351,7 @@ QUnit.test("replying to post - toggle_whisper", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - reply_as_new_topic", async (assert) => {
|
||||
test("replying to post - reply_as_new_topic", async (assert) => {
|
||||
sandbox
|
||||
.stub(Draft, "get")
|
||||
.returns(Promise.resolve({ draft: "", draft_sequence: 0 }));
|
||||
@ -143,7 +382,7 @@ QUnit.test("replying to post - reply_as_new_topic", async (assert) => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
QUnit.test("reply_as_new_topic without a new_topic draft", async (assert) => {
|
||||
test("reply_as_new_topic without a new_topic draft", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".create.reply");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
@ -152,245 +391,7 @@ QUnit.test("reply_as_new_topic without a new_topic draft", async (assert) => {
|
||||
assert.equal(exists(find(".bootbox")), false);
|
||||
});
|
||||
|
||||
QUnit.test("reply_as_new_group_message", async (assert) => {
|
||||
// eslint-disable-next-line
|
||||
server.get("/t/130.json", () => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
{
|
||||
post_stream: {
|
||||
posts: [
|
||||
{
|
||||
id: 133,
|
||||
name: null,
|
||||
username: "bianca",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
created_at: "2020-07-05T09:28:36.371Z",
|
||||
cooked:
|
||||
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas a varius ipsum. Nunc euismod, metus non vulputate malesuada, ligula metus pharetra tortor, vel sodales arcu lacus sed mauris. Nam semper, orci vitae fringilla placerat, dui tellus convallis felis, ultricies laoreet sapien mi et metus. Mauris facilisis, mi fermentum rhoncus feugiat, dolor est vehicula leo, id porta leo ex non enim. In a ligula vel tellus commodo scelerisque non in ex. Pellentesque semper leo quam, nec varius est viverra eget. Donec vehicula sem et massa faucibus tempus.</p>",
|
||||
post_number: 1,
|
||||
post_type: 1,
|
||||
updated_at: "2020-07-05T09:28:36.371Z",
|
||||
reply_count: 0,
|
||||
reply_to_post_number: null,
|
||||
quote_count: 0,
|
||||
incoming_link_count: 0,
|
||||
reads: 1,
|
||||
readers_count: 0,
|
||||
score: 0,
|
||||
yours: true,
|
||||
topic_id: 130,
|
||||
topic_slug: "lorem-ipsum-dolor-sit-amet",
|
||||
display_username: null,
|
||||
primary_group_name: null,
|
||||
primary_group_flair_url: null,
|
||||
primary_group_flair_bg_color: null,
|
||||
primary_group_flair_color: null,
|
||||
version: 1,
|
||||
can_edit: true,
|
||||
can_delete: false,
|
||||
can_recover: false,
|
||||
can_wiki: true,
|
||||
read: true,
|
||||
user_title: "Tester",
|
||||
title_is_group: false,
|
||||
actions_summary: [
|
||||
{
|
||||
id: 3,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
can_act: true,
|
||||
},
|
||||
],
|
||||
moderator: false,
|
||||
admin: true,
|
||||
staff: true,
|
||||
user_id: 1,
|
||||
hidden: false,
|
||||
trust_level: 0,
|
||||
deleted_at: null,
|
||||
user_deleted: false,
|
||||
edit_reason: null,
|
||||
can_view_edit_history: true,
|
||||
wiki: false,
|
||||
reviewable_id: 0,
|
||||
reviewable_score_count: 0,
|
||||
reviewable_score_pending_count: 0,
|
||||
},
|
||||
],
|
||||
stream: [133],
|
||||
},
|
||||
timeline_lookup: [[1, 0]],
|
||||
related_messages: [],
|
||||
suggested_topics: [],
|
||||
id: 130,
|
||||
title: "Lorem ipsum dolor sit amet",
|
||||
fancy_title: "Lorem ipsum dolor sit amet",
|
||||
posts_count: 1,
|
||||
created_at: "2020-07-05T09:28:36.260Z",
|
||||
views: 1,
|
||||
reply_count: 0,
|
||||
like_count: 0,
|
||||
last_posted_at: "2020-07-05T09:28:36.371Z",
|
||||
visible: true,
|
||||
closed: false,
|
||||
archived: false,
|
||||
has_summary: false,
|
||||
archetype: "private_message",
|
||||
slug: "lorem-ipsum-dolor-sit-amet",
|
||||
category_id: null,
|
||||
word_count: 86,
|
||||
deleted_at: null,
|
||||
user_id: 1,
|
||||
featured_link: null,
|
||||
pinned_globally: false,
|
||||
pinned_at: null,
|
||||
pinned_until: null,
|
||||
image_url: null,
|
||||
draft: null,
|
||||
draft_key: "topic_130",
|
||||
draft_sequence: 0,
|
||||
posted: true,
|
||||
unpinned: null,
|
||||
pinned: false,
|
||||
current_post_number: 1,
|
||||
highest_post_number: 1,
|
||||
last_read_post_number: 1,
|
||||
last_read_post_id: 133,
|
||||
deleted_by: null,
|
||||
has_deleted: false,
|
||||
actions_summary: [
|
||||
{
|
||||
id: 4,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
count: 0,
|
||||
hidden: false,
|
||||
can_act: true,
|
||||
},
|
||||
],
|
||||
chunk_size: 20,
|
||||
bookmarked: false,
|
||||
message_archived: false,
|
||||
topic_timer: null,
|
||||
message_bus_last_id: 5,
|
||||
participant_count: 1,
|
||||
pm_with_non_human_user: false,
|
||||
show_read_indicator: false,
|
||||
requested_group_name: null,
|
||||
thumbnails: null,
|
||||
tags_disable_ads: false,
|
||||
details: {
|
||||
notification_level: 3,
|
||||
notifications_reason_id: 1,
|
||||
can_move_posts: true,
|
||||
can_edit: true,
|
||||
can_delete: true,
|
||||
can_remove_allowed_users: true,
|
||||
can_invite_to: true,
|
||||
can_invite_via_email: true,
|
||||
can_create_post: true,
|
||||
can_reply_as_new_topic: true,
|
||||
can_flag_topic: true,
|
||||
can_convert_topic: true,
|
||||
can_review_topic: true,
|
||||
can_remove_self_id: 1,
|
||||
participants: [
|
||||
{
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
post_count: 1,
|
||||
primary_group_name: null,
|
||||
primary_group_flair_url: null,
|
||||
primary_group_flair_color: null,
|
||||
primary_group_flair_bg_color: null,
|
||||
},
|
||||
],
|
||||
allowed_users: [
|
||||
{
|
||||
id: 7,
|
||||
username: "foo",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/f/b19c9b/{size}.png",
|
||||
},
|
||||
],
|
||||
created_by: {
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
},
|
||||
last_poster: {
|
||||
id: 1,
|
||||
username: "bianca",
|
||||
name: null,
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png",
|
||||
},
|
||||
allowed_groups: [
|
||||
{
|
||||
id: 43,
|
||||
automatic: false,
|
||||
name: "foo_group",
|
||||
user_count: 4,
|
||||
mentionable_level: 0,
|
||||
messageable_level: 99,
|
||||
visibility_level: 0,
|
||||
automatic_membership_email_domains: "",
|
||||
primary_group: false,
|
||||
title: null,
|
||||
grant_trust_level: null,
|
||||
incoming_email: null,
|
||||
has_messages: true,
|
||||
flair_url: null,
|
||||
flair_bg_color: "",
|
||||
flair_color: "",
|
||||
bio_raw: null,
|
||||
bio_cooked: null,
|
||||
bio_excerpt: null,
|
||||
public_admission: false,
|
||||
public_exit: false,
|
||||
allow_membership_requests: false,
|
||||
full_name: null,
|
||||
default_notification_level: 3,
|
||||
membership_request_template: null,
|
||||
members_visibility_level: 0,
|
||||
can_see_members: true,
|
||||
publish_read_state: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
test("reply_as_new_group_message", async (assert) => {
|
||||
await visit("/t/lorem-ipsum-dolor-sit-amet/130");
|
||||
await click(".create.reply");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
@ -405,7 +406,7 @@ QUnit.test("reply_as_new_group_message", async (assert) => {
|
||||
assert.deepEqual(items, ["foo", "foo_group"]);
|
||||
});
|
||||
|
||||
QUnit.test("hide component if no content", async (assert) => {
|
||||
test("hide component if no content", async (assert) => {
|
||||
await visit("/");
|
||||
await click("button#create-topic");
|
||||
|
||||
@ -421,7 +422,7 @@ QUnit.test("hide component if no content", async (assert) => {
|
||||
assert.equal(composerActions.rows().length, 2);
|
||||
});
|
||||
|
||||
QUnit.test("interactions", async (assert) => {
|
||||
test("interactions", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
const quote = "Life is like riding a bicycle.";
|
||||
|
||||
@ -498,7 +499,7 @@ QUnit.test("interactions", async (assert) => {
|
||||
assert.equal(composerActions.rows().length, 3);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post - toggle_topic_bump", async (assert) => {
|
||||
test("replying to post - toggle_topic_bump", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -526,7 +527,7 @@ QUnit.test("replying to post - toggle_topic_bump", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("replying to post as staff", async (assert) => {
|
||||
test("replying to post as staff", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ admin: true });
|
||||
@ -538,7 +539,7 @@ QUnit.test("replying to post as staff", async (assert) => {
|
||||
assert.equal(composerActions.rowByIndex(4).value(), "toggle_topic_bump");
|
||||
});
|
||||
|
||||
QUnit.test("replying to post as TL3 user", async (assert) => {
|
||||
test("replying to post as TL3 user", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 3 });
|
||||
@ -556,7 +557,7 @@ QUnit.test("replying to post as TL3 user", async (assert) => {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("replying to post as TL4 user", async (assert) => {
|
||||
test("replying to post as TL4 user", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
|
||||
@ -568,25 +569,22 @@ QUnit.test("replying to post as TL4 user", async (assert) => {
|
||||
assert.equal(composerActions.rowByIndex(3).value(), "toggle_topic_bump");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"replying to first post - reply_as_private_message",
|
||||
async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
test("replying to first post - reply_as_private_message", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_1 button.reply");
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("article#post_1 button.reply");
|
||||
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_private_message");
|
||||
await composerActions.expand();
|
||||
await composerActions.selectRowByValue("reply_as_private_message");
|
||||
|
||||
assert.equal(find(".users-input .item:eq(0)").text(), "uwe_keim");
|
||||
assert.ok(
|
||||
find(".d-editor-input").val().indexOf("Continuing the discussion") >= 0
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.equal(find(".users-input .item:eq(0)").text(), "uwe_keim");
|
||||
assert.ok(
|
||||
find(".d-editor-input").val().indexOf("Continuing the discussion") >= 0
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("editing post", async (assert) => {
|
||||
test("editing post", async (assert) => {
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -624,7 +622,7 @@ const stubDraftResponse = () => {
|
||||
);
|
||||
};
|
||||
|
||||
QUnit.test("shared draft", async (assert) => {
|
||||
test("shared draft", async (assert) => {
|
||||
stubDraftResponse();
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
@ -666,7 +664,7 @@ QUnit.test("shared draft", async (assert) => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
QUnit.test("reply_as_new_topic with new_topic draft", async (assert) => {
|
||||
test("reply_as_new_topic with new_topic draft", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".create.reply");
|
||||
const composerActions = selectKit(".composer-actions");
|
||||
@ -1,4 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
function setupPretender(server, helper) {
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
@ -33,7 +34,7 @@ acceptance("Composer Attachment", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("attachments are cooked properly", async (assert) => {
|
||||
test("attachments are cooked properly", async (assert) => {
|
||||
await writeInComposer(assert);
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible").html().trim(),
|
||||
@ -51,13 +52,10 @@ acceptance("Composer Attachment - Secure Media Enabled", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"attachments are cooked properly when secure media is enabled",
|
||||
async (assert) => {
|
||||
await writeInComposer(assert);
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible").html().trim(),
|
||||
'<p><a class="attachment" href="/secure-media-uploads/default/3X/1/asjdiasjdiasida.png">test</a></p>'
|
||||
);
|
||||
}
|
||||
);
|
||||
test("attachments are cooked properly when secure media is enabled", async (assert) => {
|
||||
await writeInComposer(assert);
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible").html().trim(),
|
||||
'<p><a class="attachment" href="/secure-media-uploads/default/3X/1/asjdiasjdiasida.png">test</a></p>'
|
||||
);
|
||||
});
|
||||
@ -1,12 +1,13 @@
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import pretender from "helpers/create-pretender";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
|
||||
acceptance("Composer - Edit conflict", {
|
||||
loggedIn: true,
|
||||
});
|
||||
|
||||
QUnit.test("Edit a post that causes an edit conflict", async (assert) => {
|
||||
test("Edit a post that causes an edit conflict", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:eq(0) button.show-more-actions");
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
@ -47,21 +48,18 @@ function handleDraftPretender(assert) {
|
||||
});
|
||||
}
|
||||
|
||||
QUnit.test(
|
||||
"Should not send originalText when posting a new reply",
|
||||
async (assert) => {
|
||||
handleDraftPretender(assert);
|
||||
test("Should not send originalText when posting a new reply", async (assert) => {
|
||||
handleDraftPretender(assert);
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(
|
||||
".d-editor-input",
|
||||
"hello world hello world hello world hello world hello world"
|
||||
);
|
||||
}
|
||||
);
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(
|
||||
".d-editor-input",
|
||||
"hello world hello world hello world hello world hello world"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Should send originalText when editing a reply", async (assert) => {
|
||||
test("Should send originalText when editing a reply", async (assert) => {
|
||||
handleDraftPretender(assert);
|
||||
|
||||
await visit("/t/internationalization-localization/280");
|
||||
@ -1,10 +1,11 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Composer - Hyperlink", {
|
||||
loggedIn: true,
|
||||
});
|
||||
|
||||
QUnit.test("add a hyperlink to a reply", async (assert) => {
|
||||
test("add a hyperlink to a reply", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click(".topic-post:first-child button.reply");
|
||||
await fillIn(".d-editor-input", "This is a link to ");
|
||||
@ -23,8 +24,8 @@ QUnit.test("add a hyperlink to a reply", async (assert) => {
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"This is a link to [Google](http://google.com)",
|
||||
"adds link with url and text, prepends 'http://'"
|
||||
"This is a link to [Google](https://google.com)",
|
||||
"adds link with url and text, prepends 'https://'"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
@ -42,7 +43,7 @@ QUnit.test("add a hyperlink to a reply", async (assert) => {
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"Reset textarea contents.",
|
||||
"adds link with url and text, prepends 'http://'"
|
||||
"doesn’t insert anything after cancelling"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
@ -60,7 +61,7 @@ QUnit.test("add a hyperlink to a reply", async (assert) => {
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"[Reset](http://somelink.com) textarea contents.",
|
||||
"[Reset](https://somelink.com) textarea contents.",
|
||||
"adds link to a selected text"
|
||||
);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Composer - Onebox", {
|
||||
loggedIn: true,
|
||||
@ -8,15 +9,13 @@ acceptance("Composer - Onebox", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Preview update should respect max_oneboxes_per_post site setting",
|
||||
async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
test("Preview update should respect max_oneboxes_per_post site setting", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
await fillIn(
|
||||
".d-editor-input",
|
||||
`
|
||||
await fillIn(
|
||||
".d-editor-input",
|
||||
`
|
||||
http://www.example.com/has-title.html
|
||||
This is another test http://www.example.com/has-title.html
|
||||
|
||||
@ -27,11 +26,11 @@ This is another test http://www.example.com/has-title.html
|
||||
|
||||
http://www.example.com/has-title.html
|
||||
`
|
||||
);
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible").html().trim(),
|
||||
`
|
||||
assert.equal(
|
||||
find(".d-editor-preview:visible").html().trim(),
|
||||
`
|
||||
<p><aside class=\"onebox\"><article class=\"onebox-body\"><h3><a href=\"http://www.example.com/article.html\">An interesting article</a></h3></article></aside><br>
|
||||
This is another test <a href=\"http://www.example.com/has-title.html\" class=\"inline-onebox\">This is a great title</a></p>
|
||||
<p><a href=\"http://www.example.com/no-title.html\" class=\"onebox\" target=\"_blank\">http://www.example.com/no-title.html</a></p>
|
||||
@ -39,6 +38,5 @@ This is another test <a href=\"http://www.example.com/has-title.html\" class=\"i
|
||||
This is another test <a href=\"http://www.example.com/has-title.html\" class=\"inline-onebox\">This is a great title</a></p>
|
||||
<p><aside class=\"onebox\"><article class=\"onebox-body\"><h3><a href=\"http://www.example.com/article.html\">An interesting article</a></h3></article></aside></p>
|
||||
`.trim()
|
||||
);
|
||||
}
|
||||
);
|
||||
);
|
||||
});
|
||||
@ -1,6 +1,10 @@
|
||||
import { test } from "qunit";
|
||||
import Category from "discourse/models/category";
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
acceptance("Composer - Tags", {
|
||||
loggedIn: true,
|
||||
@ -14,7 +18,7 @@ acceptance("Composer - Tags", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("staff bypass tag validation rule", async (assert) => {
|
||||
test("staff bypass tag validation rule", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
@ -31,7 +35,7 @@ QUnit.test("staff bypass tag validation rule", async (assert) => {
|
||||
assert.notEqual(currentURL(), "/");
|
||||
});
|
||||
|
||||
QUnit.test("users do not bypass tag validation rule", async (assert) => {
|
||||
test("users do not bypass tag validation rule", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import { skip } from "qunit";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import { run } from "@ember/runloop";
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { toggleCheckDraftPopup } from "discourse/controllers/composer";
|
||||
import Draft from "discourse/models/draft";
|
||||
import { Promise } from "rsvp";
|
||||
|
||||
acceptance("Composer", {
|
||||
loggedIn: true,
|
||||
pretend(pretenderServer, helper) {
|
||||
pretenderServer.post("/uploads/lookup-urls", () => {
|
||||
pretend(server, helper) {
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
},
|
||||
@ -18,7 +20,7 @@ acceptance("Composer", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.skip("Tests the Composer controls", async (assert) => {
|
||||
skip("Tests the Composer controls", async (assert) => {
|
||||
await visit("/");
|
||||
assert.ok(exists("#create-topic"), "the create button is visible");
|
||||
|
||||
@ -96,7 +98,7 @@ QUnit.skip("Tests the Composer controls", async (assert) => {
|
||||
assert.ok(!exists(".bootbox.modal"), "the confirmation can be cancelled");
|
||||
});
|
||||
|
||||
QUnit.test("Composer upload placeholder", async (assert) => {
|
||||
test("Composer upload placeholder", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
@ -189,7 +191,7 @@ QUnit.test("Composer upload placeholder", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Create a topic with server side errors", async (assert) => {
|
||||
test("Create a topic with server side errors", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "this title triggers an error");
|
||||
@ -201,7 +203,7 @@ QUnit.test("Create a topic with server side errors", async (assert) => {
|
||||
assert.ok(exists(".d-editor-input"), "the composer input is visible");
|
||||
});
|
||||
|
||||
QUnit.test("Create a Topic", async (assert) => {
|
||||
test("Create a Topic", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "Internationalization Localization");
|
||||
@ -214,7 +216,7 @@ QUnit.test("Create a Topic", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Create an enqueued Topic", async (assert) => {
|
||||
test("Create an enqueued Topic", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "Internationalization Localization");
|
||||
@ -227,7 +229,7 @@ QUnit.test("Create an enqueued Topic", async (assert) => {
|
||||
assert.ok(invisible(".d-modal"), "the modal can be dismissed");
|
||||
});
|
||||
|
||||
QUnit.test("Can display a message and route to a URL", async (assert) => {
|
||||
test("Can display a message and route to a URL", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "This title doesn't matter");
|
||||
@ -247,7 +249,7 @@ QUnit.test("Can display a message and route to a URL", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Create a Reply", async (assert) => {
|
||||
test("Create a Reply", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.ok(
|
||||
@ -267,7 +269,7 @@ QUnit.test("Create a Reply", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Can edit a post after starting a reply", async (assert) => {
|
||||
test("Can edit a post after starting a reply", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
await click("#topic-footer-buttons .create");
|
||||
@ -285,7 +287,7 @@ QUnit.test("Can edit a post after starting a reply", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Posting on a different topic", async (assert) => {
|
||||
test("Posting on a different topic", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
await fillIn(".d-editor-input", "this is the content for a different topic");
|
||||
@ -302,7 +304,7 @@ QUnit.test("Posting on a different topic", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Create an enqueued Reply", async (assert) => {
|
||||
test("Create an enqueued Reply", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.notOk(find(".pending-posts .reviewable-item").length);
|
||||
@ -326,7 +328,7 @@ QUnit.test("Create an enqueued Reply", async (assert) => {
|
||||
assert.ok(find(".pending-posts .reviewable-item").length);
|
||||
});
|
||||
|
||||
QUnit.test("Edit the first post", async (assert) => {
|
||||
test("Edit the first post", async (assert) => {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.ok(
|
||||
@ -364,7 +366,7 @@ QUnit.test("Edit the first post", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Composer can switch between edits", async (assert) => {
|
||||
test("Composer can switch between edits", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
@ -381,26 +383,23 @@ QUnit.test("Composer can switch between edits", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer with dirty edit can toggle to another edit",
|
||||
async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
test("Composer with dirty edit can toggle to another edit", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".topic-post:eq(1) button.edit");
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".topic-post:eq(1) button.edit");
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
|
||||
await click(".modal-footer a:eq(0)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().indexOf("This is the second post."),
|
||||
0,
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
}
|
||||
);
|
||||
await click(".modal-footer a:eq(0)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().indexOf("This is the second post."),
|
||||
0,
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Composer can toggle between edit and reply", async (assert) => {
|
||||
test("Composer can toggle between edit and reply", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.edit");
|
||||
@ -419,7 +418,7 @@ QUnit.test("Composer can toggle between edit and reply", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Composer can toggle whispers", async (assert) => {
|
||||
test("Composer can toggle whispers", async (assert) => {
|
||||
const menu = selectKit(".toolbar-popup-menu-options");
|
||||
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
@ -454,98 +453,91 @@ QUnit.test("Composer can toggle whispers", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer can toggle layouts (open, fullscreen and draft)",
|
||||
async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
test("Composer can toggle layouts (open, fullscreen and draft)", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"it starts in open state by default"
|
||||
);
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"it starts in open state by default"
|
||||
);
|
||||
|
||||
await click(".toggle-fullscreen");
|
||||
await click(".toggle-fullscreen");
|
||||
|
||||
assert.ok(
|
||||
find("#reply-control.fullscreen").length === 1,
|
||||
"it expands composer to full screen"
|
||||
);
|
||||
assert.ok(
|
||||
find("#reply-control.fullscreen").length === 1,
|
||||
"it expands composer to full screen"
|
||||
);
|
||||
|
||||
await click(".toggle-fullscreen");
|
||||
await click(".toggle-fullscreen");
|
||||
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"it collapses composer to regular size"
|
||||
);
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"it collapses composer to regular size"
|
||||
);
|
||||
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".toggler");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".toggler");
|
||||
|
||||
assert.ok(
|
||||
find("#reply-control.draft").length === 1,
|
||||
"it collapses composer to draft bar"
|
||||
);
|
||||
assert.ok(
|
||||
find("#reply-control.draft").length === 1,
|
||||
"it collapses composer to draft bar"
|
||||
);
|
||||
|
||||
await click(".toggle-fullscreen");
|
||||
await click(".toggle-fullscreen");
|
||||
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"from draft, it expands composer back to open state"
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.ok(
|
||||
find("#reply-control.open").length === 1,
|
||||
"from draft, it expands composer back to open state"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer can toggle between reply and createTopic",
|
||||
async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
test("Composer can toggle between reply and createTopic", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
|
||||
await selectKit(".toolbar-popup-menu-options").expand();
|
||||
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
|
||||
"toggleWhisper"
|
||||
);
|
||||
await selectKit(".toolbar-popup-menu-options").expand();
|
||||
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
|
||||
"toggleWhisper"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1,
|
||||
"it sets the post type to whisper"
|
||||
);
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 1,
|
||||
"it sets the post type to whisper"
|
||||
);
|
||||
|
||||
await visit("/");
|
||||
assert.ok(exists("#create-topic"), "the create topic button is visible");
|
||||
await visit("/");
|
||||
assert.ok(exists("#create-topic"), "the create topic button is visible");
|
||||
|
||||
await click("#create-topic");
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
|
||||
"it should reset the state of the composer's model"
|
||||
);
|
||||
await click("#create-topic");
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper .d-icon-far-eye-slash").length === 0,
|
||||
"it should reset the state of the composer's model"
|
||||
);
|
||||
|
||||
await selectKit(".toolbar-popup-menu-options").expand();
|
||||
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
|
||||
"toggleInvisible"
|
||||
);
|
||||
await selectKit(".toolbar-popup-menu-options").expand();
|
||||
await selectKit(".toolbar-popup-menu-options").selectRowByValue(
|
||||
"toggleInvisible"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
find(".composer-fields .unlist")
|
||||
.text()
|
||||
.indexOf(I18n.t("composer.unlist")) > 0,
|
||||
"it sets the topic to unlisted"
|
||||
);
|
||||
assert.ok(
|
||||
find(".composer-fields .unlist").text().indexOf(I18n.t("composer.unlist")) >
|
||||
0,
|
||||
"it sets the topic to unlisted"
|
||||
);
|
||||
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper")
|
||||
.text()
|
||||
.indexOf(I18n.t("composer.unlist")) === -1,
|
||||
"it should reset the state of the composer's model"
|
||||
);
|
||||
}
|
||||
);
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
assert.ok(
|
||||
find(".composer-fields .whisper")
|
||||
.text()
|
||||
.indexOf(I18n.t("composer.unlist")) === -1,
|
||||
"it should reset the state of the composer's model"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Composer with dirty reply can toggle to edit", async (assert) => {
|
||||
test("Composer with dirty reply can toggle to edit", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
@ -560,55 +552,49 @@ QUnit.test("Composer with dirty reply can toggle to edit", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer draft with dirty reply can toggle to edit",
|
||||
async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
test("Composer draft with dirty reply can toggle to edit", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".toggler");
|
||||
await click(".topic-post:eq(1) button.edit");
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
assert.equal(
|
||||
find(".modal-footer a:eq(1)").text(),
|
||||
I18n.t("post.abandon.no_value")
|
||||
);
|
||||
await click(".modal-footer a:eq(0)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().indexOf("This is the second post."),
|
||||
0,
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
}
|
||||
);
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".toggler");
|
||||
await click(".topic-post:eq(1) button.edit");
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
assert.equal(
|
||||
find(".modal-footer a:eq(1)").text(),
|
||||
I18n.t("post.abandon.no_value")
|
||||
);
|
||||
await click(".modal-footer a:eq(0)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().indexOf("This is the second post."),
|
||||
0,
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Composer draft can switch to draft in new context without destroying current draft",
|
||||
async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
test("Composer draft can switch to draft in new context without destroying current draft", async (assert) => {
|
||||
await visit("/t/this-is-a-test-topic/9");
|
||||
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "This is a dirty reply");
|
||||
|
||||
await click("#site-logo");
|
||||
await click("#create-topic");
|
||||
await click("#site-logo");
|
||||
await click("#create-topic");
|
||||
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
assert.equal(
|
||||
find(".modal-footer a:eq(1)").text(),
|
||||
I18n.t("post.abandon.no_save_draft")
|
||||
);
|
||||
await click(".modal-footer a:eq(1)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"",
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog");
|
||||
assert.equal(
|
||||
find(".modal-footer a:eq(1)").text(),
|
||||
I18n.t("post.abandon.no_save_draft")
|
||||
);
|
||||
await click(".modal-footer a:eq(1)");
|
||||
assert.equal(
|
||||
find(".d-editor-input").val(),
|
||||
"",
|
||||
"it populates the input with the post text"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Checks for existing draft", async (assert) => {
|
||||
test("Checks for existing draft", async (assert) => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
@ -625,7 +611,7 @@ QUnit.test("Checks for existing draft", async (assert) => {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("Can switch states without abandon popup", async (assert) => {
|
||||
test("Can switch states without abandon popup", async (assert) => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
@ -673,7 +659,7 @@ QUnit.test("Can switch states without abandon popup", async (assert) => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
QUnit.test("Loading draft also replaces the recipients", async (assert) => {
|
||||
test("Loading draft also replaces the recipients", async (assert) => {
|
||||
try {
|
||||
toggleCheckDraftPopup(true);
|
||||
|
||||
@ -695,24 +681,21 @@ QUnit.test("Loading draft also replaces the recipients", async (assert) => {
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"Deleting the text content of the first post in a private message",
|
||||
async (assert) => {
|
||||
await visit("/t/34");
|
||||
test("Deleting the text content of the first post in a private message", async (assert) => {
|
||||
await visit("/t/34");
|
||||
|
||||
await click("#post_1 .d-icon-ellipsis-h");
|
||||
await click("#post_1 .d-icon-ellipsis-h");
|
||||
|
||||
await click("#post_1 .d-icon-pencil-alt");
|
||||
await click("#post_1 .d-icon-pencil-alt");
|
||||
|
||||
await fillIn(".d-editor-input", "");
|
||||
await fillIn(".d-editor-input", "");
|
||||
|
||||
assert.equal(
|
||||
find(".d-editor-container textarea").attr("placeholder"),
|
||||
I18n.t("composer.reply_placeholder"),
|
||||
"it should not block because of missing category"
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.equal(
|
||||
find(".d-editor-container textarea").attr("placeholder"),
|
||||
I18n.t("composer.reply_placeholder"),
|
||||
"it should not block because of missing category"
|
||||
);
|
||||
});
|
||||
|
||||
const assertImageResized = (assert, uploads) => {
|
||||
assert.equal(
|
||||
@ -722,7 +705,7 @@ const assertImageResized = (assert, uploads) => {
|
||||
);
|
||||
};
|
||||
|
||||
QUnit.test("Image resizing buttons", async (assert) => {
|
||||
test("Image resizing buttons", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
|
||||
@ -827,20 +810,3 @@ QUnit.test("Image resizing buttons", async (assert) => {
|
||||
"it does not unescapes script tags in code blocks"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("can reply to a private message", async (assert) => {
|
||||
let submitted;
|
||||
|
||||
/* global server */
|
||||
server.post("/posts", () => {
|
||||
submitted = true;
|
||||
return [200, { "Content-Type": "application/json" }, {}];
|
||||
});
|
||||
|
||||
await visit("/t/34");
|
||||
await click(".topic-post:eq(0) button.reply");
|
||||
await fillIn(".d-editor-input", "this is the *content* of the reply");
|
||||
await click("#reply-control button.create");
|
||||
|
||||
assert.ok(submitted);
|
||||
});
|
||||
@ -1,4 +1,8 @@
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import {
|
||||
acceptance,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Composer topic featured links", {
|
||||
loggedIn: true,
|
||||
@ -9,7 +13,7 @@ acceptance("Composer topic featured links", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("onebox with title", async (assert) => {
|
||||
test("onebox with title", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "http://www.example.com/has-title.html");
|
||||
@ -28,7 +32,7 @@ QUnit.test("onebox with title", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("onebox result doesn't include a title", async (assert) => {
|
||||
test("onebox result doesn't include a title", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "http://www.example.com/no-title.html");
|
||||
@ -47,7 +51,7 @@ QUnit.test("onebox result doesn't include a title", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("no onebox result", async (assert) => {
|
||||
test("no onebox result", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "http://www.example.com/nope-onebox.html");
|
||||
@ -66,7 +70,7 @@ QUnit.test("no onebox result", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("ignore internal links", async (assert) => {
|
||||
test("ignore internal links", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
const title = "http://" + window.location.hostname + "/internal-page.html";
|
||||
@ -84,7 +88,7 @@ QUnit.test("ignore internal links", async (assert) => {
|
||||
assert.equal(find(".title-input input").val(), title, "title is unchanged");
|
||||
});
|
||||
|
||||
QUnit.test("link is longer than max title length", async (assert) => {
|
||||
test("link is longer than max title length", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn(
|
||||
@ -106,29 +110,26 @@ QUnit.test("link is longer than max title length", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"onebox with title but extra words in title field",
|
||||
async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "http://www.example.com/has-title.html test");
|
||||
assert.equal(
|
||||
find(".d-editor-preview").html().trim().indexOf("onebox"),
|
||||
-1,
|
||||
"onebox preview doesn't show"
|
||||
);
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().length,
|
||||
0,
|
||||
"link isn't put into the post"
|
||||
);
|
||||
assert.equal(
|
||||
find(".title-input input").val(),
|
||||
"http://www.example.com/has-title.html test",
|
||||
"title is unchanged"
|
||||
);
|
||||
}
|
||||
);
|
||||
test("onebox with title but extra words in title field", async (assert) => {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
await fillIn("#reply-title", "http://www.example.com/has-title.html test");
|
||||
assert.equal(
|
||||
find(".d-editor-preview").html().trim().indexOf("onebox"),
|
||||
-1,
|
||||
"onebox preview doesn't show"
|
||||
);
|
||||
assert.equal(
|
||||
find(".d-editor-input").val().length,
|
||||
0,
|
||||
"link isn't put into the post"
|
||||
);
|
||||
assert.equal(
|
||||
find(".title-input input").val(),
|
||||
"http://www.example.com/has-title.html test",
|
||||
"title is unchanged"
|
||||
);
|
||||
});
|
||||
|
||||
acceptance("Composer topic featured links when uncategorized is not allowed", {
|
||||
loggedIn: true,
|
||||
@ -140,7 +141,7 @@ acceptance("Composer topic featured links when uncategorized is not allowed", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("Pasting a link enables the text input area", async (assert) => {
|
||||
test("Pasting a link enables the text input area", async (assert) => {
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
await visit("/");
|
||||
@ -1,5 +1,9 @@
|
||||
import selectKit from "helpers/select-kit-helper";
|
||||
import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance(
|
||||
"Composer disabled, uncategorized not allowed when any topic_template present",
|
||||
@ -12,7 +16,7 @@ acceptance(
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("Disable body until category is selected", async (assert) => {
|
||||
test("Disable body until category is selected", async (assert) => {
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
await visit("/");
|
||||
@ -83,36 +87,33 @@ acceptance(
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"Enable composer/body if no topic templates present",
|
||||
async (assert) => {
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
test("Enable composer/body if no topic templates present", async (assert) => {
|
||||
updateCurrentUser({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
assert.ok(exists(".d-editor-input"), "the composer input is visible");
|
||||
assert.ok(
|
||||
exists(".category-input .popup-tip.bad.hide"),
|
||||
"category errors are hidden by default"
|
||||
);
|
||||
assert.ok(
|
||||
find(".d-editor-textarea-wrapper.disabled").length === 0,
|
||||
"textarea is enabled"
|
||||
);
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
assert.ok(exists(".d-editor-input"), "the composer input is visible");
|
||||
assert.ok(
|
||||
exists(".category-input .popup-tip.bad.hide"),
|
||||
"category errors are hidden by default"
|
||||
);
|
||||
assert.ok(
|
||||
find(".d-editor-textarea-wrapper.disabled").length === 0,
|
||||
"textarea is enabled"
|
||||
);
|
||||
|
||||
await click("#reply-control button.create");
|
||||
assert.ok(
|
||||
exists(".category-input .popup-tip.bad"),
|
||||
"it shows the choose a category error"
|
||||
);
|
||||
await click("#reply-control button.create");
|
||||
assert.ok(
|
||||
exists(".category-input .popup-tip.bad"),
|
||||
"it shows the choose a category error"
|
||||
);
|
||||
|
||||
const categoryChooser = selectKit(".category-chooser");
|
||||
await categoryChooser.expand();
|
||||
await categoryChooser.selectRowByValue(1);
|
||||
const categoryChooser = selectKit(".category-chooser");
|
||||
await categoryChooser.expand();
|
||||
await categoryChooser.selectRowByValue(1);
|
||||
|
||||
assert.ok(
|
||||
!exists(".category-input .popup-tip.bad"),
|
||||
"category error removed after selecting category"
|
||||
);
|
||||
}
|
||||
);
|
||||
assert.ok(
|
||||
!exists(".category-input .popup-tip.bad"),
|
||||
"category error removed after selecting category"
|
||||
);
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Create Account - external auth", {
|
||||
beforeEach() {
|
||||
@ -19,7 +20,7 @@ acceptance("Create Account - external auth", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("when skip is disabled (default)", async (assert) => {
|
||||
test("when skip is disabled (default)", async (assert) => {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
@ -30,7 +31,7 @@ QUnit.test("when skip is disabled (default)", async (assert) => {
|
||||
assert.ok(exists("#new-account-username"), "it shows the fields");
|
||||
});
|
||||
|
||||
QUnit.test("when skip is enabled", async function (assert) {
|
||||
test("when skip is enabled", async function (assert) {
|
||||
this.siteSettings.external_auth_skip_create_confirm = true;
|
||||
await visit("/");
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { acceptance } from "helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
acceptance("Create Account - User Fields", {
|
||||
site: {
|
||||
@ -25,7 +26,7 @@ acceptance("Create Account - User Fields", {
|
||||
},
|
||||
});
|
||||
|
||||
QUnit.test("create account with user fields", async (assert) => {
|
||||
test("create account with user fields", async (assert) => {
|
||||
await visit("/");
|
||||
await click("header .sign-up-button");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user