diff --git a/.gitignore b/.gitignore index 2b3d1fa723..328093d7a0 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,7 @@ bootsnap-compile-cache/ # Ignore plugins except for the bundled ones. /plugins/* -!/plugins/lazyYT/ +!/plugins/lazy-yt/ !/plugins/poll/ !/plugins/discourse-details/ !/plugins/discourse-nginx-performance-report @@ -127,3 +127,6 @@ vendor/bundle/* # Vagrant .vagrant + +# ignore auto-generated plugin js assets +/app/assets/javascripts/plugins/* diff --git a/.rubocop.yml b/.rubocop.yml index 8f24c3fbe8..0d66c3bf6c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,7 +7,7 @@ AllCops: - 'vendor/**/*' - 'node_modules/**/*' - 'public/**/*' - - 'plugins/**/*' + - 'plugins/**/gems/**/*' # Prefer &&/|| over and/or. Style/AndOr: diff --git a/.travis.yml b/.travis.yml index 16534a38cf..c134e72cea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ before_install: - git clone --depth=1 https://github.com/discourse/discourse-chat-integration.git plugins/discourse-chat-integration - git clone --depth=1 https://github.com/discourse/discourse-assign.git plugins/discourse-assign - git clone --depth=1 https://github.com/discourse/discourse-patreon.git plugins/discourse-patreon - - git clone --depth=1 https://github.com/discourse/discourse-staff-notes.git plugins/discourse-staff-notes + - git clone --depth=1 https://github.com/discourse/discourse-user-notes.git plugins/discourse-user-notes - git clone --depth=1 https://github.com/discourse/discourse-group-tracker - export PATH=$HOME/.yarn/bin:$PATH diff --git a/Gemfile b/Gemfile index f1420c3458..1599efa815 100644 --- a/Gemfile +++ b/Gemfile @@ -46,12 +46,12 @@ gem 'redis-namespace' gem 'active_model_serializers', '~> 0.8.3' -gem 'onebox', '1.9.2' +gem 'onebox', '1.9.12' gem 'http_accept_language', '~>2.0.5', require: false gem 'ember-rails', '0.18.5' -gem 'discourse-ember-source', '~> 3.8.0' +gem 'discourse-ember-source', '~> 3.10.0' gem 'ember-handlebars-template', '0.8.0' gem 'barber' @@ -74,10 +74,12 @@ gem 'unf', require: false gem 'email_reply_trimmer', '~> 0.1' # Forked until https://github.com/toy/image_optim/pull/162 is merged +# https://github.com/discourse/image_optim gem 'discourse_image_optim', require: 'image_optim' gem 'multi_json' gem 'mustache' gem 'nokogiri' +gem 'css_parser', require: false gem 'omniauth' gem 'omniauth-openid' @@ -203,9 +205,12 @@ gem "sassc-rails" gem 'rotp' gem 'rqrcode' +gem 'rubyzip', require: false + gem 'sshkey', require: false gem 'rchardet', require: false +gem 'lz4-ruby', require: false, platform: :mri if ENV["IMPORT"] == "1" gem 'mysql2' diff --git a/Gemfile.lock b/Gemfile.lock index 27a97656ff..64fd90002c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -88,10 +88,12 @@ GEM crack (0.4.3) safe_yaml (~> 1.0.0) crass (1.0.4) + css_parser (1.7.0) + addressable debug_inspector (0.0.3) diff-lcs (1.3) diffy (3.3.0) - discourse-ember-source (3.8.0.1) + discourse-ember-source (3.10.0.1) discourse_image_optim (0.26.2) exifr (~> 1.2, >= 1.2.2) fspath (~> 3.0) @@ -172,11 +174,12 @@ GEM crass (~> 1.0.2) nokogiri (>= 1.5.9) lru_redux (1.1.0) + lz4-ruby (0.3.3) mail (2.7.1) mini_mime (>= 0.1.1) maxminddb (0.1.22) memory_profiler (0.9.13) - message_bus (2.2.0) + message_bus (2.2.2) rack (>= 1.1.3) metaclass (0.0.4) method_source (0.9.2) @@ -184,7 +187,7 @@ GEM mini_portile2 (2.4.0) mini_racer (0.2.6) libv8 (>= 6.9.411) - mini_scheduler (0.11.0) + mini_scheduler (0.12.1) sidekiq mini_sql (0.2.2) mini_suffix (0.3.0) @@ -199,7 +202,7 @@ GEM multi_xml (0.6.0) multipart-post (2.1.1) mustache (1.1.0) - nokogiri (1.10.3) + nokogiri (1.10.4) mini_portile2 (~> 2.4.0) nokogumbo (2.0.1) nokogiri (~> 1.8, >= 1.8.4) @@ -238,7 +241,7 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - onebox (1.9.2) + onebox (1.9.12) htmlentities (~> 4.3) moneta (~> 1.0) multi_json (~> 1.11) @@ -272,7 +275,7 @@ GEM rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) - rack-protection (2.0.5) + rack-protection (2.0.7) rack rack-test (1.1.0) rack (>= 1.0, < 3) @@ -351,6 +354,7 @@ GEM guess_html_encoding (>= 0.0.4) nokogiri (>= 1.6.0) ruby_dep (1.5.0) + rubyzip (1.2.3) safe_yaml (1.0.5) sanitize (5.0.0) crass (~> 1.0.2) @@ -437,8 +441,9 @@ DEPENDENCIES certified colored2 cppjieba_rb + css_parser diffy - discourse-ember-source (~> 3.8.0) + discourse-ember-source (~> 3.10.0) discourse_image_optim email_reply_trimmer (~> 0.1) ember-handlebars-template (= 0.8.0) @@ -463,6 +468,7 @@ DEPENDENCIES logstash-logger logster lru_redux + lz4-ruby mail maxminddb memory_profiler @@ -487,7 +493,7 @@ DEPENDENCIES omniauth-oauth2 omniauth-openid omniauth-twitter - onebox (= 1.9.2) + onebox (= 1.9.12) openid-redis-store parallel_tests pg @@ -516,6 +522,7 @@ DEPENDENCIES rubocop ruby-prof ruby-readability + rubyzip sanitize sassc sassc-rails diff --git a/app/assets/javascripts/admin/adapters/email-style.js.es6 b/app/assets/javascripts/admin/adapters/email-style.js.es6 new file mode 100644 index 0000000000..c9f3865d4c --- /dev/null +++ b/app/assets/javascripts/admin/adapters/email-style.js.es6 @@ -0,0 +1,7 @@ +import RestAdapter from "discourse/adapters/rest"; + +export default RestAdapter.extend({ + pathFor() { + return "/admin/customize/email_style"; + } +}); diff --git a/app/assets/javascripts/admin/adapters/staff-action-log.js.es6 b/app/assets/javascripts/admin/adapters/staff-action-log.js.es6 new file mode 100644 index 0000000000..8e0f087c2b --- /dev/null +++ b/app/assets/javascripts/admin/adapters/staff-action-log.js.es6 @@ -0,0 +1,7 @@ +import RestAdapter from "discourse/adapters/rest"; + +export default RestAdapter.extend({ + basePath() { + return "/admin/logs/"; + } +}); diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index ff3203f9d3..8fd9089b2e 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -75,7 +75,7 @@ export default Ember.Component.extend({ if (!this.element || this.isDestroying || this.isDestroyed) { return; } - const editor = loadedAce.edit(this.$(".ace")[0]); + const editor = loadedAce.edit(this.element.querySelector(".ace")); editor.setTheme("ace/theme/chrome"); editor.setShowPrintMargin(false); @@ -89,7 +89,7 @@ export default Ember.Component.extend({ editor.$blockScrolling = Infinity; editor.renderer.setScrollMargin(10, 10); - this.$().data("editor", editor); + this.element.setAttribute("data-editor", editor); this._editor = editor; this.changeDisabledState(); diff --git a/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 index 56f90325f3..5112564eec 100644 --- a/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 @@ -18,8 +18,8 @@ export default Ember.Component.extend( }, _scrollDown() { - const $div = this.$()[0]; - $div.scrollTop = $div.scrollHeight; + const div = this.element; + div.scrollTop = div.scrollHeight; }, @on("init") diff --git a/app/assets/javascripts/admin/components/admin-graph.js.es6 b/app/assets/javascripts/admin/components/admin-graph.js.es6 index 5ef384022e..5949d51e24 100644 --- a/app/assets/javascripts/admin/components/admin-graph.js.es6 +++ b/app/assets/javascripts/admin/components/admin-graph.js.es6 @@ -5,7 +5,7 @@ export default Ember.Component.extend({ type: "line", refreshChart() { - const ctx = this.$()[0].getContext("2d"); + const ctx = this.element.getContext("2d"); const model = this.model; const rawData = this.get("model.data"); diff --git a/app/assets/javascripts/admin/components/admin-report-chart.js.es6 b/app/assets/javascripts/admin/components/admin-report-chart.js.es6 index b4ced4e1cb..80d35c4693 100644 --- a/app/assets/javascripts/admin/components/admin-report-chart.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-chart.js.es6 @@ -35,14 +35,17 @@ export default Ember.Component.extend({ _scheduleChartRendering() { Ember.run.schedule("afterRender", () => { - this._renderChart(this.model, this.$(".chart-canvas")); + this._renderChart( + this.model, + this.element && this.element.querySelector(".chart-canvas") + ); }); }, - _renderChart(model, $chartCanvas) { - if (!$chartCanvas || !$chartCanvas.length) return; + _renderChart(model, chartCanvas) { + if (!chartCanvas) return; - const context = $chartCanvas[0].getContext("2d"); + const context = chartCanvas.getContext("2d"); const chartData = Ember.makeArray( model.get("chartData") || model.get("data") ); diff --git a/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 b/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 index a70f698010..ce0dfd9021 100644 --- a/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 @@ -33,14 +33,17 @@ export default Ember.Component.extend({ _scheduleChartRendering() { Ember.run.schedule("afterRender", () => { - this._renderChart(this.model, this.$(".chart-canvas")); + this._renderChart( + this.model, + this.element.querySelector(".chart-canvas") + ); }); }, - _renderChart(model, $chartCanvas) { - if (!$chartCanvas || !$chartCanvas.length) return; + _renderChart(model, chartCanvas) { + if (!chartCanvas) return; - const context = $chartCanvas[0].getContext("2d"); + const context = chartCanvas.getContext("2d"); const chartData = Ember.makeArray( model.get("chartData") || model.get("data") diff --git a/app/assets/javascripts/admin/components/admin-report.js.es6 b/app/assets/javascripts/admin/components/admin-report.js.es6 index 402794763d..37a8f2acc8 100644 --- a/app/assets/javascripts/admin/components/admin-report.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report.js.es6 @@ -183,6 +183,32 @@ export default Ember.Component.extend({ }, actions: { + onChangeEndDate(date) { + const startDate = moment(this.startDate); + const newEndDate = moment(date).endOf("day"); + + if (newEndDate.isSameOrAfter(startDate)) { + this.set("endDate", newEndDate.format("YYYY-MM-DD")); + } else { + this.set("endDate", startDate.endOf("day").format("YYYY-MM-DD")); + } + + this.send("refreshReport"); + }, + + onChangeStartDate(date) { + const endDate = moment(this.endDate); + const newStartDate = moment(date).startOf("day"); + + if (newStartDate.isSameOrBefore(endDate)) { + this.set("startDate", newStartDate.format("YYYY-MM-DD")); + } else { + this.set("startDate", endDate.startOf("day").format("YYYY-MM-DD")); + } + + this.send("refreshReport"); + }, + applyFilter(id, value) { let customFilters = this.get("filters.customFilters") || {}; diff --git a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 index 1dc7a27c35..6e325b2fe9 100644 --- a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 +++ b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 @@ -5,7 +5,7 @@ import { bufferedRender } from "discourse-common/lib/buffered-render"; export default Ember.Component.extend( bufferedRender({ classes: ["text-muted", "text-danger", "text-successful", "text-muted"], - icons: ["circle-o", "times-circle", "circle", "circle"], + icons: ["far-circle", "times-circle", "circle", "circle"], @computed("deliveryStatuses", "model.last_delivery_status") status(deliveryStatuses, lastDeliveryStatus) { diff --git a/app/assets/javascripts/admin/components/color-input.js.es6 b/app/assets/javascripts/admin/components/color-input.js.es6 index e57a8efde8..17783cd36a 100644 --- a/app/assets/javascripts/admin/components/color-input.js.es6 +++ b/app/assets/javascripts/admin/components/color-input.js.es6 @@ -11,10 +11,10 @@ export default Ember.Component.extend({ classNames: ["color-picker"], hexValueChanged: function() { var hex = this.hexValue; - let $text = this.$("input.hex-input"); + let text = this.element.querySelector("input.hex-input"); if (this.valid) { - $text.attr( + text.setAttribute( "style", "color: " + (this.brightnessValue > 125 ? "black" : "white") + @@ -24,10 +24,12 @@ export default Ember.Component.extend({ ); if (this.pickerLoaded) { - this.$(".picker").spectrum({ color: "#" + this.hexValue }); + $(this.element.querySelector(".picker")).spectrum({ + color: "#" + this.hexValue + }); } } else { - $text.attr("style", ""); + text.setAttribute("style", ""); } }.observes("hexValue", "brightnessValue", "valid"), @@ -35,7 +37,7 @@ export default Ember.Component.extend({ loadScript("/javascripts/spectrum.js").then(() => { loadCSS("/javascripts/spectrum.css").then(() => { Ember.run.schedule("afterRender", () => { - this.$(".picker") + $(this.element.querySelector(".picker")) .spectrum({ color: "#" + this.hexValue }) .on("change.spectrum", (me, color) => { this.set("hexValue", color.toHexString().replace("#", "")); diff --git a/app/assets/javascripts/admin/components/email-styles-editor.js.es6 b/app/assets/javascripts/admin/components/email-styles-editor.js.es6 new file mode 100644 index 0000000000..d0e569421f --- /dev/null +++ b/app/assets/javascripts/admin/components/email-styles-editor.js.es6 @@ -0,0 +1,45 @@ +import computed from "ember-addons/ember-computed-decorators"; + +export default Ember.Component.extend({ + editorId: Ember.computed.reads("fieldName"), + + @computed("fieldName", "styles.html", "styles.css") + resetDisabled(fieldName) { + return ( + this.get(`styles.${fieldName}`) === + this.get(`styles.default_${fieldName}`) + ); + }, + + @computed("styles", "fieldName") + editorContents: { + get(styles, fieldName) { + return styles[fieldName]; + }, + set(value, styles, fieldName) { + styles.setField(fieldName, value); + return value; + } + }, + + actions: { + reset() { + bootbox.confirm( + I18n.t("admin.customize.email_style.reset_confirm", { + fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`) + }), + I18n.t("no_value"), + I18n.t("yes_value"), + result => { + if (result) { + this.styles.setField( + this.fieldName, + this.styles.get(`default_${this.fieldName}`) + ); + this.notifyPropertyChange("editorContents"); + } + } + ); + } + } +}); diff --git a/app/assets/javascripts/admin/components/embeddable-host.js.es6 b/app/assets/javascripts/admin/components/embeddable-host.js.es6 index 34d46ac181..7639312ceb 100644 --- a/app/assets/javascripts/admin/components/embeddable-host.js.es6 +++ b/app/assets/javascripts/admin/components/embeddable-host.js.es6 @@ -14,7 +14,7 @@ export default Ember.Component.extend(bufferedProperty("host"), { @observes("editing") _focusOnInput() { Ember.run.schedule("afterRender", () => { - this.$(".host-name").focus(); + this.element.querySelector(".host-name").focus(); }); }, diff --git a/app/assets/javascripts/admin/components/highlighted-code.js.es6 b/app/assets/javascripts/admin/components/highlighted-code.js.es6 index 62cf58f21b..9f99c0929b 100644 --- a/app/assets/javascripts/admin/components/highlighted-code.js.es6 +++ b/app/assets/javascripts/admin/components/highlighted-code.js.es6 @@ -5,6 +5,6 @@ export default Ember.Component.extend({ @on("didInsertElement") @observes("code") _refresh: function() { - highlightSyntax(this.$()); + highlightSyntax($(this.element)); } }); diff --git a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 index 543a8baf3c..e60393b3ba 100644 --- a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 +++ b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 @@ -23,10 +23,10 @@ export default Ember.Component.extend({ // If we switch to edit mode, jump to the edit textarea if (postAction === "edit") { Ember.run.scheduleOnce("afterRender", () => { - let $elem = this.$(); - let body = $elem.closest(".modal-body"); + let elem = this.element; + let body = elem.closest(".modal-body"); body.scrollTop(body.height()); - $elem.find(".post-editor").focus(); + elem.querySelector(".post-editor").focus(); }); } } diff --git a/app/assets/javascripts/admin/components/permalink-form.js.es6 b/app/assets/javascripts/admin/components/permalink-form.js.es6 index bce150f8c9..40ae69d090 100644 --- a/app/assets/javascripts/admin/components/permalink-form.js.es6 +++ b/app/assets/javascripts/admin/components/permalink-form.js.es6 @@ -19,7 +19,9 @@ export default Ember.Component.extend({ }, focusPermalink() { - Ember.run.schedule("afterRender", () => this.$(".permalink-url").focus()); + Ember.run.schedule("afterRender", () => + this.element.querySelector(".permalink-url").focus() + ); }, actions: { @@ -67,7 +69,7 @@ export default Ember.Component.extend({ this._super(...arguments); Ember.run.schedule("afterRender", () => { - this.$(".external-url").keydown(e => { + $(this.element.querySelector(".external-url")).keydown(e => { // enter key if (e.keyCode === 13) { this.send("submit"); diff --git a/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 b/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 index 5573374a24..7fb246bf7a 100644 --- a/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 +++ b/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 @@ -62,7 +62,7 @@ export default Ember.Component.extend({ this.setProperties({ ip_address: "", formSubmitted: false }); this.action(ScreenedIpAddress.create(result.screened_ip_address)); Ember.run.schedule("afterRender", () => - this.$(".ip-address-input").focus() + this.element.querySelector(".ip-address-input").focus() ); }) .catch(e => { @@ -73,7 +73,9 @@ export default Ember.Component.extend({ error: e.jqXHR.responseJSON.errors.join(". ") }) : I18n.t("generic_error"); - bootbox.alert(msg, () => this.$(".ip-address-input").focus()); + bootbox.alert(msg, () => + this.element.querySelector(".ip-address-input").focus() + ); }); } } @@ -82,7 +84,7 @@ export default Ember.Component.extend({ @on("didInsertElement") _init() { Ember.run.schedule("afterRender", () => { - this.$(".ip-address-input").keydown(e => { + $(this.element.querySelector(".ip-address-input")).keydown(e => { if (e.keyCode === 13) { this.send("submit"); } diff --git a/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 b/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 index 4e60f1da08..0ab60a3436 100644 --- a/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 +++ b/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 @@ -3,6 +3,8 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ @computed() groupChoices() { - return this.site.get("groups").map(g => g.name); + return this.site.get("groups").map(g => { + return { name: g.name, id: g.id.toString() }; + }); } }); diff --git a/app/assets/javascripts/admin/components/site-text-summary.js.es6 b/app/assets/javascripts/admin/components/site-text-summary.js.es6 index 003ff2ffef..da6dda43f8 100644 --- a/app/assets/javascripts/admin/components/site-text-summary.js.es6 +++ b/app/assets/javascripts/admin/components/site-text-summary.js.es6 @@ -9,11 +9,13 @@ export default Ember.Component.extend({ const term = this._searchTerm(); if (term) { - this.$(".site-text-id, .site-text-value").highlight(term, { + $( + this.element.querySelector(".site-text-id, .site-text-value") + ).highlight(term, { className: "text-highlight" }); } - this.$(".site-text-value").ellipsis(); + $(this.element.querySelector(".site-text-value")).ellipsis(); }, click() { diff --git a/app/assets/javascripts/admin/components/staff-actions.js.es6 b/app/assets/javascripts/admin/components/staff-actions.js.es6 index 3a979b0290..5c7da1dc9d 100644 --- a/app/assets/javascripts/admin/components/staff-actions.js.es6 +++ b/app/assets/javascripts/admin/components/staff-actions.js.es6 @@ -4,19 +4,23 @@ export default Ember.Component.extend({ classNames: ["table", "staff-actions"], willDestroyElement() { - this.$().off("click.discourse-staff-logs"); + $(this.element).off("click.discourse-staff-logs"); }, didInsertElement() { this._super(...arguments); - this.$().on("click.discourse-staff-logs", "[data-link-post-id]", e => { - let postId = $(e.target).attr("data-link-post-id"); + $(this.element).on( + "click.discourse-staff-logs", + "[data-link-post-id]", + e => { + let postId = $(e.target).attr("data-link-post-id"); - this.store.find("post", postId).then(p => { - DiscourseURL.routeTo(p.get("url")); - }); - return false; - }); + this.store.find("post", postId).then(p => { + DiscourseURL.routeTo(p.get("url")); + }); + return false; + } + ); } }); diff --git a/app/assets/javascripts/admin/components/themes-list-item.js.es6 b/app/assets/javascripts/admin/components/themes-list-item.js.es6 index a3a84ea3d8..7bafa95c21 100644 --- a/app/assets/javascripts/admin/components/themes-list-item.js.es6 +++ b/app/assets/javascripts/admin/components/themes-list-item.js.es6 @@ -38,8 +38,8 @@ export default Ember.Component.extend({ }, animate(isInitial) { - const $container = this.$(); - const $list = this.$(".components-list"); + const $container = $(this.element); + const $list = $(this.element.querySelector(".components-list")); if ($list.length === 0 || Ember.testing) { return; } diff --git a/app/assets/javascripts/admin/components/watched-word-form.js.es6 b/app/assets/javascripts/admin/components/watched-word-form.js.es6 index 837ce517b0..b56f2c423c 100644 --- a/app/assets/javascripts/admin/components/watched-word-form.js.es6 +++ b/app/assets/javascripts/admin/components/watched-word-form.js.es6 @@ -64,7 +64,7 @@ export default Ember.Component.extend({ }); this.action(WatchedWord.create(result)); Ember.run.schedule("afterRender", () => - this.$(".watched-word-input").focus() + this.element.querySelector(".watched-word-input").focus() ); }) .catch(e => { @@ -75,7 +75,9 @@ export default Ember.Component.extend({ error: e.jqXHR.responseJSON.errors.join(". ") }) : I18n.t("generic_error"); - bootbox.alert(msg, () => this.$(".watched-word-input").focus()); + bootbox.alert(msg, () => + this.element.querySelector(".watched-word-input").focus() + ); }); } } @@ -84,7 +86,7 @@ export default Ember.Component.extend({ @on("didInsertElement") _init() { Ember.run.schedule("afterRender", () => { - this.$(".watched-word-input").keydown(e => { + $(this.element.querySelector(".watched-word-input")).keydown(e => { if (e.keyCode === 13) { this.send("submit"); } diff --git a/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 b/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 index 5f047a2bc6..b1706337f2 100644 --- a/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 +++ b/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 @@ -2,13 +2,13 @@ import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; export default Ember.Component.extend(UploadMixin, { - type: "csv", + type: "txt", classNames: "watched-words-uploader", uploadUrl: "/admin/logs/watched_words/upload", addDisabled: Ember.computed.alias("uploading"), validateUploadedFilesOptions() { - return { csvOnly: true }; + return { skipValidation: true }; }, @computed("actionKey") diff --git a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 index 07cd082fcc..684f844bc5 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 @@ -29,7 +29,7 @@ export default Ember.Controller.extend({ I18n.t("yes_value"), confirmed => { if (confirmed) { - Discourse.User.currentProp("hideReadOnlyAlert", true); + this.set("currentUser.hideReadOnlyAlert", true); this._toggleReadOnlyMode(true); } } diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 new file mode 100644 index 0000000000..b8054c8bc3 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 @@ -0,0 +1,33 @@ +import computed from "ember-addons/ember-computed-decorators"; + +export default Ember.Controller.extend({ + @computed("model.isSaving") + saveButtonText(isSaving) { + return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save"); + }, + + @computed("model.changed", "model.isSaving") + saveDisabled(changed, isSaving) { + return !changed || isSaving; + }, + + actions: { + save() { + if (!this.model.saving) { + this.set("saving", true); + this.model + .update(this.model.getProperties("html", "css")) + .catch(e => { + const msg = + e.jqXHR.responseJSON && e.jqXHR.responseJSON.errors + ? I18n.t("admin.customize.email_style.save_error_with_reason", { + error: e.jqXHR.responseJSON.errors.join(". ") + }) + : I18n.t("generic_error"); + bootbox.alert(msg); + }) + .finally(() => this.set("model.changed", false)); + } + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 index 7bf7659f65..8631babc67 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 @@ -6,5 +6,11 @@ export default Ember.Controller.extend({ this._super(...arguments); this.titleSorting = ["title"]; + }, + + actions: { + selectTemplate(template) { + this.transitionToRoute("adminCustomizeEmailTemplates.edit", template); + } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 new file mode 100644 index 0000000000..9cb38c75ea --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 @@ -0,0 +1,45 @@ +import { ajax } from "discourse/lib/ajax"; +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import { propertyEqual } from "discourse/lib/computed"; + +export default Ember.Controller.extend(bufferedProperty("model"), { + saved: false, + isSaving: false, + saveDisabled: propertyEqual("model.robots_txt", "buffered.robots_txt"), + resetDisbaled: Ember.computed.not("model.overridden"), + + actions: { + save() { + this.setProperties({ + isSaving: true, + saved: false + }); + + ajax("robots.json", { + method: "PUT", + data: { robots_txt: this.buffered.get("robots_txt") } + }) + .then(data => { + this.commitBuffer(); + this.set("saved", true); + this.set("model.overridden", data.overridden); + }) + .finally(() => this.set("isSaving", false)); + }, + + reset() { + this.setProperties({ + isSaving: true, + saved: false + }); + ajax("robots.json", { method: "DELETE" }) + .then(data => { + this.buffered.set("robots_txt", data.robots_txt); + this.commitBuffer(); + this.set("saved", true); + this.set("model.overridden", false); + }) + .finally(() => this.set("isSaving", false)); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 index 205c5fe853..eb85ef4a41 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 @@ -5,11 +5,11 @@ import Report from "admin/models/report"; import PeriodComputationMixin from "admin/mixins/period-computation"; function staticReport(reportType) { - return function() { + return Ember.computed("reports.[]", function() { return Ember.makeArray(this.reports).find( report => report.type === reportType ); - }.property("reports.[]"); + }); } export default Ember.Controller.extend(PeriodComputationMixin, { diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 index c1cd77b63b..a3d332c1f5 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 @@ -1,21 +1,15 @@ import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; -import StaffActionLog from "admin/models/staff-action-log"; import { default as computed, on } from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend({ - loading: false, - filters: null, - userHistoryActions: [], model: null, - nextPage: 0, - lastPage: null, - + filters: null, filtersExists: Ember.computed.gt("filterCount", 0), - showTable: Ember.computed.gt("model.length", 0), + userHistoryActions: null, @computed("filters.action_name") actionFilter(name) { @@ -25,34 +19,21 @@ export default Ember.Controller.extend({ @on("init") resetFilters() { this.setProperties({ - filters: Ember.Object.create(), - model: [], - nextPage: 0, - lastPage: null + model: Ember.Object.create({ loadingMore: true }), + filters: Ember.Object.create() }); this.scheduleRefresh(); }, _changeFilters(props) { + this.set("model", Ember.Object.create({ loadingMore: true })); this.filters.setProperties(props); - this.setProperties({ - model: [], - nextPage: 0, - lastPage: null - }); this.scheduleRefresh(); }, _refresh() { - if (this.lastPage && this.nextPage >= this.lastPage) { - return; - } - - this.set("loading", true); - - const page = this.nextPage; let filters = this.filters; - let params = { page }; + let params = {}; let count = 0; // Don't send null values @@ -65,32 +46,23 @@ export default Ember.Controller.extend({ }); this.set("filterCount", count); - StaffActionLog.findAll(params) - .then(result => { - this.setProperties({ - model: this.model.concat(result.staff_action_logs), - nextPage: page + 1 - }); + this.store.findAll("staff-action-log", params).then(result => { + this.set("model", result); - if (result.staff_action_logs.length === 0) { - this.set("lastPage", page); - } - - if (this.userHistoryActions.length === 0) { - this.set( - "userHistoryActions", - result.user_history_actions - .map(action => ({ - id: action.id, - action_id: action.action_id, - name: I18n.t("admin.logs.staff_actions.actions." + action.id), - name_raw: action.id - })) - .sort((a, b) => (a.name > b.name ? 1 : -1)) - ); - } - }) - .finally(() => this.set("loading", false)); + if (!this.userHistoryActions) { + this.set( + "userHistoryActions", + result.extras.user_history_actions + .map(action => ({ + id: action.id, + action_id: action.action_id, + name: I18n.t("admin.logs.staff_actions.actions." + action.id), + name_raw: action.id + })) + .sort((a, b) => a.name.localeCompare(b.name)) + ); + } + }); }, scheduleRefresh() { @@ -153,7 +125,7 @@ export default Ember.Controller.extend({ }, loadMore() { - this._refresh(); + this.model.loadMore(); } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index 79eceed9f1..4a24bbd4b5 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -134,7 +134,7 @@ export default Ember.Controller.extend(CanCheckEmails, { return this.model.resetBounceScore(); }, approve() { - return this.model.approve(); + return this.model.approve(this.currentUser); }, deactivate() { return this.model.deactivate(); diff --git a/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 b/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 index 2e38279b54..cf4a28e2d3 100644 --- a/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 @@ -1,5 +1,8 @@ import computed from "ember-addons/ember-computed-decorators"; import WatchedWord from "admin/models/watched-word"; +import { ajax } from "discourse/lib/ajax"; +import { fmt } from "discourse/lib/computed"; +import showModal from "discourse/lib/show-modal"; export default Ember.Controller.extend({ actionNameKey: null, @@ -8,6 +11,10 @@ export default Ember.Controller.extend({ "adminWatchedWords.filtered", "adminWatchedWords.showWords" ), + downloadLink: fmt( + "actionNameKey", + "/admin/logs/watched_words/action/%@/download" + ), findAction(actionName) { return (this.get("adminWatchedWords.model") || []).findBy( @@ -17,13 +24,13 @@ export default Ember.Controller.extend({ }, @computed("actionNameKey", "adminWatchedWords.model") - filteredContent(actionNameKey) { - if (!actionNameKey) { - return []; - } + currentAction(actionName) { + return this.findAction(actionName); + }, - const a = this.findAction(actionNameKey); - return a ? a.words : []; + @computed("currentAction.words.[]", "adminWatchedWords.model") + filteredContent(words) { + return words || []; }, @computed("actionNameKey") @@ -31,10 +38,9 @@ export default Ember.Controller.extend({ return I18n.t("admin.watched_words.action_descriptions." + actionNameKey); }, - @computed("actionNameKey", "adminWatchedWords.model") - wordCount(actionNameKey) { - const a = this.findAction(actionNameKey); - return a ? a.words.length : 0; + @computed("currentAction.count") + wordCount(count) { + return count || 0; }, actions: { @@ -62,10 +68,9 @@ export default Ember.Controller.extend({ }, recordRemoved(arg) { - const a = this.findAction(this.actionNameKey); - if (a) { - a.words.removeObject(arg); - a.decrementProperty("count"); + if (this.currentAction) { + this.currentAction.words.removeObject(arg); + this.currentAction.decrementProperty("count"); } }, @@ -73,6 +78,40 @@ export default Ember.Controller.extend({ WatchedWord.findAll().then(data => { this.set("adminWatchedWords.model", data); }); + }, + + clearAll() { + const actionKey = this.actionNameKey; + bootbox.confirm( + I18n.t(`admin.watched_words.clear_all_confirm_${actionKey}`), + I18n.t("no_value"), + I18n.t("yes_value"), + result => { + if (result) { + ajax(`/admin/logs/watched_words/action/${actionKey}.json`, { + method: "DELETE" + }).then(() => { + const action = this.findAction(actionKey); + if (action) { + action.setProperties({ + words: [], + count: 0 + }); + } + }); + } + } + ); + }, + + test() { + WatchedWord.findAll().then(data => { + this.set("adminWatchedWords.model", data); + showModal("admin-watched-word-test", { + admin: true, + model: this.currentAction + }); + }); } } }); diff --git a/app/assets/javascripts/admin/controllers/admin.js.es6 b/app/assets/javascripts/admin/controllers/admin.js.es6 index 9823f0fa79..a79cf81944 100644 --- a/app/assets/javascripts/admin/controllers/admin.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin.js.es6 @@ -1,7 +1,7 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend({ - application: Ember.inject.controller(), + router: Ember.inject.service(), @computed("siteSettings.enable_group_directory") showGroups(enableGroupDirectory) { @@ -13,7 +13,7 @@ export default Ember.Controller.extend({ return this.currentUser.get("admin") && enableBadges; }, - @computed("application.currentPath") + @computed("router._router.currentPath") adminContentsClassName(currentPath) { let cssClasses = currentPath .split(".") diff --git a/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 new file mode 100644 index 0000000000..7af6650ca6 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 @@ -0,0 +1,11 @@ +import { default as computed } from "ember-addons/ember-computed-decorators"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; + +export default Ember.Controller.extend(ModalFunctionality, { + @computed("value", "model.compiledRegularExpression") + matches(value, regexpString) { + if (!value || !regexpString) return; + let censorRegexp = new RegExp(regexpString, "ig"); + return value.match(censorRegexp); + } +}); diff --git a/app/assets/javascripts/admin/mixins/setting-component.js.es6 b/app/assets/javascripts/admin/mixins/setting-component.js.es6 index dbed60a799..18be48a2d1 100644 --- a/app/assets/javascripts/admin/mixins/setting-component.js.es6 +++ b/app/assets/javascripts/admin/mixins/setting-component.js.es6 @@ -90,7 +90,7 @@ export default Ember.Mixin.create({ }, _watchEnterKey: function() { - this.$().on("keydown.setting-enter", ".input-setting-string", e => { + $(this.element).on("keydown.setting-enter", ".input-setting-string", e => { if (e.keyCode === 13) { // enter key this.send("save"); @@ -99,7 +99,7 @@ export default Ember.Mixin.create({ }.on("didInsertElement"), _removeBindings: function() { - this.$().off("keydown.setting-enter"); + $(this.element).off("keydown.setting-enter"); }.on("willDestroyElement"), _save() { diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6 index f5ff4c2761..bd830be687 100644 --- a/app/assets/javascripts/admin/models/admin-user.js.es6 +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -227,14 +227,14 @@ const AdminUser = Discourse.User.extend({ .catch(popupAjaxError); }, - approve() { + approve(approvedBy) { return ajax(`/admin/users/${this.id}/approve`, { type: "PUT" }).then(() => { this.setProperties({ can_approve: false, approved: true, - approved_by: Discourse.User.current() + approved_by: approvedBy }); }); }, diff --git a/app/assets/javascripts/admin/models/color-scheme-color.js.es6 b/app/assets/javascripts/admin/models/color-scheme-color.js.es6 index a2f1a7b12d..a3b22d23bc 100644 --- a/app/assets/javascripts/admin/models/color-scheme-color.js.es6 +++ b/app/assets/javascripts/admin/models/color-scheme-color.js.es6 @@ -3,7 +3,7 @@ import { observes, on } from "ember-addons/ember-computed-decorators"; -import { propertyNotEqual, i18n } from "discourse/lib/computed"; +import { propertyNotEqual } from "discourse/lib/computed"; const ColorSchemeColor = Discourse.Model.extend({ @on("init") @@ -42,9 +42,23 @@ const ColorSchemeColor = Discourse.Model.extend({ } }, - translatedName: i18n("name", "admin.customize.colors.%@.name"), + @computed("name") + translatedName(name) { + if (!this.is_advanced) { + return I18n.t(`admin.customize.colors.${name}.name`); + } else { + return name; + } + }, - description: i18n("name", "admin.customize.colors.%@.description"), + @computed("name") + description(name) { + if (!this.is_advanced) { + return I18n.t(`admin.customize.colors.${name}.description`); + } else { + return ""; + } + }, /** brightness returns a number between 0 (darkest) to 255 (brightest). diff --git a/app/assets/javascripts/admin/models/color-scheme.js.es6 b/app/assets/javascripts/admin/models/color-scheme.js.es6 index 5276ef849d..26c8ccdc0e 100644 --- a/app/assets/javascripts/admin/models/color-scheme.js.es6 +++ b/app/assets/javascripts/admin/models/color-scheme.js.es6 @@ -128,7 +128,8 @@ ColorScheme.reopenClass({ return ColorSchemeColor.create({ name: c.name, hex: c.hex, - default_hex: c.default_hex + default_hex: c.default_hex, + is_advanced: c.is_advanced }); }) }) diff --git a/app/assets/javascripts/admin/models/email-style.js.es6 b/app/assets/javascripts/admin/models/email-style.js.es6 new file mode 100644 index 0000000000..29d7568aba --- /dev/null +++ b/app/assets/javascripts/admin/models/email-style.js.es6 @@ -0,0 +1,10 @@ +import RestModel from "discourse/models/rest"; + +export default RestModel.extend({ + changed: false, + + setField(fieldName, value) { + this.set(`${fieldName}`, value); + this.set("changed", true); + } +}); diff --git a/app/assets/javascripts/admin/models/staff-action-log.js.es6 b/app/assets/javascripts/admin/models/staff-action-log.js.es6 index 3451cffa22..2d63019dda 100644 --- a/app/assets/javascripts/admin/models/staff-action-log.js.es6 +++ b/app/assets/javascripts/admin/models/staff-action-log.js.es6 @@ -2,6 +2,7 @@ import computed from "ember-addons/ember-computed-decorators"; import { ajax } from "discourse/lib/ajax"; import AdminUser from "admin/models/admin-user"; import { escapeExpression } from "discourse/lib/utilities"; +import RestModel from "discourse/models/rest"; function format(label, value, escape = true) { return value @@ -9,7 +10,7 @@ function format(label, value, escape = true) { : ""; } -const StaffActionLog = Discourse.Model.extend({ +const StaffActionLog = RestModel.extend({ showFullDetails: false, @computed("action_name") @@ -80,16 +81,14 @@ const StaffActionLog = Discourse.Model.extend({ }); StaffActionLog.reopenClass({ - create(attrs) { - attrs = attrs || {}; - - if (attrs.acting_user) { - attrs.acting_user = AdminUser.create(attrs.acting_user); + munge(json) { + if (json.acting_user) { + json.acting_user = AdminUser.create(json.acting_user); } - if (attrs.target_user) { - attrs.target_user = AdminUser.create(attrs.target_user); + if (json.target_user) { + json.target_user = AdminUser.create(json.target_user); } - return this._super(attrs); + return json; }, findAll(data) { diff --git a/app/assets/javascripts/admin/models/watched-word.js.es6 b/app/assets/javascripts/admin/models/watched-word.js.es6 index 03404e7de0..9f335032e3 100644 --- a/app/assets/javascripts/admin/models/watched-word.js.es6 +++ b/app/assets/javascripts/admin/models/watched-word.js.es6 @@ -42,7 +42,8 @@ WatchedWord.reopenClass({ name: I18n.t("admin.watched_words.actions." + n), words: actions[n], count: actions[n].length, - regularExpressions: list.regular_expressions + regularExpressions: list.regular_expressions, + compiledRegularExpression: list.compiled_regular_expressions[n] }); }); }); diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 new file mode 100644 index 0000000000..74649c1a00 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 @@ -0,0 +1,39 @@ +export default Ember.Route.extend({ + model(params) { + return { + model: this.modelFor("adminCustomizeEmailStyle"), + fieldName: params.field_name + }; + }, + + setupController(controller, model) { + controller.setProperties({ + fieldName: model.fieldName, + model: model.model + }); + this._shouldAlertUnsavedChanges = true; + }, + + actions: { + willTransition(transition) { + if ( + this.get("controller.model.changed") && + this._shouldAlertUnsavedChanges && + transition.intent.name !== this.routeName + ) { + transition.abort(); + bootbox.confirm( + I18n.t("admin.customize.theme.unsaved_changes_alert"), + I18n.t("admin.customize.theme.discard"), + I18n.t("admin.customize.theme.stay"), + result => { + if (!result) { + this._shouldAlertUnsavedChanges = false; + transition.retry(); + } + } + ); + } + } + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 new file mode 100644 index 0000000000..8e202e62bd --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 @@ -0,0 +1,9 @@ +export default Ember.Route.extend({ + model() { + return this.store.find("email-style"); + }, + + redirect() { + this.transitionTo("adminCustomizeEmailStyle.edit", "html"); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 new file mode 100644 index 0000000000..50acd6cac1 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 @@ -0,0 +1,7 @@ +import { ajax } from "discourse/lib/ajax"; + +export default Ember.Route.extend({ + model() { + return ajax("/admin/customize/robots"); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 index 9ae0063ffe..478a851d86 100644 --- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 @@ -86,6 +86,17 @@ export default function() { this.route("edit", { path: "/:id" }); } ); + this.route("adminCustomizeRobotsTxt", { + path: "/robots", + resetNamespace: true + }); + this.route( + "adminCustomizeEmailStyle", + { path: "/email_style", resetNamespace: true }, + function() { + this.route("edit", { path: "/:field_name" }); + } + ); } ); diff --git a/app/assets/javascripts/admin/routes/admin-users-list.js.es6 b/app/assets/javascripts/admin/routes/admin-users-list.js.es6 index f2edad8aa5..d6b76356f1 100644 --- a/app/assets/javascripts/admin/routes/admin-users-list.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-users-list.js.es6 @@ -11,7 +11,7 @@ export default Discourse.Route.extend({ }, sendInvites() { - this.transitionTo("userInvited", Discourse.User.current()); + this.transitionTo("userInvited", this.currentUser); }, deleteUser(user) { diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs index a23223d2bb..8d9729dc82 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs @@ -130,9 +130,7 @@
- {{date-picker-past - value=startDate - defaultDate=startDate}} + {{date-input date=startDate onChange=(action "onChangeStartDate")}}
@@ -142,9 +140,7 @@
- {{date-picker-past - value=endDate - defaultDate=endDate}} + {{date-input date=endDate onChange=(action "onChangeEndDate")}}
{{/if}} diff --git a/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs b/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs new file mode 100644 index 0000000000..883149644d --- /dev/null +++ b/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs @@ -0,0 +1,20 @@ +
+
+ +
+
+ +{{ace-editor content=editorContents mode=fieldName editorId=editorId}} + + diff --git a/app/assets/javascripts/admin/templates/components/site-settings/group-list.hbs b/app/assets/javascripts/admin/templates/components/site-settings/group-list.hbs index adb6ec5098..005f14398e 100644 --- a/app/assets/javascripts/admin/templates/components/site-settings/group-list.hbs +++ b/app/assets/javascripts/admin/templates/components/site-settings/group-list.hbs @@ -1,3 +1,3 @@ -{{list-setting settingValue=value choices=groupChoices settingName=setting.setting}} +{{list-setting settingValue=value choices=groupChoices settingName='name'}} {{setting-validation-message message=validationMessage}}
{{{unbound setting.description}}}
diff --git a/app/assets/javascripts/admin/templates/components/watched-word-uploader.hbs b/app/assets/javascripts/admin/templates/components/watched-word-uploader.hbs index d7c7f2a572..d2422da00b 100644 --- a/app/assets/javascripts/admin/templates/components/watched-word-uploader.hbs +++ b/app/assets/javascripts/admin/templates/components/watched-word-uploader.hbs @@ -1,7 +1,6 @@ -
-One word per line +{{i18n 'admin.watched_words.one_word_per_line'}} diff --git a/app/assets/javascripts/admin/templates/customize-colors-show.hbs b/app/assets/javascripts/admin/templates/customize-colors-show.hbs index fd44f997f6..521cd8688c 100644 --- a/app/assets/javascripts/admin/templates/customize-colors-show.hbs +++ b/app/assets/javascripts/admin/templates/customize-colors-show.hbs @@ -6,7 +6,7 @@ {{/unless}} - + {{#if model.theme_id}} {{i18n "admin.customize.theme_owner"}} {{#link-to "adminCustomizeThemes.show" model.theme_id}}{{model.theme_name}}{{/link-to}} diff --git a/app/assets/javascripts/admin/templates/customize-email-style-edit.hbs b/app/assets/javascripts/admin/templates/customize-email-style-edit.hbs new file mode 100644 index 0000000000..1e68fd0c1a --- /dev/null +++ b/app/assets/javascripts/admin/templates/customize-email-style-edit.hbs @@ -0,0 +1,9 @@ +{{email-styles-editor styles=model fieldName=fieldName}} + + diff --git a/app/assets/javascripts/admin/templates/customize-email-style.hbs b/app/assets/javascripts/admin/templates/customize-email-style.hbs new file mode 100644 index 0000000000..d46e732603 --- /dev/null +++ b/app/assets/javascripts/admin/templates/customize-email-style.hbs @@ -0,0 +1,7 @@ +
+

{{i18n 'admin.customize.email_style.heading'}}

+ +

{{i18n 'admin.customize.email_style.instructions'}}

+
+ +{{outlet}} diff --git a/app/assets/javascripts/admin/templates/customize-email-templates.hbs b/app/assets/javascripts/admin/templates/customize-email-templates.hbs index 7dd95b092f..d89624e477 100644 --- a/app/assets/javascripts/admin/templates/customize-email-templates.hbs +++ b/app/assets/javascripts/admin/templates/customize-email-templates.hbs @@ -1,15 +1,8 @@ -
-
- -
+{{combo-box + content=sortedTemplates + valueAttribute="id" + nameProperty="title" + onSelect=(action "selectTemplate") +}} -
- {{outlet}} -
-
+{{outlet}} diff --git a/app/assets/javascripts/admin/templates/customize-robots-txt.hbs b/app/assets/javascripts/admin/templates/customize-robots-txt.hbs new file mode 100644 index 0000000000..b556f0c537 --- /dev/null +++ b/app/assets/javascripts/admin/templates/customize-robots-txt.hbs @@ -0,0 +1,20 @@ +
+

{{i18n "admin.customize.robots.title"}}

+

{{i18n "admin.customize.robots.warning"}}

+ {{#if model.overridden}} +
+ {{i18n "admin.customize.robots.overridden"}} +
+ {{/if}} + {{textarea + value=buffered.robots_txt + class="robots-txt-input"}} + {{#save-controls model=this action=(action "save") saved=saved saveDisabled=saveDisabled}} + {{d-button + class="btn-default" + disabled=resetDisbaled + icon="undo" + action=(action "reset") + label="admin.settings.reset"}} + {{/save-controls}} +
diff --git a/app/assets/javascripts/admin/templates/customize.hbs b/app/assets/javascripts/admin/templates/customize.hbs index d5d3816310..768eaf29a2 100644 --- a/app/assets/javascripts/admin/templates/customize.hbs +++ b/app/assets/javascripts/admin/templates/customize.hbs @@ -3,6 +3,7 @@ {{nav-item route='adminCustomize.colors' label='admin.customize.colors.title'}} {{nav-item route='adminSiteText' label='admin.site_text.title'}} {{nav-item route='adminCustomizeEmailTemplates' label='admin.customize.email_templates.title'}} + {{nav-item route='adminCustomizeEmailStyle' label='admin.customize.email_style.title'}} {{nav-item route='adminUserFields' label='admin.user_fields.title'}} {{nav-item route='adminEmojis' label='admin.emoji.title'}} {{nav-item route='adminPermalinks' label='admin.permalink.title'}} diff --git a/app/assets/javascripts/admin/templates/dashboard_general.hbs b/app/assets/javascripts/admin/templates/dashboard_general.hbs index 2feaefe97d..af0bb36ae9 100644 --- a/app/assets/javascripts/admin/templates/dashboard_general.hbs +++ b/app/assets/javascripts/admin/templates/dashboard_general.hbs @@ -117,13 +117,15 @@

{{i18n "admin.dashboard.last_updated"}}

{{format-date model.attributes.updated_at leaveAgo="true"}}

-
-

{{i18n "admin.dashboard.discourse_last_updated"}}

-

{{format-date model.attributes.discourse_updated_at leaveAgo="true"}}

- - {{i18n "admin.dashboard.whats_new_in_discourse"}} - -
+ {{#if model.attributes.discourse_updated_at}} +
+

{{i18n "admin.dashboard.discourse_last_updated"}}

+

{{format-date model.attributes.discourse_updated_at leaveAgo="true"}}

+ + {{i18n "admin.dashboard.whats_new_in_discourse"}} + +
+ {{/if}} diff --git a/app/assets/javascripts/admin/templates/email-preview-digest.hbs b/app/assets/javascripts/admin/templates/email-preview-digest.hbs index 70fe22afe6..32df5b0d97 100644 --- a/app/assets/javascripts/admin/templates/email-preview-digest.hbs +++ b/app/assets/javascripts/admin/templates/email-preview-digest.hbs @@ -6,13 +6,15 @@ {{date-picker-past value=lastSeen id="last-seen"}} {{user-selector single="true" usernames=username canReceiveUpdates="true"}} - +
{{#if showHtml}} - {{i18n 'admin.email.html'}} | {{i18n 'admin.email.text'}} + {{i18n 'admin.email.html'}} | {{i18n 'admin.email.text'}} {{else}} - {{i18n 'admin.email.html'}} | {{i18n 'admin.email.text'}} + {{i18n 'admin.email.html'}} | + {{i18n 'admin.email.text'}} {{/if}}
@@ -20,35 +22,33 @@ {{#conditional-loading-spinner condition=loading}} -
- {{#if showSendEmailForm}} -
-
- {{#if sendingEmail}} - {{i18n 'admin.email.sending_test'}} - {{else}} - - {{text-field value=email placeholderKey="admin.email.test_email_address"}} - - {{#if sentEmail}} - {{i18n 'admin.email.sent_test'}} +