DEV: Convert admin component definitions to native class syntax ()

This conversion was achieved using the ember-native-class-codemod, plus a handful of manual fixes/tweaks
This commit is contained in:
David Taylor 2023-02-23 15:32:53 +00:00 committed by GitHub
parent a0ca10fa17
commit a433b30650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 1227 additions and 1141 deletions
app/assets/javascripts/admin/addon/components
ace-editor.jsadmin-backups-logs.jsadmin-editable-field.jsadmin-form-row.jsadmin-graph.jsadmin-nav.jsadmin-penalty-history.jsadmin-penalty-post-action.jsadmin-penalty-reason.jsadmin-penalty-similar-users.jsadmin-report-chart.jsadmin-report-counters.jsadmin-report-counts.jsadmin-report-inline-table.jsadmin-report-per-day-counts.jsadmin-report-stacked-chart.jsadmin-report-storage-stats.jsadmin-report-table-cell.jsadmin-report-table-header.jsadmin-report-table-row.jsadmin-report-table.jsadmin-report-trust-level-counts.jsadmin-report.jsadmin-theme-editor.jsadmin-watched-word.jsadmin-wrapper.jscancel-link.jscolor-input.jsdashboard-new-feature-item.jsdashboard-new-features.jsdashboard-problems.jsemail-styles-editor.jsembeddable-host.jsembedding-setting.jsemoji-value-list.jsflag-user-lists.jsflag-user.jshighlighted-code.jsinline-edit-checkbox.jsinstall-theme-item.jsip-lookup.jsmoderation-history-item.jspermalink-form.js
report-filters
resumable-upload.jsscreened-ip-address-form.hbsscreened-ip-address-form.jssecret-value-list.jssetting-validation-message.jssilence-details.jssimple-list.jssite-customization-change-details.jssite-customization-change-field.jssite-setting.js
site-settings
site-text-summary.jsstaff-actions.jstags-uploader.jstheme-translation.jsthemes-list-item.jsthemes-list.jsvalue-list.jsversion-checks.jswatched-word-form.hbswatched-word-form.jswatched-word-uploader.js

@ -1,31 +1,33 @@
import { action } from "@ember/object";
import { classNames } from "@ember-decorators/component";
import { on } from "@ember-decorators/object";
import Component from "@ember/component";
import getURL from "discourse-common/lib/get-url";
import loadScript from "discourse/lib/load-script";
import I18n from "I18n";
import { bind, observes } from "discourse-common/utils/decorators";
import { on } from "@ember/object/evented";
const COLOR_VARS_REGEX =
/\$(primary|secondary|tertiary|quaternary|header_background|header_primary|highlight|danger|success|love)(\s|;|-(low|medium|high))/g;
export default Component.extend({
mode: "css",
classNames: ["ace-wrapper"],
_editor: null,
_skipContentChangeEvent: null,
disabled: false,
htmlPlaceholder: false,
@classNames("ace-wrapper")
export default class AceEditor extends Component {
mode = "css";
disabled = false;
htmlPlaceholder = false;
_editor = null;
_skipContentChangeEvent = null;
@observes("editorId")
editorIdChanged() {
if (this.autofocus) {
this.send("focus");
}
},
}
didRender() {
this._skipContentChangeEvent = false;
},
}
@observes("content")
contentChanged() {
@ -33,14 +35,14 @@ export default Component.extend({
if (this._editor && !this._skipContentChangeEvent) {
this._editor.getSession().setValue(content);
}
},
}
@observes("mode")
modeChanged() {
if (this._editor && !this._skipContentChangeEvent) {
this._editor.getSession().setMode("ace/mode/" + this.mode);
}
},
}
@observes("placeholder")
placeholderChanged() {
@ -49,12 +51,12 @@ export default Component.extend({
placeholder: this.placeholder,
});
}
},
}
@observes("disabled")
disabledStateChanged() {
this.changeDisabledState();
},
}
changeDisabledState() {
const editor = this._editor;
@ -67,9 +69,10 @@ export default Component.extend({
});
editor.container.parentNode.setAttribute("data-disabled", disabled);
}
},
}
_destroyEditor: on("willDestroyElement", function () {
@on("willDestroyElement")
_destroyEditor() {
if (this._editor) {
this._editor.destroy();
this._editor = null;
@ -80,16 +83,16 @@ export default Component.extend({
}
$(window).off("ace:resize");
}),
}
resize() {
if (this._editor) {
this._editor.resize();
}
},
}
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
loadScript("/javascripts/ace/ace.js").then(() => {
window.ace.require(["ace/ace"], (loadedAce) => {
loadedAce.config.set("loadWorkerFromBlob", false);
@ -153,13 +156,13 @@ export default Component.extend({
this._darkModeListener.addListener(this.setAceTheme);
});
});
},
}
willDestroyElement() {
if (this._darkModeListener) {
this._darkModeListener.removeListener(this.setAceTheme);
}
},
}
@bind
setAceTheme() {
@ -170,7 +173,7 @@ export default Component.extend({
this._editor.setTheme(
`ace/theme/${schemeType === "dark" ? "chaos" : "chrome"}`
);
},
}
warnSCSSDeprecations() {
if (
@ -202,16 +205,15 @@ export default Component.extend({
? I18n.t("admin.customize.theme.scss_color_variables_warning")
: false
);
},
}
actions: {
focus() {
if (this._editor) {
this._editor.focus();
this._editor.navigateFileEnd();
}
},
},
@action
focus() {
if (this._editor) {
this._editor.focus();
this._editor.navigateFileEnd();
}
}
_overridePlaceholder(loadedAce) {
const originalPlaceholderSetter =
@ -239,5 +241,5 @@ export default Component.extend({
this.$updatePlaceholder();
};
},
});
}
}

@ -1,28 +1,26 @@
import { classNames } from "@ember-decorators/component";
import { observes, on } from "discourse-common/utils/decorators";
import Component from "@ember/component";
import I18n from "I18n";
import discourseDebounce from "discourse-common/lib/debounce";
import { scheduleOnce } from "@ember/runloop";
export default Component.extend({
classNames: ["admin-backups-logs"],
showLoadingSpinner: false,
hasFormattedLogs: false,
noLogsMessage: I18n.t("admin.backups.logs.none"),
init() {
this._super(...arguments);
this._reset();
},
@classNames("admin-backups-logs")
export default class AdminBackupsLogs extends Component {
showLoadingSpinner = false;
hasFormattedLogs = false;
noLogsMessage = I18n.t("admin.backups.logs.none");
formattedLogs = "";
index = 0;
_reset() {
this.setProperties({ formattedLogs: "", index: 0 });
},
}
_scrollDown() {
const div = this.element;
div.scrollTop = div.scrollHeight;
},
}
@on("init")
@observes("logs.[]")
@ -31,7 +29,7 @@ export default Component.extend({
this._reset(); // reset the cached logs whenever the model is reset
this.renderLogs();
}
},
}
_updateFormattedLogsFunc() {
const logs = this.logs;
@ -55,13 +53,13 @@ export default Component.extend({
this.renderLogs();
scheduleOnce("afterRender", this, this._scrollDown);
},
}
@on("init")
@observes("logs.[]")
_updateFormattedLogs() {
discourseDebounce(this, this._updateFormattedLogsFunc, 150);
},
}
renderLogs() {
const formattedLogs = this.formattedLogs;
@ -76,5 +74,5 @@ export default Component.extend({
} else {
this.set("showLoadingSpinner", false);
}
},
});
}
}

@ -1,28 +1,22 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
import { action } from "@ember/object";
export default Component.extend({
tagName: "",
buffer: "",
editing: false,
init() {
this._super(...arguments);
this.set("editing", false);
},
@tagName("")
export default class AdminEditableField extends Component {
buffer = "";
editing = false;
@action
edit(event) {
event?.preventDefault();
this.set("buffer", this.value);
this.toggleProperty("editing");
},
}
actions: {
save() {
// Action has to toggle 'editing' property.
this.action(this.buffer);
},
},
});
@action
save() {
// Action has to toggle 'editing' property.
this.action(this.buffer);
}
}

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
classNames: ["row"],
});
@classNames("row")
export default class AdminFormRow extends Component {}

@ -1,9 +1,10 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
import loadScript from "discourse/lib/load-script";
export default Component.extend({
tagName: "canvas",
type: "line",
@tagName("canvas")
export default class AdminGraph extends Component {
type = "line";
refreshChart() {
const ctx = this.element.getContext("2d");
@ -49,11 +50,11 @@ export default Component.extend({
};
this._chart = new window.Chart(ctx, config);
},
}
didInsertElement() {
loadScript("/javascripts/Chart.min.js").then(() =>
this.refreshChart.apply(this)
);
},
});
}
}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "",
});
@tagName("")
export default class AdminNav extends Component {}

@ -1,16 +1,16 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
classNames: ["penalty-history"],
@classNames("penalty-history")
export default class AdminPenaltyHistory extends Component {
@discourseComputed("user.penalty_counts.suspended")
suspendedCountClass(count) {
if (count > 0) {
return "danger";
}
return "";
},
}
@discourseComputed("user.penalty_counts.silenced")
silencedCountClass(count) {
@ -18,5 +18,5 @@ export default Component.extend({
return "danger";
}
return "";
},
});
}
}

@ -1,5 +1,6 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { equal } from "@ember/object/computed";
import Component from "@ember/component";
import discourseComputed, {
afterRender,
} from "discourse-common/utils/decorators";
@ -7,30 +8,28 @@ import I18n from "I18n";
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
export default Component.extend({
postId: null,
postAction: null,
postEdit: null,
export default class AdminPenaltyPostAction extends Component {
postId = null;
postAction = null;
postEdit = null;
@equal("postAction", "edit") editing;
@discourseComputed
penaltyActions() {
return ACTIONS.map((id) => {
return { id, name: I18n.t(`admin.user.penalty_post_${id}`) };
});
},
}
editing: equal("postAction", "edit"),
@action
penaltyChanged(postAction) {
this.set("postAction", postAction);
actions: {
penaltyChanged(postAction) {
this.set("postAction", postAction);
// If we switch to edit mode, jump to the edit textarea
if (postAction === "edit") {
this._focusEditTextarea();
}
},
},
// If we switch to edit mode, jump to the edit textarea
if (postAction === "edit") {
this._focusEditTextarea();
}
}
@afterRender
_focusEditTextarea() {
@ -38,5 +37,5 @@ export default Component.extend({
const body = elem.closest(".modal-body");
body.scrollTo(0, body.clientHeight);
elem.querySelector(".post-editor").focus();
},
});
}
}

@ -1,43 +1,46 @@
import { tagName } from "@ember-decorators/component";
import { equal } from "@ember/object/computed";
import Component from "@ember/component";
import { action } from "@ember/object";
import { equal } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "I18n";
const CUSTOM_REASON_KEY = "custom";
export default Component.extend({
tagName: "",
selectedReason: CUSTOM_REASON_KEY,
customReason: "",
reasonKeys: [
@tagName("")
export default class AdminPenaltyReason extends Component {
selectedReason = CUSTOM_REASON_KEY;
customReason = "";
reasonKeys = [
"not_listening_to_staff",
"consuming_staff_time",
"combative",
"in_wrong_place",
"no_constructive_purpose",
CUSTOM_REASON_KEY,
],
isCustomReason: equal("selectedReason", CUSTOM_REASON_KEY),
];
@equal("selectedReason", CUSTOM_REASON_KEY) isCustomReason;
@discourseComputed("reasonKeys")
reasons(keys) {
return keys.map((key) => {
return { id: key, name: I18n.t(`admin.user.suspend_reasons.${key}`) };
});
},
}
@action
setSelectedReason(value) {
this.set("selectedReason", value);
this.setReason();
},
}
@action
setCustomReason(value) {
this.set("customReason", value);
this.setReason();
},
}
setReason() {
if (this.isCustomReason) {
@ -48,5 +51,5 @@ export default Component.extend({
I18n.t(`admin.user.suspend_reasons.${this.selectedReason}`)
);
}
},
});
}
}

@ -1,10 +1,10 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
import { action } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "",
@tagName("")
export default class AdminPenaltySimilarUsers extends Component {
@discourseComputed("penaltyType")
penaltyField(penaltyType) {
if (penaltyType === "suspend") {
@ -12,7 +12,7 @@ export default Component.extend({
} else if (penaltyType === "silence") {
return "can_be_silenced";
}
},
}
@action
selectUserId(userId, event) {
@ -25,5 +25,5 @@ export default Component.extend({
} else {
this.selectedUserIds.removeObject(userId);
}
},
});
}
}

@ -1,3 +1,4 @@
import { classNames } from "@ember-decorators/component";
import Report from "admin/models/report";
import Component from "@ember/component";
import discourseDebounce from "discourse-common/lib/debounce";
@ -7,31 +8,31 @@ import { number } from "discourse/lib/formatter";
import { schedule } from "@ember/runloop";
import { bind } from "discourse-common/utils/decorators";
export default Component.extend({
classNames: ["admin-report-chart"],
limit: 8,
total: 0,
options: null,
@classNames("admin-report-chart")
export default class AdminReportChart extends Component {
limit = 8;
total = 0;
options = null;
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
window.addEventListener("resize", this._resizeHandler);
},
}
willDestroyElement() {
this._super(...arguments);
super.willDestroyElement(...arguments);
window.removeEventListener("resize", this._resizeHandler);
this._resetChart();
},
}
didReceiveAttrs() {
this._super(...arguments);
super.didReceiveAttrs(...arguments);
discourseDebounce(this, this._scheduleChartRendering, 100);
},
}
_scheduleChartRendering() {
schedule("afterRender", () => {
@ -40,7 +41,7 @@ export default Component.extend({
this.element && this.element.querySelector(".chart-canvas")
);
});
},
}
_renderChart(model, chartCanvas) {
if (!chartCanvas) {
@ -99,7 +100,7 @@ export default Component.extend({
this._buildChartConfig(data, this.options)
);
});
},
}
_buildChartConfig(data, options) {
return {
@ -161,21 +162,21 @@ export default Component.extend({
},
},
};
},
}
_resetChart() {
if (this._chart) {
this._chart.destroy();
this._chart = null;
}
},
}
_applyChartGrouping(model, data, options) {
return Report.collapse(model, data, options.chartGrouping);
},
}
@bind
_resizeHandler() {
discourseDebounce(this, this._scheduleChartRendering, 500);
},
});
}
}

@ -1,6 +1,6 @@
import { attributeBindings, classNames } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
classNames: ["admin-report-counters"],
attributeBindings: ["model.description:title"],
});
@classNames("admin-report-counters")
@attributeBindings("model.description:title")
export default class AdminReportCounters extends Component {}

@ -1,11 +1,12 @@
import Component from "@ember/component";
import { classNameBindings, tagName } from "@ember-decorators/component";
import { match } from "@ember/object/computed";
export default Component.extend({
allTime: true,
tagName: "tr",
reverseColors: match(
"report.type",
/^(time_to_first_response|topics_with_no_response)$/
),
classNameBindings: ["reverseColors"],
});
import Component from "@ember/component";
@tagName("tr")
@classNameBindings("reverseColors")
export default class AdminReportCounts extends Component {
allTime = true;
@match("report.type", /^(time_to_first_response|topics_with_no_response)$/)
reverseColors;
}

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
classNames: ["admin-report-inline-table"],
});
@classNames("admin-report-inline-table")
export default class AdminReportInlineTable extends Component {}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "tr",
});
@tagName("tr")
export default class AdminReportPerDayCounts extends Component {}

@ -1,3 +1,4 @@
import { classNames } from "@ember-decorators/component";
import Report from "admin/models/report";
import Component from "@ember/component";
import discourseDebounce from "discourse-common/lib/debounce";
@ -7,32 +8,31 @@ import { number } from "discourse/lib/formatter";
import { schedule } from "@ember/runloop";
import { bind } from "discourse-common/utils/decorators";
export default Component.extend({
classNames: ["admin-report-chart", "admin-report-stacked-chart"],
@classNames("admin-report-chart", "admin-report-stacked-chart")
export default class AdminReportStackedChart extends Component {
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
window.addEventListener("resize", this._resizeHandler);
},
}
willDestroyElement() {
this._super(...arguments);
super.willDestroyElement(...arguments);
window.removeEventListener("resize", this._resizeHandler);
this._resetChart();
},
}
didReceiveAttrs() {
this._super(...arguments);
super.didReceiveAttrs(...arguments);
discourseDebounce(this, this._scheduleChartRendering, 100);
},
}
@bind
_resizeHandler() {
discourseDebounce(this, this._scheduleChartRendering, 500);
},
}
_scheduleChartRendering() {
schedule("afterRender", () => {
@ -45,7 +45,7 @@ export default Component.extend({
this.element.querySelector(".chart-canvas")
);
});
},
}
_renderChart(model, chartCanvas) {
if (!chartCanvas) {
@ -79,7 +79,7 @@ export default Component.extend({
this._chart = new window.Chart(context, this._buildChartConfig(data));
});
},
}
_buildChartConfig(data) {
return {
@ -150,10 +150,10 @@ export default Component.extend({
},
},
};
},
}
_resetChart() {
this._chart?.destroy();
this._chart = null;
},
});
}
}

@ -1,43 +1,45 @@
import { classNames } from "@ember-decorators/component";
import { alias } from "@ember/object/computed";
import Component from "@ember/component";
import I18n from "I18n";
import { alias } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import { setting } from "discourse/lib/computed";
export default Component.extend({
classNames: ["admin-report-storage-stats"],
@classNames("admin-report-storage-stats")
export default class AdminReportStorageStats extends Component {
@setting("backup_location") backupLocation;
backupLocation: setting("backup_location"),
backupStats: alias("model.data.backups"),
uploadStats: alias("model.data.uploads"),
@alias("model.data.backups") backupStats;
@alias("model.data.uploads") uploadStats;
@discourseComputed("backupStats")
showBackupStats(stats) {
return stats && this.currentUser.admin;
},
}
@discourseComputed("backupLocation")
backupLocationName(backupLocation) {
return I18n.t(`admin.backups.location.${backupLocation}`);
},
}
@discourseComputed("backupStats.used_bytes")
usedBackupSpace(bytes) {
return I18n.toHumanSize(bytes);
},
}
@discourseComputed("backupStats.free_bytes")
freeBackupSpace(bytes) {
return I18n.toHumanSize(bytes);
},
}
@discourseComputed("uploadStats.used_bytes")
usedUploadSpace(bytes) {
return I18n.toHumanSize(bytes);
},
}
@discourseComputed("uploadStats.free_bytes")
freeUploadSpace(bytes) {
return I18n.toHumanSize(bytes);
},
});
}
}

@ -1,21 +1,27 @@
import Component from "@ember/component";
import {
attributeBindings,
classNameBindings,
classNames,
tagName,
} from "@ember-decorators/component";
import { alias } from "@ember/object/computed";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "td",
classNames: ["admin-report-table-cell"],
classNameBindings: ["type", "property"],
attributeBindings: ["value:title"],
options: null,
@tagName("td")
@classNames("admin-report-table-cell")
@classNameBindings("type", "property")
@attributeBindings("value:title")
export default class AdminReportTableCell extends Component {
options = null;
@alias("label.type") type;
@alias("label.mainProperty") property;
@alias("computedLabel.formattedValue") formattedValue;
@alias("computedLabel.value") value;
@discourseComputed("label", "data", "options")
computedLabel(label, data, options) {
return label.compute(data, options || {});
},
type: alias("label.type"),
property: alias("label.mainProperty"),
formattedValue: alias("computedLabel.formattedValue"),
value: alias("computedLabel.value"),
});
}
}

@ -1,19 +1,24 @@
import {
attributeBindings,
classNameBindings,
classNames,
tagName,
} from "@ember-decorators/component";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
tagName: "th",
classNames: ["admin-report-table-header"],
classNameBindings: ["label.mainProperty", "label.type", "isCurrentSort"],
attributeBindings: ["label.title:title"],
@tagName("th")
@classNames("admin-report-table-header")
@classNameBindings("label.mainProperty", "label.type", "isCurrentSort")
@attributeBindings("label.title:title")
export default class AdminReportTableHeader extends Component {
@discourseComputed("currentSortLabel.sortProperty", "label.sortProperty")
isCurrentSort(currentSortField, labelSortField) {
return currentSortField === labelSortField;
},
}
@discourseComputed("currentSortDirection")
sortIcon(currentSortDirection) {
return currentSortDirection === 1 ? "caret-up" : "caret-down";
},
});
}
}

@ -1,6 +1,8 @@
import { classNames, tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "tr",
classNames: ["admin-report-table-row"],
options: null,
});
@tagName("tr")
@classNames("admin-report-table-row")
export default class AdminReportTableRow extends Component {
options = null;
}

@ -1,22 +1,26 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { classNameBindings, classNames } from "@ember-decorators/component";
import { alias } from "@ember/object/computed";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import { makeArray } from "discourse-common/lib/helpers";
const PAGES_LIMIT = 8;
export default Component.extend({
classNameBindings: ["sortable", "twoColumns"],
classNames: ["admin-report-table"],
sortable: false,
sortDirection: 1,
perPage: alias("options.perPage"),
page: 0,
@classNameBindings("sortable", "twoColumns")
@classNames("admin-report-table")
export default class AdminReportTable extends Component {
sortable = false;
sortDirection = 1;
@alias("options.perPage") perPage;
page = 0;
@discourseComputed("model.computedLabels.length")
twoColumns(labelsLength) {
return labelsLength === 2;
},
}
@discourseComputed(
"totalsForSample",
@ -31,12 +35,12 @@ export default Component.extend({
.reduce((s, v) => s + v, 0);
return sum >= 1 && total && datesFiltering;
},
}
@discourseComputed("model.total", "options.total", "twoColumns")
showTotal(reportTotal, total, twoColumns) {
return reportTotal && total && twoColumns;
},
}
@discourseComputed(
"model.{average,data}",
@ -50,17 +54,17 @@ export default Component.extend({
sampleTotalValue &&
hasTwoColumns
);
},
}
@discourseComputed("totalsForSample.1.value", "model.data.length")
averageForSample(totals, count) {
return (totals / count).toFixed(0);
},
}
@discourseComputed("model.data.length")
showSortingUI(dataLength) {
return dataLength >= 5;
},
}
@discourseComputed("totalsForSampleRow", "model.computedLabels")
totalsForSample(row, labels) {
@ -70,7 +74,7 @@ export default Component.extend({
computedLabel.property = label.mainProperty;
return computedLabel;
});
},
}
@discourseComputed("model.data", "model.computedLabels")
totalsForSampleRow(rows, labels) {
@ -98,7 +102,7 @@ export default Component.extend({
});
return totalsRow;
},
}
@discourseComputed("sortLabel", "sortDirection", "model.data.[]")
sortedData(sortLabel, sortDirection, data) {
@ -118,7 +122,7 @@ export default Component.extend({
}
return data;
},
}
@discourseComputed("sortedData.[]", "perPage", "page")
paginatedData(data, perPage, page) {
@ -128,7 +132,7 @@ export default Component.extend({
}
return data;
},
}
@discourseComputed("model.data", "perPage", "page")
pages(data, perPage, page) {
@ -156,19 +160,19 @@ export default Component.extend({
}
return pages;
},
}
actions: {
changePage(page) {
this.set("page", page);
},
@action
changePage(page) {
this.set("page", page);
}
sortByLabel(label) {
if (this.sortLabel === label) {
this.set("sortDirection", this.sortDirection === 1 ? -1 : 1);
} else {
this.set("sortLabel", label);
}
},
},
});
@action
sortByLabel(label) {
if (this.sortLabel === label) {
this.set("sortDirection", this.sortDirection === 1 ? -1 : 1);
} else {
this.set("sortLabel", label);
}
}
}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "tr",
});
@tagName("tr")
export default class AdminReportTrustLevelCounts extends Component {}

@ -1,6 +1,7 @@
import { classNameBindings, classNames } from "@ember-decorators/component";
import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
import EmberObject, { action, computed } from "@ember/object";
import Report, { DAILY_LIMIT_DAYS, SCHEMA_VERSION } from "admin/models/report";
import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
import Component from "@ember/component";
import I18n from "I18n";
import ReportLoader from "discourse/lib/reports-loader";
@ -21,51 +22,58 @@ const TABLE_OPTIONS = {
const CHART_OPTIONS = {};
export default Component.extend({
classNameBindings: [
"isHidden:hidden",
"isHidden::is-visible",
"isEnabled",
"isLoading",
"dasherizedDataSourceName",
],
classNames: ["admin-report"],
isEnabled: true,
disabledLabel: I18n.t("admin.dashboard.disabled"),
isLoading: false,
rateLimitationString: null,
dataSourceName: null,
report: null,
model: null,
reportOptions: null,
forcedModes: null,
showAllReportsLink: false,
filters: null,
showTrend: false,
showHeader: true,
showTitle: true,
showFilteringUI: false,
showDatesOptions: alias("model.dates_filtering"),
showRefresh: or("showDatesOptions", "model.available_filters.length"),
shouldDisplayTrend: and("showTrend", "model.prev_period"),
endDate: null,
startDate: null,
@classNameBindings(
"isHidden:hidden",
"isHidden::is-visible",
"isEnabled",
"isLoading",
"dasherizedDataSourceName"
)
@classNames("admin-report")
export default class AdminReport extends Component {
isEnabled = true;
disabledLabel = I18n.t("admin.dashboard.disabled");
isLoading = false;
rateLimitationString = null;
dataSourceName = null;
report = null;
model = null;
reportOptions = null;
forcedModes = null;
showAllReportsLink = false;
filters = null;
showTrend = false;
showHeader = true;
showTitle = true;
showFilteringUI = false;
init() {
this._super(...arguments);
@alias("model.dates_filtering") showDatesOptions;
this._reports = [];
},
@or("showDatesOptions", "model.available_filters.length") showRefresh;
isHidden: computed("siteSettings.dashboard_hidden_reports", function () {
@and("showTrend", "model.prev_period") shouldDisplayTrend;
endDate = null;
startDate = null;
@or("showTimeoutError", "showExceptionError", "showNotFoundError") showError;
@equal("model.error", "not_found") showNotFoundError;
@equal("model.error", "timeout") showTimeoutError;
@equal("model.error", "exception") showExceptionError;
@notEmpty("model.data") hasData;
_reports = [];
@computed("siteSettings.dashboard_hidden_reports")
get isHidden() {
return (this.siteSettings.dashboard_hidden_reports || "")
.split("|")
.filter(Boolean)
.includes(this.dataSourceName);
}),
}
didReceiveAttrs() {
this._super(...arguments);
super.didReceiveAttrs(...arguments);
let startDate = moment();
if (this.filters && isPresent(this.filters.startDate)) {
@ -88,42 +96,35 @@ export default Component.extend({
} else if (this.dataSourceName) {
this._fetchReport();
}
},
showError: or("showTimeoutError", "showExceptionError", "showNotFoundError"),
showNotFoundError: equal("model.error", "not_found"),
showTimeoutError: equal("model.error", "timeout"),
showExceptionError: equal("model.error", "exception"),
hasData: notEmpty("model.data"),
}
@discourseComputed("dataSourceName", "model.type")
dasherizedDataSourceName(dataSourceName, type) {
return (dataSourceName || type || "undefined").replace(/_/g, "-");
},
}
@discourseComputed("dataSourceName", "model.type")
dataSource(dataSourceName, type) {
dataSourceName = dataSourceName || type;
return `/admin/reports/${dataSourceName}`;
},
}
@discourseComputed("displayedModes.length")
showModes(displayedModesLength) {
return displayedModesLength > 1;
},
}
@discourseComputed("currentMode")
isChartMode(currentMode) {
return currentMode === "chart";
},
}
@action
changeGrouping(grouping) {
this.send("refreshReport", {
chartGrouping: grouping,
});
},
}
@discourseComputed("currentMode", "model.modes", "forcedModes")
displayedModes(currentMode, reportModes, forcedModes) {
@ -139,12 +140,12 @@ export default Component.extend({
icon: mode === "table" ? "table" : "signal",
};
});
},
}
@discourseComputed("currentMode")
modeComponent(currentMode) {
return `admin-report-${currentMode.replace(/_/g, "-")}`;
},
}
@discourseComputed(
"dataSourceName",
@ -178,7 +179,7 @@ export default Component.extend({
.join(":");
return reportKey;
},
}
@discourseComputed("options.chartGrouping", "model.chartData.length")
chartGroupings(grouping, count) {
@ -192,7 +193,7 @@ export default Component.extend({
class: `chart-grouping ${grouping === id ? "active" : "inactive"}`,
};
});
},
}
@action
onChangeDateRange(range) {
@ -200,7 +201,7 @@ export default Component.extend({
startDate: range.from,
endDate: range.to,
});
},
}
@action
applyFilter(id, value) {
@ -215,7 +216,7 @@ export default Component.extend({
this.send("refreshReport", {
filters: customFilters,
});
},
}
@action
refreshReport(options = {}) {
@ -238,7 +239,7 @@ export default Component.extend({
? this.get("filters.customFilters")
: options.filters,
});
},
}
@action
exportCsv() {
@ -254,7 +255,7 @@ export default Component.extend({
}
exportEntity("report", args).then(outputExportResult);
},
}
@action
onChangeMode(mode) {
@ -263,7 +264,7 @@ export default Component.extend({
this.send("refreshReport", {
chartGrouping: null,
});
},
}
_computeReport() {
if (!this.element || this.isDestroying || this.isDestroyed) {
@ -306,7 +307,7 @@ export default Component.extend({
}
this._renderReport(report, this.forcedModes, this.currentMode);
},
}
_renderReport(report, forcedModes, currentMode) {
const modes = forcedModes ? forcedModes.split(",") : report.modes;
@ -317,11 +318,9 @@ export default Component.extend({
currentMode,
options: this._buildOptions(currentMode, report),
});
},
}
_fetchReport() {
this._super(...arguments);
this.setProperties({ isLoading: true, rateLimitationString: null });
next(() => {
@ -349,7 +348,7 @@ export default Component.extend({
ReportLoader.enqueue(this.dataSourceName, payload.data, callback);
});
},
}
_buildPayload(facets) {
let payload = { data: { facets } };
@ -375,7 +374,7 @@ export default Component.extend({
}
return payload;
},
}
_buildOptions(mode, report) {
if (mode === "table") {
@ -393,7 +392,7 @@ export default Component.extend({
})
);
}
},
}
_loadReport(jsonReport) {
Report.fillMissingDates(jsonReport, { filledField: "chartData" });
@ -423,5 +422,5 @@ export default Component.extend({
}
return Report.create(jsonReport);
},
});
}
}

@ -6,8 +6,10 @@ import { isDocumentRTL } from "discourse/lib/text-direction";
import { action } from "@ember/object";
import { next } from "@ember/runloop";
export default Component.extend({
warning: null,
export default class AdminThemeEditor extends Component {
warning = null;
@fmt("fieldName", "currentTargetName", "%@|%@") editorId;
@discourseComputed("theme.targets", "onlyOverridden", "showAdvanced")
visibleTargets(targets, onlyOverridden, showAdvanced) {
@ -20,7 +22,7 @@ export default Component.extend({
}
return target.edited;
});
},
}
@discourseComputed("currentTargetName", "onlyOverridden", "theme.fields")
visibleFields(targetName, onlyOverridden, fields) {
@ -29,7 +31,7 @@ export default Component.extend({
fields = fields.filter((field) => field.edited);
}
return fields;
},
}
@discourseComputed("currentTargetName", "fieldName")
activeSectionMode(targetName, fieldName) {
@ -43,7 +45,7 @@ export default Component.extend({
return "scss";
}
return fieldName && fieldName.includes("scss") ? "scss" : "html";
},
}
@discourseComputed("currentTargetName", "fieldName")
placeholder(targetName, fieldName) {
@ -58,30 +60,27 @@ export default Component.extend({
});
}
return "";
},
}
@discourseComputed("fieldName", "currentTargetName", "theme")
activeSection: {
get(fieldName, target, model) {
return model.getField(target, fieldName);
},
set(value, fieldName, target, model) {
model.setField(target, fieldName, value);
return value;
},
},
get activeSection() {
return this.model.getField(this.currentTargetName, this.fieldName);
}
editorId: fmt("fieldName", "currentTargetName", "%@|%@"),
set activeSection(value) {
this.theme.setField(this.fieldName, value);
return value;
}
@discourseComputed("maximized")
maximizeIcon(maximized) {
return maximized ? "discourse-compress" : "discourse-expand";
},
}
@discourseComputed("currentTargetName", "theme.targets")
showAddField(currentTargetName, targets) {
return targets.find((t) => t.name === currentTargetName).customNames;
},
}
@discourseComputed(
"currentTargetName",
@ -90,52 +89,55 @@ export default Component.extend({
)
error(target, fieldName) {
return this.theme.getError(target, fieldName);
},
}
@action
toggleShowAdvanced(event) {
event?.preventDefault();
this.toggleProperty("showAdvanced");
},
}
@action
toggleAddField(event) {
event?.preventDefault();
this.toggleProperty("addingField");
},
}
@action
toggleMaximize(event) {
event?.preventDefault();
this.toggleProperty("maximized");
next(() => this.appEvents.trigger("ace:resize"));
},
}
actions: {
cancelAddField() {
this.set("addingField", false);
},
@action
cancelAddField() {
this.set("addingField", false);
}
addField(name) {
if (!name) {
return;
}
name = name.replace(/[^a-zA-Z0-9-_/]/g, "");
this.theme.setField(this.currentTargetName, name, "");
this.setProperties({ newFieldName: "", addingField: false });
this.fieldAdded(this.currentTargetName, name);
},
@action
addField(name) {
if (!name) {
return;
}
name = name.replace(/[^a-zA-Z0-9-_/]/g, "");
this.theme.setField(this.currentTargetName, name, "");
this.setProperties({ newFieldName: "", addingField: false });
this.fieldAdded(this.currentTargetName, name);
}
onlyOverriddenChanged(value) {
this.onlyOverriddenChanged(value);
},
@action
onlyOverriddenChanged(value) {
this.onlyOverriddenChanged(value);
}
save() {
this.attrs.save();
},
@action
save() {
this.attrs.save();
}
setWarning(message) {
this.set("warning", message);
},
},
});
@action
setWarning(message) {
this.set("warning", message);
}
}

@ -1,23 +1,27 @@
import Component from "@ember/component";
import { classNames } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import { alias, equal } from "@ember/object/computed";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import { action } from "@ember/object";
import I18n from "I18n";
import { inject as service } from "@ember/service";
export default Component.extend({
classNames: ["watched-word"],
dialog: service(),
@classNames("watched-word")
export default class AdminWatchedWord extends Component {
@service dialog;
isReplace: equal("actionKey", "replace"),
isTag: equal("actionKey", "tag"),
isLink: equal("actionKey", "link"),
isCaseSensitive: alias("word.case_sensitive"),
@equal("actionKey", "replace") isReplace;
@equal("actionKey", "tag") isTag;
@equal("actionKey", "link") isLink;
@alias("word.case_sensitive") isCaseSensitive;
@discourseComputed("word.replacement")
tags(replacement) {
return replacement.split(",");
},
}
@action
deleteWord() {
@ -33,5 +37,5 @@ export default Component.extend({
})
);
});
},
});
}
}

@ -1,14 +1,15 @@
import Component from "@ember/component";
export default Component.extend({
export default class AdminWrapper extends Component {
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
document.querySelector("html").classList.add("admin-area");
document.querySelector("body").classList.add("admin-interface");
},
}
willDestroyElement() {
this._super(...arguments);
super.willDestroyElement(...arguments);
document.querySelector("html").classList.remove("admin-area");
document.querySelector("body").classList.remove("admin-interface");
},
});
}
}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "",
});
@tagName("")
export default class CancelLink extends Component {}

@ -1,3 +1,4 @@
import { classNames } from "@ember-decorators/component";
import { action, computed } from "@ember/object";
import Component from "@ember/component";
import { observes } from "discourse-common/utils/decorators";
@ -9,20 +10,20 @@ import { observes } from "discourse-common/utils/decorators";
@param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor.
@params valid is a boolean indicating if the input field is a valid color.
**/
export default Component.extend({
classNames: ["color-picker"],
@classNames("color-picker")
export default class ColorInput extends Component {
onlyHex = true;
styleSelection = true;
onlyHex: true,
styleSelection: true,
maxlength: computed("onlyHex", function () {
@computed("onlyHex")
get maxlength() {
return this.onlyHex ? 6 : null;
}),
}
normalizedHexValue: computed("hexValue", function () {
@computed("hexValue")
get normalizedHexValue() {
return this.normalize(this.hexValue);
}),
}
normalize(color) {
if (this._valid(color)) {
@ -40,19 +41,19 @@ export default Component.extend({
}
}
return color;
},
}
@action
onHexInput(color) {
if (this.attrs.onChangeColor) {
this.attrs.onChangeColor(this.normalize(color || ""));
}
},
}
@action
onPickerInput(event) {
this.set("hexValue", event.target.value.replace("#", ""));
},
}
@observes("hexValue", "brightnessValue", "valid")
hexValueChanged() {
@ -65,9 +66,9 @@ export default Component.extend({
if (this._valid()) {
this.element.querySelector(".picker").value = this.normalize(hex);
}
},
}
_valid(color = this.hexValue) {
return /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color);
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class DashboardNewFeatureItem extends Component {}

@ -1,18 +1,19 @@
import { classNameBindings, classNames } from "@ember-decorators/component";
import Component from "@ember/component";
import { action, computed } from "@ember/object";
import { ajax } from "discourse/lib/ajax";
export default Component.extend({
newFeatures: null,
classNames: ["section", "dashboard-new-features"],
classNameBindings: ["hasUnseenFeatures:ordered-first"],
releaseNotesLink: null,
@classNames("section", "dashboard-new-features")
@classNameBindings("hasUnseenFeatures:ordered-first")
export default class DashboardNewFeatures extends Component {
newFeatures = null;
releaseNotesLink = null;
init() {
this._super(...arguments);
constructor() {
super(...arguments);
ajax("/admin/dashboard/new-features.json").then((json) => {
if (!this.element || this.isDestroying || this.isDestroyed) {
if (this.isDestroying || this.isDestroyed) {
return;
}
@ -22,16 +23,17 @@ export default Component.extend({
releaseNotesLink: json.release_notes_link,
});
});
},
}
columnCountClass: computed("newFeatures", function () {
@computed("newFeatures")
get columnCountClass() {
return this.newFeatures.length > 2 ? "three-or-more-items" : "";
}),
}
@action
dismissNewFeatures() {
ajax("/admin/dashboard/mark-new-features-as-seen.json", {
type: "PUT",
}).then(() => this.set("hasUnseenFeatures", false));
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class DashboardProblems extends Component {}

@ -1,17 +1,19 @@
import { action, computed } from "@ember/object";
import { inject as service } from "@ember/service";
import { reads } from "@ember/object/computed";
import Component from "@ember/component";
import I18n from "I18n";
import discourseComputed from "discourse-common/utils/decorators";
import { reads } from "@ember/object/computed";
import { inject as service } from "@ember/service";
export default Component.extend({
dialog: service(),
editorId: reads("fieldName"),
export default class EmailStylesEditor extends Component {
@service dialog;
@reads("fieldName") editorId;
@discourseComputed("fieldName")
currentEditorMode(fieldName) {
return fieldName === "css" ? "scss" : fieldName;
},
}
@discourseComputed("fieldName", "styles.html", "styles.css")
resetDisabled(fieldName) {
@ -19,36 +21,36 @@ export default Component.extend({
this.get(`styles.${fieldName}`) ===
this.get(`styles.default_${fieldName}`)
);
},
}
@discourseComputed("styles", "fieldName")
editorContents: {
get(styles, fieldName) {
return styles[fieldName];
},
set(value, styles, fieldName) {
styles.setField(fieldName, value);
return value;
},
},
@computed("styles", "fieldName")
get editorContents() {
return this.styles[this.fieldName];
}
actions: {
reset() {
this.dialog.yesNoConfirm({
message: I18n.t("admin.customize.email_style.reset_confirm", {
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`),
}),
didConfirm: () => {
this.styles.setField(
this.fieldName,
this.styles.get(`default_${this.fieldName}`)
);
this.notifyPropertyChange("editorContents");
},
});
},
save() {
this.attrs.save();
},
},
});
set editorContents(value) {
this.styles.setField(this.fieldName, value);
return value;
}
@action
reset() {
this.dialog.yesNoConfirm({
message: I18n.t("admin.customize.email_style.reset_confirm", {
fieldName: I18n.t(`admin.customize.email_style.${this.fieldName}`),
}),
didConfirm: () => {
this.styles.setField(
this.fieldName,
this.styles.get(`default_${this.fieldName}`)
);
this.notifyPropertyChange("editorContents");
},
});
}
@action
save() {
this.attrs.save();
}
}

@ -1,85 +1,91 @@
import { action } from "@ember/object";
import { tagName } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import { or } from "@ember/object/computed";
import Category from "discourse/models/category";
import Component from "@ember/component";
import I18n from "I18n";
import { bufferedProperty } from "discourse/mixins/buffered-content";
import discourseComputed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { or } from "@ember/object/computed";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default Component.extend(bufferedProperty("host"), {
editToggled: false,
tagName: "tr",
categoryId: null,
category: null,
dialog: service(),
@tagName("tr")
export default class EmbeddableHost extends Component.extend(
bufferedProperty("host")
) {
@service dialog;
editToggled = false;
categoryId = null;
category = null;
editing: or("host.isNew", "editToggled"),
@or("host.isNew", "editToggled") editing;
init() {
this._super(...arguments);
constructor() {
super(...arguments);
const host = this.host;
const categoryId = host.category_id || this.site.uncategorized_category_id;
const category = Category.findById(categoryId);
host.set("category", category);
},
}
@discourseComputed("buffered.host", "host.isSaving")
cantSave(host, isSaving) {
return isSaving || isEmpty(host);
},
}
actions: {
edit() {
this.set("categoryId", this.get("host.category.id"));
this.set("editToggled", true);
},
@action
edit() {
this.set("categoryId", this.get("host.category.id"));
this.set("editToggled", true);
}
save() {
if (this.cantSave) {
return;
}
@action
save() {
if (this.cantSave) {
return;
}
const props = this.buffered.getProperties(
"host",
"allowed_paths",
"class_name"
);
props.category_id = this.categoryId;
const props = this.buffered.getProperties(
"host",
"allowed_paths",
"class_name"
);
props.category_id = this.categoryId;
const host = this.host;
const host = this.host;
host
.save(props)
.then(() => {
host.set("category", Category.findById(this.categoryId));
this.set("editToggled", false);
})
.catch(popupAjaxError);
},
delete() {
return this.dialog.confirm({
message: I18n.t("admin.embedding.confirm_delete"),
didConfirm: () => {
return this.host.destroyRecord().then(() => {
this.deleteHost(this.host);
});
},
});
},
cancel() {
const host = this.host;
if (host.get("isNew")) {
this.deleteHost(host);
} else {
this.rollbackBuffer();
host
.save(props)
.then(() => {
host.set("category", Category.findById(this.categoryId));
this.set("editToggled", false);
}
},
},
});
})
.catch(popupAjaxError);
}
@action
delete() {
return this.dialog.confirm({
message: I18n.t("admin.embedding.confirm_delete"),
didConfirm: () => {
return this.host.destroyRecord().then(() => {
this.deleteHost(this.host);
});
},
});
}
@action
cancel() {
const host = this.host;
if (host.get("isNew")) {
this.deleteHost(host);
} else {
this.rollbackBuffer();
this.set("editToggled", false);
}
}
}

@ -1,33 +1,33 @@
import { classNames } from "@ember-decorators/component";
import { computed } from "@ember/object";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import { dasherize } from "@ember/string";
export default Component.extend({
classNames: ["embed-setting"],
@classNames("embed-setting")
export default class EmbeddingSetting extends Component {
@discourseComputed("field")
inputId(field) {
return dasherize(field);
},
}
@discourseComputed("field")
translationKey(field) {
return `admin.embedding.${field}`;
},
}
@discourseComputed("type")
isCheckbox(type) {
return type === "checkbox";
},
}
@discourseComputed("value")
checked: {
get(value) {
return !!value;
},
set(value) {
this.set("value", value);
return value;
},
},
});
@computed("value")
get checked() {
return !!this.value;
}
set(value) {
this.set("value", value);
return value;
}
}

@ -1,3 +1,4 @@
import { classNameBindings } from "@ember-decorators/component";
import Component from "@ember/component";
import I18n from "I18n";
import discourseComputed from "discourse-common/utils/decorators";
@ -6,12 +7,12 @@ import { action, set, setProperties } from "@ember/object";
import { schedule } from "@ember/runloop";
import discourseLater from "discourse-common/lib/later";
export default Component.extend({
classNameBindings: [":value-list", ":emoji-list"],
values: null,
validationMessage: null,
emojiPickerIsActive: false,
isEditorFocused: false,
@classNameBindings(":value-list", ":emoji-list")
export default class EmojiValueList extends Component {
values = null;
validationMessage = null;
emojiPickerIsActive = false;
isEditorFocused = false;
@discourseComputed("values")
collection(values) {
@ -28,14 +29,14 @@ export default Component.extend({
emojiUrl: emojiUrlFor(value),
};
});
},
}
@action
closeEmojiPicker() {
this.collection.setEach("isEditing", false);
this.set("emojiPickerIsActive", false);
this.set("isEditorFocused", false);
},
}
@action
emojiSelected(code) {
@ -65,12 +66,12 @@ export default Component.extend({
this.set("emojiPickerIsActive", false);
this.set("isEditorFocused", false);
},
}
@discourseComputed("collection")
showUpDownButtons(collection) {
return collection.length - 1 ? true : false;
},
}
_splitValues(values) {
if (values && values.length) {
@ -91,7 +92,7 @@ export default Component.extend({
} else {
return [];
}
},
}
@action
editValue(index) {
@ -111,12 +112,12 @@ export default Component.extend({
}
}, 100);
});
},
}
@action
removeValue(value) {
this._removeValue(value);
},
}
@action
shift(operation, index) {
@ -133,7 +134,7 @@ export default Component.extend({
this.collection.insertAt(futureIndex, shiftedEmoji);
this._saveValues();
},
}
_validateInput(input) {
this.set("validationMessage", null);
@ -147,12 +148,12 @@ export default Component.extend({
}
return true;
},
}
_removeValue(value) {
this.collection.removeObject(value);
this._saveValues();
},
}
_replaceValue(index, newValue) {
const item = this.collection[index];
@ -161,9 +162,9 @@ export default Component.extend({
}
set(item, "value", newValue);
this._saveValues();
},
}
_saveValues() {
this.set("values", this.collection.mapBy("value").join("|"));
},
});
}
}

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
classNames: ["flag-user-lists"],
});
@classNames("flag-user-lists")
export default class FlagUserLists extends Component {}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class FlagUser extends Component {}

@ -2,10 +2,10 @@ import { observes, on } from "discourse-common/utils/decorators";
import Component from "@ember/component";
import highlightSyntax from "discourse/lib/highlight-syntax";
export default Component.extend({
export default class HighlightedCode extends Component {
@on("didInsertElement")
@observes("code")
_refresh() {
highlightSyntax(this.element, this.siteSettings, this.session);
},
});
}
}

@ -1,15 +1,15 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
import { action } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
classNames: ["inline-edit"],
buffer: null,
bufferModelId: null,
@classNames("inline-edit")
export default class InlineEditCheckbox extends Component {
buffer = null;
bufferModelId = null;
didReceiveAttrs() {
this._super(...arguments);
super.didReceiveAttrs(...arguments);
if (this.modelId !== this.bufferModelId) {
// HACK: The condition above ensures this method is called only when its
@ -24,21 +24,21 @@ export default Component.extend({
bufferModelId: this.modelId,
});
}
},
}
@discourseComputed("checked", "buffer")
changed(checked, buffer) {
return !!checked !== !!buffer;
},
}
@action
apply() {
this.set("checked", this.buffer);
this.action();
},
}
@action
cancel() {
this.set("buffer", this.checked);
},
});
}
}

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
classNames: ["install-theme-item"],
});
@classNames("install-theme-item")
export default class InstallThemeItem extends Component {}

@ -1,3 +1,5 @@
import { classNames } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import AdminUser from "admin/models/admin-user";
import Component from "@ember/component";
import EmberObject, { action } from "@ember/object";
@ -6,12 +8,11 @@ import { ajax } from "discourse/lib/ajax";
import copyText from "discourse/lib/copy-text";
import discourseComputed from "discourse-common/utils/decorators";
import discourseLater from "discourse-common/lib/later";
import { inject as service } from "@ember/service";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default Component.extend({
classNames: ["ip-lookup"],
dialog: service(),
@classNames("ip-lookup")
export default class IpLookup extends Component {
@service dialog;
@discourseComputed("other_accounts.length", "totalOthersWithSameIP")
otherAccountsToDelete(otherAccountsLength, totalOthersWithSameIP) {
@ -19,101 +20,100 @@ export default Component.extend({
const total = Math.min(50, totalOthersWithSameIP || 0);
const visible = Math.min(50, otherAccountsLength || 0);
return Math.max(visible, total);
},
}
@action
hide(event) {
event?.preventDefault();
this.set("show", false);
},
}
actions: {
lookup() {
this.set("show", true);
@action
lookup() {
this.set("show", true);
if (!this.location) {
ajax("/admin/users/ip-info", {
data: { ip: this.ip },
}).then((location) =>
this.set("location", EmberObject.create(location))
);
}
if (!this.location) {
ajax("/admin/users/ip-info", {
data: { ip: this.ip },
}).then((location) => this.set("location", EmberObject.create(location)));
}
if (!this.other_accounts) {
this.set("otherAccountsLoading", true);
if (!this.other_accounts) {
this.set("otherAccountsLoading", true);
const data = {
ip: this.ip,
exclude: this.userId,
order: "trust_level DESC",
};
const data = {
ip: this.ip,
exclude: this.userId,
order: "trust_level DESC",
};
ajax("/admin/users/total-others-with-same-ip", {
data,
}).then((result) => this.set("totalOthersWithSameIP", result.total));
ajax("/admin/users/total-others-with-same-ip", {
data,
}).then((result) => this.set("totalOthersWithSameIP", result.total));
AdminUser.findAll("active", data).then((users) => {
this.setProperties({
other_accounts: users,
otherAccountsLoading: false,
});
AdminUser.findAll("active", data).then((users) => {
this.setProperties({
other_accounts: users,
otherAccountsLoading: false,
});
}
},
copy() {
let text = `IP: ${this.ip}\n`;
const location = this.location;
if (location) {
if (location.hostname) {
text += `${I18n.t("ip_lookup.hostname")}: ${location.hostname}\n`;
}
text += I18n.t("ip_lookup.location");
if (location.location) {
text += `: ${location.location}\n`;
} else {
text += `: ${I18n.t("ip_lookup.location_not_found")}\n`;
}
if (location.organization) {
text += I18n.t("ip_lookup.organisation");
text += `: ${location.organization}\n`;
}
}
const $copyRange = $('<p id="copy-range"></p>');
$copyRange.html(text.trim().replace(/\n/g, "<br>"));
$(document.body).append($copyRange);
if (copyText(text, $copyRange[0])) {
this.set("copied", true);
discourseLater(() => this.set("copied", false), 2000);
}
$copyRange.remove();
},
deleteOtherAccounts() {
this.dialog.yesNoConfirm({
message: I18n.t("ip_lookup.confirm_delete_other_accounts"),
didConfirm: () => {
this.setProperties({
other_accounts: null,
otherAccountsLoading: true,
totalOthersWithSameIP: null,
});
ajax("/admin/users/delete-others-with-same-ip.json", {
type: "DELETE",
data: {
ip: this.ip,
exclude: this.userId,
order: "trust_level DESC",
},
})
.catch(popupAjaxError)
.finally(this.send("lookup"));
},
});
},
},
});
}
}
@action
copy() {
let text = `IP: ${this.ip}\n`;
const location = this.location;
if (location) {
if (location.hostname) {
text += `${I18n.t("ip_lookup.hostname")}: ${location.hostname}\n`;
}
text += I18n.t("ip_lookup.location");
if (location.location) {
text += `: ${location.location}\n`;
} else {
text += `: ${I18n.t("ip_lookup.location_not_found")}\n`;
}
if (location.organization) {
text += I18n.t("ip_lookup.organisation");
text += `: ${location.organization}\n`;
}
}
const $copyRange = $('<p id="copy-range"></p>');
$copyRange.html(text.trim().replace(/\n/g, "<br>"));
$(document.body).append($copyRange);
if (copyText(text, $copyRange[0])) {
this.set("copied", true);
discourseLater(() => this.set("copied", false), 2000);
}
$copyRange.remove();
}
@action
deleteOtherAccounts() {
this.dialog.yesNoConfirm({
message: I18n.t("ip_lookup.confirm_delete_other_accounts"),
didConfirm: () => {
this.setProperties({
other_accounts: null,
otherAccountsLoading: true,
totalOthersWithSameIP: null,
});
ajax("/admin/users/delete-others-with-same-ip.json", {
type: "DELETE",
data: {
ip: this.ip,
exclude: this.userId,
order: "trust_level DESC",
},
})
.catch(popupAjaxError)
.finally(this.send("lookup"));
},
});
}
}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "tr",
});
@tagName("tr")
export default class ModerationHistoryItem extends Component {}

@ -1,3 +1,5 @@
import { tagName } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import Component from "@ember/component";
import I18n from "I18n";
import Permalink from "admin/models/permalink";
@ -5,16 +7,18 @@ import discourseComputed, { bind } from "discourse-common/utils/decorators";
import { fmt } from "discourse/lib/computed";
import { schedule } from "@ember/runloop";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default Component.extend({
tagName: "",
dialog: service(),
formSubmitted: false,
permalinkType: "topic_id",
permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"),
action: null,
permalinkTypeValue: null,
@tagName("")
export default class PermalinkForm extends Component {
@service dialog;
formSubmitted = false;
permalinkType = "topic_id";
@fmt("permalinkType", "admin.permalink.%@") permalinkTypePlaceholder;
action = null;
permalinkTypeValue = null;
@discourseComputed
permalinkTypes() {
@ -25,21 +29,21 @@ export default Component.extend({
{ id: "tag_name", name: I18n.t("admin.permalink.tag_name") },
{ id: "external_url", name: I18n.t("admin.permalink.external_url") },
];
},
}
@bind
focusPermalink() {
schedule("afterRender", () =>
document.querySelector(".permalink-url")?.focus()
);
},
}
@action
submitFormOnEnter(event) {
if (event.key === "Enter") {
this.onSubmit();
}
},
}
@action
onSubmit() {
@ -84,5 +88,5 @@ export default Component.extend({
}
);
}
},
});
}
}

@ -1,16 +1,16 @@
import FilterComponent from "admin/components/report-filters/filter";
import { action } from "@ember/object";
export default FilterComponent.extend({
checked: false,
export default class Bool extends FilterComponent {
checked = false;
didReceiveAttrs() {
this._super(...arguments);
super.didReceiveAttrs(...arguments);
this.set("checked", !!this.filter.default);
},
}
@action
onChange() {
this.applyFilter(this.filter.id, !this.checked || undefined);
},
});
}
}

@ -1,12 +1,12 @@
import { readOnly } from "@ember/object/computed";
import FilterComponent from "admin/components/report-filters/filter";
import { action } from "@ember/object";
import { readOnly } from "@ember/object/computed";
export default FilterComponent.extend({
category: readOnly("filter.default"),
export default class Category extends FilterComponent {
@readOnly("filter.default") category;
@action
onChange(categoryId) {
this.applyFilter(this.filter.id, categoryId || undefined);
},
});
}
}

@ -1,9 +1,9 @@
import Component from "@ember/component";
import { action } from "@ember/object";
export default Component.extend({
export default class Filter extends Component {
@action
onChange(value) {
this.applyFilter(this.filter.id, value);
},
});
}
}

@ -1,18 +1,18 @@
import FilterComponent from "admin/components/report-filters/filter";
import { classNames } from "@ember-decorators/component";
import { computed } from "@ember/object";
import FilterComponent from "admin/components/report-filters/filter";
export default FilterComponent.extend({
classNames: ["group-filter"],
@classNames("group-filter")
export default class Group extends FilterComponent {
@computed
get groupOptions() {
return (this.site.groups || []).map((group) => {
return { name: group["name"], value: group["id"] };
});
},
}
@computed("filter.default")
get groupId() {
return this.filter.default ? parseInt(this.filter.default, 10) : null;
},
});
}
}

@ -1,3 +1,3 @@
import FilterComponent from "admin/components/report-filters/filter";
export default FilterComponent.extend();
export default class List extends FilterComponent {}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class ResumableUpload extends Component {}

@ -17,7 +17,7 @@
<DButton
@type="submit"
@class="btn-default"
@action={{action "submit"}}
@action={{action "submitForm"}}
@disabled={{this.formSubmitted}}
@label="admin.logs.screened_ips.form.add"
/>

@ -1,9 +1,11 @@
import { action } from "@ember/object";
import { classNames, tagName } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component";
import I18n from "I18n";
import ScreenedIpAddress from "admin/models/screened-ip-address";
import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
/**
A form to create an IP address that will be blocked or allowed.
@ -16,12 +18,13 @@ import { inject as service } from "@ember/service";
as an argument.
**/
export default Component.extend({
tagName: "form",
dialog: service(),
classNames: ["screened-ip-address-form", "inline-form"],
formSubmitted: false,
actionName: "block",
@tagName("form")
@classNames("screened-ip-address-form", "inline-form")
export default class ScreenedIpAddressForm extends Component {
@service dialog;
formSubmitted = false;
actionName = "block";
@discourseComputed("siteSettings.use_admin_ip_allowlist")
actionNames(adminAllowlistEnabled) {
@ -46,43 +49,42 @@ export default Component.extend({
},
];
}
},
}
focusInput() {
schedule("afterRender", () => {
this.element.querySelector("input").focus();
});
},
}
actions: {
submit() {
if (!this.formSubmitted) {
this.set("formSubmitted", true);
const screenedIpAddress = ScreenedIpAddress.create({
ip_address: this.ip_address,
action_name: this.actionName,
});
screenedIpAddress
.save()
.then((result) => {
this.setProperties({ ip_address: "", formSubmitted: false });
this.action(ScreenedIpAddress.create(result.screened_ip_address));
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
@action
submitForm() {
if (!this.formSubmitted) {
this.set("formSubmitted", true);
const screenedIpAddress = ScreenedIpAddress.create({
ip_address: this.ip_address,
action_name: this.actionName,
});
screenedIpAddress
.save()
.then((result) => {
this.setProperties({ ip_address: "", formSubmitted: false });
this.action(ScreenedIpAddress.create(result.screened_ip_address));
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
}
},
},
});
});
}
}
}

@ -1,15 +1,16 @@
import { classNameBindings } from "@ember-decorators/component";
import Component from "@ember/component";
import I18n from "I18n";
import { isEmpty } from "@ember/utils";
import { on } from "discourse-common/utils/decorators";
import { set } from "@ember/object";
import { action, set } from "@ember/object";
export default Component.extend({
classNameBindings: [":value-list", ":secret-value-list"],
inputDelimiter: null,
collection: null,
values: null,
validationMessage: null,
@classNameBindings(":value-list", ":secret-value-list")
export default class SecretValueList extends Component {
inputDelimiter = null;
collection = null;
values = null;
validationMessage = null;
@on("didReceiveAttrs")
_setupCollection() {
@ -19,41 +20,43 @@ export default Component.extend({
"collection",
this._splitValues(values, this.inputDelimiter || "\n")
);
},
}
actions: {
changeKey(index, event) {
const newValue = event.target.value;
@action
changeKey(index, event) {
const newValue = event.target.value;
if (this._checkInvalidInput(newValue)) {
return;
}
if (this._checkInvalidInput(newValue)) {
return;
}
this._replaceValue(index, newValue, "key");
},
this._replaceValue(index, newValue, "key");
}
changeSecret(index, event) {
const newValue = event.target.value;
@action
changeSecret(index, event) {
const newValue = event.target.value;
if (this._checkInvalidInput(newValue)) {
return;
}
if (this._checkInvalidInput(newValue)) {
return;
}
this._replaceValue(index, newValue, "secret");
},
this._replaceValue(index, newValue, "secret");
}
addValue() {
if (this._checkInvalidInput([this.newKey, this.newSecret])) {
return;
}
this._addValue(this.newKey, this.newSecret);
this.setProperties({ newKey: "", newSecret: "" });
},
@action
addValue() {
if (this._checkInvalidInput([this.newKey, this.newSecret])) {
return;
}
this._addValue(this.newKey, this.newSecret);
this.setProperties({ newKey: "", newSecret: "" });
}
removeValue(value) {
this._removeValue(value);
},
},
@action
removeValue(value) {
this._removeValue(value);
}
_checkInvalidInput(inputs) {
this.set("validationMessage", null);
@ -66,25 +69,25 @@ export default Component.extend({
return true;
}
}
},
}
_addValue(value, secret) {
this.collection.addObject({ key: value, secret });
this._saveValues();
},
}
_removeValue(value) {
const collection = this.collection;
collection.removeObject(value);
this._saveValues();
},
}
_replaceValue(index, newValue, keyName) {
let item = this.collection[index];
set(item, keyName, newValue);
this._saveValues();
},
}
_saveValues() {
this.set(
@ -95,7 +98,7 @@ export default Component.extend({
})
.join("\n")
);
},
}
_splitValues(values, delimiter) {
if (values && values.length) {
@ -113,5 +116,5 @@ export default Component.extend({
} else {
return [];
}
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class SettingValidationMessage extends Component {}

@ -1,4 +1,5 @@
import { tagName } from "@ember-decorators/component";
import Component from "@ember/component";
export default Component.extend({
tagName: "",
});
@tagName("")
export default class SilenceDetails extends Component {}

@ -1,34 +1,36 @@
import { classNameBindings } from "@ember-decorators/component";
import { empty } from "@ember/object/computed";
import Component from "@ember/component";
import { action } from "@ember/object";
import { empty } from "@ember/object/computed";
import discourseComputed, { on } from "discourse-common/utils/decorators";
export default Component.extend({
classNameBindings: [":simple-list", ":value-list"],
inputEmpty: empty("newValue"),
inputDelimiter: null,
newValue: "",
collection: null,
values: null,
@classNameBindings(":simple-list", ":value-list")
export default class SimpleList extends Component {
@empty("newValue") inputEmpty;
inputDelimiter = null;
newValue = "";
collection = null;
values = null;
@on("didReceiveAttrs")
_setupCollection() {
this.set("collection", this._splitValues(this.values, this.inputDelimiter));
},
}
keyDown(event) {
if (event.which === 13) {
this.addValue(this.newValue);
return;
}
},
}
@action
changeValue(index, event) {
this.collection.replace(index, 1, [event.target.value]);
this.collection.arrayContentDidChange(index);
this._onChange();
},
}
@action
addValue(newValue) {
@ -39,13 +41,13 @@ export default Component.extend({
this.set("newValue", null);
this.collection.addObject(newValue);
this._onChange();
},
}
@action
removeValue(value) {
this.collection.removeObject(value);
this._onChange();
},
}
@action
shift(operation, index) {
@ -62,20 +64,20 @@ export default Component.extend({
this.collection.insertAt(futureIndex, shiftedValue);
this._onChange();
},
}
_onChange() {
this.onChange?.(this.collection);
},
}
@discourseComputed("collection")
showUpDownButtons(collection) {
return collection.length - 1 ? true : false;
},
}
_splitValues(values, delimiter) {
return values && values.length
? values.split(delimiter || "\n").filter(Boolean)
: [];
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class SiteCustomizationChangeDetails extends Component {}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class SiteCustomizationChangeField extends Component {}

@ -1,18 +1,21 @@
import { readOnly } from "@ember/object/computed";
import BufferedContent from "discourse/mixins/buffered-content";
import Component from "@ember/component";
import SettingComponent from "admin/mixins/setting-component";
import SiteSetting from "admin/models/site-setting";
import { readOnly } from "@ember/object/computed";
export default Component.extend(BufferedContent, SettingComponent, {
updateExistingUsers: null,
export default class SiteSettingComponent extends Component.extend(
BufferedContent,
SettingComponent
) {
updateExistingUsers = null;
@readOnly("setting.staffLogFilter") staffLogFilter;
_save() {
const setting = this.buffered;
return SiteSetting.update(setting.get("setting"), setting.get("value"), {
updateExistingUsers: this.updateExistingUsers,
});
},
staffLogFilter: readOnly("setting.staffLogFilter"),
});
}
}

@ -1,19 +1,18 @@
import { computed } from "@ember/object";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import { isEmpty } from "@ember/utils";
export default Component.extend({
@discourseComputed("value")
enabled: {
get(value) {
if (isEmpty(value)) {
return false;
}
return value.toString() === "true";
},
set(value) {
this.set("value", value ? "true" : "false");
return value;
},
},
});
export default class Bool extends Component {
@computed("value")
get enabled() {
if (isEmpty(this.value)) {
return false;
}
return this.value.toString() === "true";
}
set enabled(value) {
this.set("value", value ? "true" : "false");
return value;
}
}

@ -1,15 +1,15 @@
import { action, computed } from "@ember/object";
import Category from "discourse/models/category";
import Component from "@ember/component";
import { computed } from "@ember/object";
export default Component.extend({
selectedCategories: computed("value", function () {
export default class CategoryList extends Component {
@computed("value")
get selectedCategories() {
return Category.findByIds(this.value.split("|").filter(Boolean));
}),
}
actions: {
onChangeSelectedCategories(value) {
this.set("value", (value || []).mapBy("id").join("|"));
},
},
});
@action
onChangeSelectedCategories(value) {
this.set("value", (value || []).mapBy("id").join("|"));
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class Category extends Component {}

@ -24,8 +24,9 @@ function RGBToHex(rgb) {
return "#" + r + g + b;
}
export default Component.extend({
valid: computed("value", function () {
export default class Color extends Component {
@computed("value")
get valid() {
let value = this.value.toLowerCase();
let testColor = new Option().style;
@ -43,10 +44,10 @@ export default Component.extend({
}
return testColor.color && hexifiedColor === value;
}),
}
@action
onChangeColor(color) {
this.set("value", color);
},
});
}
}

@ -1,40 +1,36 @@
import { action, computed } from "@ember/object";
import Component from "@ember/component";
import { computed } from "@ember/object";
import { makeArray } from "discourse-common/lib/helpers";
export default Component.extend({
tokenSeparator: "|",
export default class CompactList extends Component {
tokenSeparator = "|";
createdChoices = null;
createdChoices: null,
settingValue: computed("value", function () {
@computed("value")
get settingValue() {
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
}),
}
settingChoices: computed(
"settingValue",
"setting.choices.[]",
"createdChoices.[]",
function () {
return [
...new Set([
...makeArray(this.settingValue),
...makeArray(this.setting.choices),
...makeArray(this.createdChoices),
]),
];
}
),
@computed("settingValue", "setting.choices.[]", "createdChoices.[]")
get settingChoices() {
return [
...new Set([
...makeArray(this.settingValue),
...makeArray(this.setting.choices),
...makeArray(this.createdChoices),
]),
];
}
actions: {
onChangeListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
},
@action
onChangeListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
}
onChangeChoices(choices) {
this.set("createdChoices", [
...new Set([...makeArray(this.createdChoices), ...makeArray(choices)]),
]);
},
},
});
@action
onChangeChoices(choices) {
this.set("createdChoices", [
...new Set([...makeArray(this.createdChoices), ...makeArray(choices)]),
]);
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class EmojiList extends Component {}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class Enum extends Component {}

@ -1,25 +1,25 @@
import { action, computed } from "@ember/object";
import Component from "@ember/component";
import { computed } from "@ember/object";
export default Component.extend({
tokenSeparator: "|",
export default class GroupList extends Component {
tokenSeparator = "|";
nameProperty = "name";
valueProperty = "id";
nameProperty: "name",
valueProperty: "id",
groupChoices: computed("site.groups", function () {
@computed("site.groups")
get groupChoices() {
return (this.site.groups || []).map((g) => {
return { name: g.name, id: g.id.toString() };
});
}),
}
settingValue: computed("value", function () {
@computed("value")
get settingValue() {
return (this.value || "").split(this.tokenSeparator).filter(Boolean);
}),
}
actions: {
onChangeGroupListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
},
},
});
@action
onChangeGroupListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
}
}

@ -1,14 +1,14 @@
import Component from "@ember/component";
import { action, computed } from "@ember/object";
export default Component.extend({
tokenSeparator: "|",
choices: null,
export default class HostList extends Component {
tokenSeparator = "|";
choices = null;
@computed("value")
get settingValue() {
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
},
}
@action
onChange(value) {
@ -17,5 +17,5 @@ export default Component.extend({
}
this.set("value", value.join(this.tokenSeparator));
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class List extends Component {}

@ -1,13 +1,13 @@
import Component from "@ember/component";
import { action, computed } from "@ember/object";
export default Component.extend({
tokenSeparator: "|",
export default class NamedList extends Component {
tokenSeparator = "|";
@computed("value")
get settingValue() {
return this.value.toString().split(this.tokenSeparator).filter(Boolean);
},
}
@computed("setting.choices.[]", "settingValue")
get settingChoices() {
@ -24,10 +24,10 @@ export default Component.extend({
}
return choices;
},
}
@action
onChangeListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class SecretList extends Component {}

@ -1,11 +1,11 @@
import Component from "@ember/component";
import { action } from "@ember/object";
export default Component.extend({
inputDelimiter: "|",
export default class SimpleList extends Component {
inputDelimiter = "|";
@action
onChange(value) {
this.set("value", value.join(this.inputDelimiter || "\n"));
},
});
}
}

@ -2,7 +2,7 @@ import { action } from "@ember/object";
import Component from "@ember/component";
import showModal from "discourse/lib/show-modal";
export default Component.extend({
export default class String extends Component {
@action
launchJsonEditorModal() {
const schemaModal = showModal("json-schema-editor", {
@ -16,5 +16,5 @@ export default Component.extend({
schemaModal.set("onClose", () => {
this.set("value", schemaModal.model.value);
});
},
});
}
}

@ -2,16 +2,14 @@ import Component from "@ember/component";
import { action } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
export default Component.extend({
export default class TagList extends Component {
@discourseComputed("value")
selectedTags: {
get(value) {
return value.split("|").filter(Boolean);
},
},
selectedTags(value) {
return value.split("|").filter(Boolean);
}
@action
changeSelectedTags(tags) {
this.set("value", tags.join("|"));
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class Upload extends Component {}

@ -1,16 +1,16 @@
import { action } from "@ember/object";
import Component from "@ember/component";
import showModal from "discourse/lib/show-modal";
export default Component.extend({
actions: {
showUploadModal({ value, setting }) {
showModal("admin-uploaded-image-list", {
admin: true,
title: `admin.site_settings.${setting.setting}.title`,
model: { value, setting },
}).setProperties({
save: (v) => this.set("value", v),
});
},
},
});
export default class UploadedImageList extends Component {
@action
showUploadModal({ value, setting }) {
showModal("admin-uploaded-image-list", {
admin: true,
title: `admin.site_settings.${setting.setting}.title`,
model: { value, setting },
}).setProperties({
save: (v) => this.set("value", v),
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class UrlList extends Component {}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class ValueList extends Component {}

@ -1,11 +1,11 @@
import { classNameBindings, classNames } from "@ember-decorators/component";
import Component from "@ember/component";
import highlightHTML from "discourse/lib/highlight-html";
import { on } from "discourse-common/utils/decorators";
export default Component.extend({
classNames: ["site-text"],
classNameBindings: ["siteText.overridden"],
@classNames("site-text")
@classNameBindings("siteText.overridden")
export default class SiteTextSummary extends Component {
@on("didInsertElement")
highlightTerm() {
const term = this._searchTerm();
@ -19,11 +19,11 @@ export default Component.extend({
}
);
}
},
}
click() {
this.editAction(this.siteText);
},
}
_searchTerm() {
const regex = this.searchRegex;
@ -37,5 +37,5 @@ export default Component.extend({
}
return this.term;
},
});
}
}

@ -1,10 +1,10 @@
import { tagName } from "@ember-decorators/component";
import { action } from "@ember/object";
import Component from "@ember/component";
import DiscourseURL from "discourse/lib/url";
export default Component.extend({
tagName: "",
@tagName("")
export default class StaffActions extends Component {
@action
openLinks(event) {
const dataset = event.target.dataset;
@ -20,5 +20,5 @@ export default Component.extend({
DiscourseURL.routeTo(`/t/${dataset.linkTopicId}`);
}
},
});
}
}

@ -1,24 +1,27 @@
import { inject as service } from "@ember/service";
import { alias } from "@ember/object/computed";
import Component from "@ember/component";
import I18n from "I18n";
import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { alias } from "@ember/object/computed";
import { inject as service } from "@ember/service";
export default Component.extend(UppyUploadMixin, {
type: "csv",
dialog: service(),
uploadUrl: "/tags/upload",
addDisabled: alias("uploading"),
elementId: "tag-uploader",
preventDirectS3Uploads: true,
export default class TagsUploader extends Component.extend(UppyUploadMixin) {
@service dialog;
type = "csv";
uploadUrl = "/tags/upload";
@alias("uploading") addDisabled;
elementId = "tag-uploader";
preventDirectS3Uploads = true;
validateUploadedFilesOptions() {
return { csvOnly: true };
},
}
uploadDone() {
this.closeModal();
this.refresh();
this.dialog.alert(I18n.t("tagging.upload_successful"));
},
});
}
}

@ -3,9 +3,10 @@ import { alias } from "@ember/object/computed";
export default class ThemeTranslation extends SiteSettingComponent {
@alias("translation") setting;
type = "string";
@alias("translation.key") settingName;
type = "string";
_save() {
return this.model.saveTranslation(
this.get("translation.key"),

@ -1,3 +1,4 @@
import { classNameBindings, classNames } from "@ember-decorators/component";
import { and, gt } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component";
@ -7,19 +8,22 @@ import { action } from "@ember/object";
const MAX_COMPONENTS = 4;
export default Component.extend({
childrenExpanded: false,
classNames: ["themes-list-item"],
classNameBindings: ["theme.selected:selected"],
hasComponents: gt("children.length", 0),
displayComponents: and("hasComponents", "theme.isActive"),
displayHasMore: gt("theme.childThemes.length", MAX_COMPONENTS),
@classNames("themes-list-item")
@classNameBindings("theme.selected:selected")
export default class ThemesListItem extends Component {
childrenExpanded = false;
@gt("children.length", 0) hasComponents;
@and("hasComponents", "theme.isActive") displayComponents;
@gt("theme.childThemes.length", MAX_COMPONENTS) displayHasMore;
click(e) {
if (!e.target.classList.contains("others-count")) {
this.navigateToTheme();
}
},
}
@discourseComputed(
"theme.component",
@ -40,12 +44,12 @@ export default Component.extend({
const name = escape(t.name);
return t.enabled ? name : `${iconHTML("ban")} ${name}`;
});
},
}
@discourseComputed("children")
childrenString(children) {
return children.join(", ");
},
}
@discourseComputed(
"theme.childThemes.length",
@ -58,11 +62,11 @@ export default Component.extend({
return 0;
}
return childrenCount - MAX_COMPONENTS;
},
}
@action
toggleChildrenExpanded(event) {
event?.preventDefault();
this.toggleProperty("childrenExpanded");
},
});
}
}

@ -1,25 +1,30 @@
import { COMPONENTS, THEMES } from "admin/models/theme";
import { classNames } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import { equal, gt, gte } from "@ember/object/computed";
import { COMPONENTS, THEMES } from "admin/models/theme";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
export default Component.extend({
router: service(),
THEMES,
COMPONENTS,
@classNames("themes-list")
export default class ThemesList extends Component {
@service router;
classNames: ["themes-list"],
filterTerm: null,
THEMES = THEMES;
COMPONENTS = COMPONENTS;
filterTerm = null;
hasThemes: gt("themesList.length", 0),
hasActiveThemes: gt("activeThemes.length", 0),
hasInactiveThemes: gt("inactiveThemes.length", 0),
showFilter: gte("themesList.length", 10),
@gt("themesList.length", 0) hasThemes;
themesTabActive: equal("currentTab", THEMES),
componentsTabActive: equal("currentTab", COMPONENTS),
@gt("activeThemes.length", 0) hasActiveThemes;
@gt("inactiveThemes.length", 0) hasInactiveThemes;
@gte("themesList.length", 10) showFilter;
@equal("currentTab", THEMES) themesTabActive;
@equal("currentTab", COMPONENTS) componentsTabActive;
@discourseComputed("themes", "components", "currentTab")
themesList(themes, components) {
@ -28,7 +33,7 @@ export default Component.extend({
} else {
return components;
}
},
}
@discourseComputed(
"themesList",
@ -49,7 +54,7 @@ export default Component.extend({
);
}
return this._filterThemes(results, this.filterTerm);
},
}
@discourseComputed(
"themesList",
@ -78,7 +83,7 @@ export default Component.extend({
});
}
return this._filterThemes(results, this.filterTerm);
},
}
_filterThemes(themes, term) {
term = term?.trim()?.toLowerCase();
@ -86,7 +91,7 @@ export default Component.extend({
return themes;
}
return themes.filter(({ name }) => name.toLowerCase().includes(term));
},
}
@action
changeView(newTab) {
@ -96,10 +101,10 @@ export default Component.extend({
this.set("filterTerm", null);
}
}
},
}
@action
navigateToTheme(theme) {
this.router.transitionTo("adminCustomizeThemes.show", theme);
},
});
}
}

@ -1,17 +1,21 @@
import discourseComputed, { on } from "discourse-common/utils/decorators";
import { action } from "@ember/object";
import { classNames } from "@ember-decorators/component";
import { empty, reads } from "@ember/object/computed";
import discourseComputed, { on } from "discourse-common/utils/decorators";
import Component from "@ember/component";
import { makeArray } from "discourse-common/lib/helpers";
export default Component.extend({
classNameBindings: [":value-list"],
inputInvalid: empty("newValue"),
inputDelimiter: null,
inputType: null,
newValue: "",
collection: null,
values: null,
noneKey: reads("addKey"),
@classNames("value-list")
export default class ValueList extends Component {
@empty("newValue") inputInvalid;
inputDelimiter = null;
inputType = null;
newValue = "";
collection = null;
values = null;
@reads("addKey") noneKey;
@on("didReceiveAttrs")
_setupCollection() {
@ -25,57 +29,60 @@ export default Component.extend({
"collection",
this._splitValues(values, this.inputDelimiter || "\n")
);
},
}
@discourseComputed("choices.[]", "collection.[]")
filteredChoices(choices, collection) {
return makeArray(choices).filter((i) => !collection.includes(i));
},
}
keyDown(event) {
if (event.key === "Enter") {
this.send("addValue", this.newValue);
}
},
}
actions: {
changeValue(index, event) {
this._replaceValue(index, event.target.value);
},
@action
changeValue(index, event) {
this._replaceValue(index, event.target.value);
}
addValue(newValue) {
if (this.inputInvalid) {
return;
}
@action
addValue(newValue) {
if (this.inputInvalid) {
return;
}
this.set("newValue", null);
this._addValue(newValue);
},
this.set("newValue", null);
this._addValue(newValue);
}
removeValue(value) {
this._removeValue(value);
},
@action
removeValue(value) {
this._removeValue(value);
}
selectChoice(choice) {
this._addValue(choice);
},
@action
selectChoice(choice) {
this._addValue(choice);
}
shift(operation, index) {
let futureIndex = index + operation;
@action
shift(operation, index) {
let futureIndex = index + operation;
if (futureIndex > this.collection.length - 1) {
futureIndex = 0;
} else if (futureIndex < 0) {
futureIndex = this.collection.length - 1;
}
if (futureIndex > this.collection.length - 1) {
futureIndex = 0;
} else if (futureIndex < 0) {
futureIndex = this.collection.length - 1;
}
const shiftedValue = this.collection[index];
this.collection.removeAt(index);
this.collection.insertAt(futureIndex, shiftedValue);
const shiftedValue = this.collection[index];
this.collection.removeAt(index);
this.collection.insertAt(futureIndex, shiftedValue);
this._saveValues();
},
},
this._saveValues();
}
_addValue(value) {
this.collection.addObject(value);
@ -87,7 +94,7 @@ export default Component.extend({
}
this._saveValues();
},
}
_removeValue(value) {
this.collection.removeObject(value);
@ -99,12 +106,12 @@ export default Component.extend({
}
this._saveValues();
},
}
_replaceValue(index, newValue) {
this.collection.replace(index, 1, [newValue]);
this._saveValues();
},
}
_saveValues() {
if (this.inputType === "array") {
@ -113,12 +120,12 @@ export default Component.extend({
}
this.set("values", this.collection.join(this.inputDelimiter || "\n"));
},
}
@discourseComputed("collection")
showUpDownButtons(collection) {
return collection.length - 1 ? true : false;
},
}
_splitValues(values, delimiter) {
if (values && values.length) {
@ -126,5 +133,5 @@ export default Component.extend({
} else {
return [];
}
},
});
}
}

@ -1,3 +1,3 @@
import Component from "@ember/component";
export default Component.extend({});
export default class VersionChecks extends Component {}

@ -79,7 +79,7 @@
<DButton
@type="submit"
@class="btn btn-primary"
@action={{action "submit"}}
@action={{action "submitForm"}}
@disabled={{this.submitDisabled}}
@label="admin.watched_words.form.add"
/>

@ -1,30 +1,37 @@
import { action } from "@ember/object";
import { classNames, tagName } from "@ember-decorators/component";
import { inject as service } from "@ember/service";
import { equal, not } from "@ember/object/computed";
import discourseComputed, { observes } from "discourse-common/utils/decorators";
import Component from "@ember/component";
import I18n from "I18n";
import WatchedWord from "admin/models/watched-word";
import { equal, not } from "@ember/object/computed";
import { isEmpty } from "@ember/utils";
import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
export default Component.extend({
tagName: "form",
dialog: service(),
classNames: ["watched-word-form"],
formSubmitted: false,
actionKey: null,
showMessage: false,
selectedTags: null,
isCaseSensitive: false,
submitDisabled: not("word"),
canReplace: equal("actionKey", "replace"),
canTag: equal("actionKey", "tag"),
canLink: equal("actionKey", "link"),
@tagName("form")
@classNames("watched-word-form")
export default class WatchedWordForm extends Component {
@service dialog;
formSubmitted = false;
actionKey = null;
showMessage = false;
selectedTags = null;
isCaseSensitive = false;
@not("word") submitDisabled;
@equal("actionKey", "replace") canReplace;
@equal("actionKey", "tag") canTag;
@equal("actionKey", "link") canLink;
didInsertElement() {
this._super(...arguments);
super.didInsertElement(...arguments);
this.set("selectedTags", []);
},
}
@discourseComputed("siteSettings.watched_words_regular_expressions")
placeholderKey(watchedWordsRegularExpressions) {
@ -33,14 +40,14 @@ export default Component.extend({
} else {
return "admin.watched_words.form.placeholder";
}
},
}
@observes("word")
removeMessage() {
if (this.showMessage && !isEmpty(this.word)) {
this.set("showMessage", false);
}
},
}
@discourseComputed("word")
isUniqueWord(word) {
@ -54,71 +61,71 @@ export default Component.extend({
}
return content.word.toLowerCase() !== word.toLowerCase();
});
},
}
focusInput() {
schedule("afterRender", () => this.element.querySelector("input").focus());
},
}
actions: {
changeSelectedTags(tags) {
@action
changeSelectedTags(tags) {
this.setProperties({
selectedTags: tags,
replacement: tags.join(","),
});
}
@action
submitForm() {
if (!this.isUniqueWord) {
this.setProperties({
selectedTags: tags,
replacement: tags.join(","),
showMessage: true,
message: I18n.t("admin.watched_words.form.exists"),
});
},
return;
}
submit() {
if (!this.isUniqueWord) {
this.setProperties({
showMessage: true,
message: I18n.t("admin.watched_words.form.exists"),
});
return;
}
if (!this.formSubmitted) {
this.set("formSubmitted", true);
if (!this.formSubmitted) {
this.set("formSubmitted", true);
const watchedWord = WatchedWord.create({
word: this.word,
replacement:
this.canReplace || this.canTag || this.canLink
? this.replacement
: null,
action: this.actionKey,
isCaseSensitive: this.isCaseSensitive,
});
const watchedWord = WatchedWord.create({
word: this.word,
replacement:
this.canReplace || this.canTag || this.canLink
? this.replacement
: null,
action: this.actionKey,
isCaseSensitive: this.isCaseSensitive,
});
watchedWord
.save()
.then((result) => {
this.setProperties({
word: "",
replacement: "",
formSubmitted: false,
selectedTags: [],
showMessage: true,
message: I18n.t("admin.watched_words.form.success"),
isCaseSensitive: false,
});
this.action(WatchedWord.create(result));
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
watchedWord
.save()
.then((result) => {
this.setProperties({
word: "",
replacement: "",
formSubmitted: false,
selectedTags: [],
showMessage: true,
message: I18n.t("admin.watched_words.form.success"),
isCaseSensitive: false,
});
}
},
},
});
this.action(WatchedWord.create(result));
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
});
}
}
}

@ -1,28 +1,33 @@
import { classNames } from "@ember-decorators/component";
import { alias } from "@ember/object/computed";
import Component from "@ember/component";
import I18n from "I18n";
import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { alias } from "@ember/object/computed";
import { dialog } from "discourse/lib/uploads";
export default Component.extend(UppyUploadMixin, {
type: "txt",
classNames: "watched-words-uploader",
uploadUrl: "/admin/customize/watched_words/upload",
addDisabled: alias("uploading"),
preventDirectS3Uploads: true,
@classNames("watched-words-uploader")
export default class WatchedWordUploader extends Component.extend(
UppyUploadMixin
) {
type = "txt";
uploadUrl = "/admin/customize/watched_words/upload";
@alias("uploading") addDisabled;
preventDirectS3Uploads = true;
validateUploadedFilesOptions() {
return { skipValidation: true };
},
}
_perFileData() {
return { action_key: this.actionKey };
},
}
uploadDone() {
if (this) {
dialog.alert(I18n.t("admin.watched_words.form.upload_successful"));
this.done();
}
},
});
}
}