Merge branch 'main' into chat-side-panel-initial-skeleton-threads

This commit is contained in:
Martin Brennan 2023-02-10 08:23:47 +10:00
commit c19394c184
No known key found for this signature in database
GPG Key ID: A08063EEF3EA26A4
37 changed files with 473 additions and 83 deletions

View File

@ -476,10 +476,10 @@ GEM
sprockets (>= 3.0.0)
sshkey (2.0.0)
stackprof (0.2.23)
syntax_tree (5.2.0)
syntax_tree (5.3.0)
prettier_print (>= 1.2.0)
syntax_tree-disable_ternary (1.0.0)
test-prof (1.1.0)
test-prof (1.2.0)
thor (1.2.1)
tilt (2.0.11)
timeout (0.3.1)

View File

@ -1,7 +1,6 @@
import Controller, { inject as controller } from "@ember/controller";
import { observes } from "discourse-common/utils/decorators";
import I18n from "I18n";
import { bufferedProperty } from "discourse/mixins/buffered-content";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { next } from "@ember/runloop";
@ -25,6 +24,14 @@ export default class AdminBadgesShowController extends Controller.extend(
@tracked savingStatus = "";
@tracked selectedGraphicType = null;
get badgeEnabledLabel() {
if (this.buffered.get("enabled")) {
return "admin.badges.enabled";
} else {
return "admin.badges.disabled";
}
}
get badgeTypes() {
return this.adminBadges.badgeTypes;
}
@ -238,4 +245,11 @@ export default class AdminBadgesShowController extends Controller.extend(
},
});
}
@action
toggleBadge() {
this.model
.save({ enabled: !this.buffered.get("enabled") })
.catch(popupAjaxError);
}
}

View File

@ -1,4 +1,12 @@
<DSection @class="current-badge content-body">
<div class="control-group current-badge__toggle-badge">
<DToggleSwitch
@state={{this.buffered.enabled}}
@label={{this.badgeEnabledLabel}}
{{on "click" this.toggleBadge}}
/>
</div>
<form class="form-horizontal">
<div class="control-group">
<label for="name">{{i18n "admin.badges.name"}}</label>
@ -253,13 +261,6 @@
{{i18n "admin.badges.show_posts"}}
</label>
</div>
<div>
<label>
<Input @type="checkbox" @checked={{this.buffered.enabled}} />
{{i18n "admin.badges.enabled"}}
</label>
</div>
</div>
<div class="buttons">

View File

@ -1,9 +1,6 @@
"use strict";
const WidgetHbsCompiler =
require("../../../../lib/javascripts/widget-hbs-compiler").WidgetHbsCompiler;
const glimmer = require("@glimmer/syntax");
const widgetHbsCompilerPath = require.resolve("./lib/widget-hbs-compiler");
module.exports = {
name: require("./package").name,
@ -15,9 +12,12 @@ module.exports = {
addonOptions.babel.plugins = addonOptions.babel.plugins || [];
let babelPlugins = addonOptions.babel.plugins;
WidgetHbsCompiler.cacheKey = () => "discourse-widget-hbs";
WidgetHbsCompiler.glimmer = glimmer;
babelPlugins.push(WidgetHbsCompiler);
babelPlugins.push({
_parallelBabel: {
requireFile: widgetHbsCompilerPath,
useMethod: "WidgetHbsCompiler",
},
});
},
_getAddonOptions() {

View File

@ -373,4 +373,6 @@ const WidgetHbsCompiler = function (babel) {
};
};
WidgetHbsCompiler.cacheKey = () => "discourse-widget-hbs";
exports.WidgetHbsCompiler = WidgetHbsCompiler;

View File

@ -276,6 +276,11 @@ export default Component.extend(TextareaTextManipulation, {
this._itsatrap.bind("tab", () => this.indentSelection("right"));
this._itsatrap.bind("shift+tab", () => this.indentSelection("left"));
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
const mod = mac ? "meta" : "ctrl";
this._itsatrap.bind(`${mod}+shift+.`, () => this.send("insertCurrentTime"));
// disable clicking on links in the preview
this.element
.querySelector(".d-editor-preview")
@ -763,6 +768,15 @@ export default Component.extend(TextareaTextManipulation, {
}
},
insertCurrentTime() {
const sel = this.getSelected("", { lineVal: true });
const timezone = this.currentUser.user_option.timezone;
const time = moment().format("HH:mm:ss");
const date = moment().format("YYYY-MM-DD");
this.addText(sel, `[date=${date} time=${time} timezone="${timezone}"]`);
},
focusIn() {
this.set("isEditorFocused", true);
},

View File

@ -0,0 +1,20 @@
<div class="d-toggle-switch">
<label class="d-toggle-switch--label">
{{! template-lint-disable no-unnecessary-concat }}
<button
class="d-toggle-switch__checkbox"
type="button"
role="switch"
aria-checked="{{@state}}"
...attributes
></button>
<span class="d-toggle-switch__checkbox-slider">
{{#if @state}}
{{d-icon "check"}}
{{/if}}
</span>
</label>
<span class="d-toggle-switch__checkbox-label">
{{this.computedLabel}}
</span>
</div>

View File

@ -0,0 +1,15 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import I18n from "I18n";
export default class DiscourseToggleSwitch extends Component {
@tracked iconEnabled = true;
@tracked showIcon = this.iconEnabled && this.icon;
get computedLabel() {
if (this.args.label) {
return I18n.t(this.args.label);
}
return this.args.translatedLabel;
}
}

View File

@ -13,7 +13,7 @@ export default class UserStatusMessage extends Component {
}
const timezone = this.currentUser
? this.currentUser.timezone
? this.currentUser.user_option?.timezone
: moment.tz.guess();
return until(this.status.ends_at, timezone, this.currentUser?.locale);

View File

@ -194,6 +194,10 @@ export default Controller.extend(ModalFunctionality, {
keys1: [SHIFT, "F11"],
keysDelimiter: PLUS,
}),
insertCurrentTime: buildShortcut("composing.insert_current_time", {
keys1: [META, SHIFT, "."],
keysDelimiter: PLUS,
}),
},
},
bookmarks: {

View File

@ -434,8 +434,6 @@ export default Controller.extend({
},
resetSeenUserTips() {
this.model.set("skip_new_user_tips", false);
this.model.set("seen_popups", null);
this.model.set("user_option.skip_new_user_tips", false);
this.model.set("user_option.seen_popups", null);
return this.model.save(["skip_new_user_tips", "seen_popups"]);

View File

@ -1179,7 +1179,7 @@ const User = RestModel.extend({
showUserTip(options) {
const userTips = Site.currentProp("user_tips");
if (!userTips || this.skip_new_user_tips) {
if (!userTips || this.user_option?.skip_new_user_tips) {
return;
}
@ -1191,7 +1191,7 @@ const User = RestModel.extend({
return;
}
const seenUserTips = this.seen_popups || [];
const seenUserTips = this.user_option?.seen_popups || [];
if (
seenUserTips.includes(-1) ||
seenUserTips.includes(userTips[options.id])
@ -1208,7 +1208,7 @@ const User = RestModel.extend({
hideUserTipForever(userTipId) {
const userTips = Site.currentProp("user_tips");
if (!userTips || this.skip_new_user_tips) {
if (!userTips || this.user_option?.skip_new_user_tips) {
return;
}
@ -1228,7 +1228,7 @@ const User = RestModel.extend({
}
// Update list of seen user tips.
let seenUserTips = this.seen_popups || [];
let seenUserTips = this.user_option?.seen_popups || [];
if (userTipId) {
if (seenUserTips.includes(userTips[userTipId])) {
return;

View File

@ -10,36 +10,16 @@ const { parsePluginClientSettings } = require("./lib/site-settings-plugin");
const discourseScss = require("./lib/discourse-scss");
const generateScriptsTree = require("./lib/scripts");
const funnel = require("broccoli-funnel");
const SILENCED_WARN_PREFIXES = [
"Setting the `jquery-integration` optional feature flag",
"The Ember Classic edition has been deprecated",
"Setting the `template-only-glimmer-components` optional feature flag to `false`",
"DEPRECATION: Invoking the `<LinkTo>` component with positional arguments is deprecated",
];
const DeprecationSilencer = require("./lib/deprecation-silencer");
module.exports = function (defaults) {
let discourseRoot = resolve("../../../..");
let vendorJs = discourseRoot + "/vendor/assets/javascripts/";
// Silence the warnings listed in SILENCED_WARN_PREFIXES
// Silence deprecations which we are aware of - see `lib/deprecation-silencer.js`
const ui = defaults.project.ui;
const oldWriteWarning = ui.writeWarnLine.bind(ui);
ui.writeWarnLine = (message, ...args) => {
if (!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))) {
return oldWriteWarning(message, ...args);
}
};
// Silence warnings which go straight to console.warn (e.g. template compiler deprecations)
/* eslint-disable no-console */
const oldConsoleWarn = console.warn.bind(console);
console.warn = (message, ...args) => {
if (!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))) {
return oldConsoleWarn(message, ...args);
}
};
/* eslint-enable no-console */
DeprecationSilencer.silenceUiWarn(ui);
DeprecationSilencer.silenceConsoleWarn();
const isProduction = EmberApp.env().includes("production");
const isTest = EmberApp.env().includes("test");
@ -56,6 +36,9 @@ module.exports = function (defaults) {
enabled: true,
},
autoImport: {
alias: {
"virtual-dom": "@discourse/virtual-dom",
},
forbidEval: true,
insertScriptsAt: "ember-auto-import-scripts",
webpack: {
@ -108,6 +91,14 @@ module.exports = function (defaults) {
],
},
"ember-cli-babel": {
throwUnlessParallelizable: true,
},
babel: {
plugins: [DeprecationSilencer.generateBabelPlugin()],
},
// We need to build tests in prod for theme tests
tests: true,

View File

@ -0,0 +1,56 @@
const SILENCED_WARN_PREFIXES = [
"Setting the `jquery-integration` optional feature flag",
"The Ember Classic edition has been deprecated",
"Setting the `template-only-glimmer-components` optional feature flag to `false`",
"DEPRECATION: Invoking the `<LinkTo>` component with positional arguments is deprecated",
];
let consoleWarnSilenced = false;
module.exports = class DeprecationSilencer {
static silenceUiWarn(ui) {
const oldWriteWarning = ui.writeWarnLine.bind(ui);
ui.writeWarnLine = (message, ...args) => {
if (
!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))
) {
return oldWriteWarning(message, ...args);
}
};
}
static silenceConsoleWarn() {
if (consoleWarnSilenced) {
return;
}
/* eslint-disable no-console */
const oldConsoleWarn = console.warn.bind(console);
console.warn = (message, ...args) => {
if (
!SILENCED_WARN_PREFIXES.some((prefix) => message.startsWith(prefix))
) {
return oldConsoleWarn(message, ...args);
}
};
/* eslint-enable no-console */
consoleWarnSilenced = true;
}
/**
* Generates a dummy babel plugin which applies the console.warn silences in worker
* processes. Does not actually affect babel output.
*/
static generateBabelPlugin() {
return {
_parallelBabel: {
requireFile: require.resolve("./deprecation-silencer"),
buildUsing: "babelShim",
},
};
}
static babelShim() {
DeprecationSilencer.silenceConsoleWarn();
return {};
}
};

View File

@ -17,7 +17,7 @@
},
"dependencies": {
"@babel/core": "^7.20.12",
"@babel/standalone": "^7.20.14",
"@babel/standalone": "^7.20.15",
"@discourse/backburner.js": "^2.7.1-0",
"@discourse/itsatrap": "^2.0.10",
"@ember-compat/tracked-built-ins": "^0.9.1",
@ -94,7 +94,7 @@
"terser": "^5.16.3",
"tippy.js": "^6.3.7",
"util": "^0.12.5",
"virtual-dom": "^2.1.1",
"@discourse/virtual-dom": "^2.1.2-0",
"webpack": "^5.75.0",
"wizard": "1.0.0",
"xss": "^1.0.14"

View File

@ -1360,3 +1360,32 @@ acceptance("Composer - default category not set", function (needs) {
});
});
// END: Default Composer Category tests
acceptance("Composer - current time", function (needs) {
needs.user();
test("composer insert current time shortcut", async function (assert) {
await visit("/t/internationalization-localization/280");
await click("#topic-footer-buttons .btn.create");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
await fillIn(".d-editor-input", "and the time now is: ");
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
await triggerKeyEvent(".d-editor-input", "keydown", ".", {
shiftKey: true,
ctrlKey: !mac,
metaKey: mac,
});
const time = moment().format("HH:mm:ss");
const date = moment().format("YYYY-MM-DD");
assert.strictEqual(
query("#reply-control .d-editor-input").value.trim(),
`and the time now is: [date=${date} time=${time} timezone="Australia/Brisbane"]`,
"it adds the current date"
);
});
});

View File

@ -23,7 +23,7 @@ acceptance("Topic - Bulk Actions - Mobile", function (needs) {
});
test("bulk select - modal", async function (assert) {
updateCurrentUser({ moderator: true, enable_defer: true });
updateCurrentUser({ moderator: true, user_option: { enable_defer: true } });
await visit("/latest");
await click("button.bulk-select");

View File

@ -14,7 +14,7 @@ acceptance("User Card - Show Local Time", function (needs) {
needs.settings({ display_local_time_in_user_card: true });
test("user card local time - does not update timezone for another user", async function (assert) {
User.current().timezone = "Australia/Brisbane";
User.current().user_option.timezone = "Australia/Brisbane";
await visit("/t/internationalization-localization/280");
await click('a[data-user-card="charlie"]');

View File

@ -482,7 +482,7 @@ acceptance("User Status - new user menu", function (needs) {
needs.user({
id: userId,
timezone: userTimezone,
"user_option.timezone": userTimezone,
redesigned_user_menu_enabled: true,
});

View File

@ -3118,8 +3118,8 @@ export default {
text_size: "normal",
text_size_seq: 0,
title_count_mode: "notifications",
timezone: "Asia/Tokyo",
},
timezone: "Asia/Tokyo",
},
},
"/u/%E3%83%A9%E3%82%A4%E3%82%AA%E3%83%B3/summary.json": {

View File

@ -0,0 +1,66 @@
import { module, test } from "qunit";
import { render } from "@ember/test-helpers";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { hbs } from "ember-cli-htmlbars";
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
import I18n from "I18n";
module("Integration | Component | d-toggle-switch", function (hooks) {
setupRenderingTest(hooks);
test("it renders a toggle button in a disabled state", async function (assert) {
this.set("state", false);
await render(hbs`<DToggleSwitch @state={{this.state}}/>`);
assert.ok(exists(".d-toggle-switch"), "it renders a toggle switch");
assert.strictEqual(
query(".d-toggle-switch__checkbox").getAttribute("aria-checked"),
"false"
);
});
test("it renders a toggle button in a enabled state", async function (assert) {
this.set("state", true);
await render(hbs`<DToggleSwitch @state={{this.state}}/>`);
assert.ok(exists(".d-toggle-switch"), "it renders a toggle switch");
assert.strictEqual(
query(".d-toggle-switch__checkbox").getAttribute("aria-checked"),
"true"
);
});
test("it renders a checkmark icon when enabled", async function (assert) {
this.set("state", true);
await render(hbs`<DToggleSwitch @state={{this.state}}/>`);
assert.ok(exists(".d-toggle-switch__checkbox-slider .d-icon-check"));
});
test("it renders a label for the button", async function (assert) {
I18n.translations[I18n.locale].js.test = { fooLabel: "foo" };
this.set("state", true);
await render(
hbs`<DToggleSwitch @state={{this.state}}/ @label={{this.label}} @translatedLabel={{this.translatedLabel}} />`
);
this.set("label", "test.fooLabel");
assert.strictEqual(
query(".d-toggle-switch__checkbox-label").innerText,
I18n.t("test.fooLabel")
);
this.setProperties({
label: null,
translatedLabel: "bar",
});
assert.strictEqual(
query(".d-toggle-switch__checkbox-label").innerText,
"bar"
);
});
});

View File

@ -85,7 +85,7 @@ module(
});
test("notification reason text - user mailing list mode", async function (assert) {
this.currentUser.set("mailing_list_mode", true);
this.currentUser.set("user_option.mailing_list_mode", true);
this.set("topic", buildTopic.call(this, { level: 2 }));
await render(hbs`

View File

@ -9,6 +9,7 @@ import { Promise } from "rsvp";
import { createWidget } from "discourse/widgets/widget";
import { next } from "@ember/runloop";
import { withPluginApi } from "discourse/lib/plugin-api";
import { h } from "virtual-dom";
module("Integration | Component | Widget | base", function (hooks) {
setupRenderingTest(hooks);
@ -394,4 +395,75 @@ module("Integration | Component | Widget | base", function (hooks) {
"renders container with overridden tagName"
);
});
test("avoids rerendering on prepend", async function (assert) {
createWidget("prepend-test", {
tagName: "div.test",
html(attrs) {
const result = [];
result.push(
this.attach("button", {
label: "rerender",
className: "rerender",
action: "dummyAction",
})
);
result.push(
h(
"div",
attrs.array.map((val) => h(`span.val.${val}`, { key: val }, val))
)
);
return result;
},
dummyAction() {},
});
const array = ["ElementOne", "ElementTwo"];
this.set("args", { array });
await render(
hbs`<MountWidget @widget="prepend-test" @args={{this.args}} />`
);
const startElements = Array.from(document.querySelectorAll("span.val"));
assert.deepEqual(
startElements.map((e) => e.innerText),
["ElementOne", "ElementTwo"]
);
const elementOneBefore = startElements[0];
const parent = elementOneBefore.parentNode;
const observer = new MutationObserver(function (mutations) {
assert.notOk(
mutations.some((m) =>
Array.from(m.addedNodes).includes(elementOneBefore)
)
);
});
observer.observe(parent, { childList: true });
array.unshift(
"PrependedElementOne",
"PrependedElementTwo",
"PrependedElementThree"
);
await click(".rerender");
const endElements = Array.from(document.querySelectorAll("span.val"));
assert.deepEqual(
endElements.map((e) => e.innerText),
[
"PrependedElementOne",
"PrependedElementTwo",
"PrependedElementThree",
"ElementOne",
"ElementTwo",
]
);
const elementOneAfter = endElements[3];
assert.strictEqual(elementOneBefore, elementOneAfter);
});
});

View File

@ -956,10 +956,10 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/standalone@^7.20.14":
version "7.20.14"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.20.14.tgz#26b02632680ca58da9612630b1035d11e62437a1"
integrity sha512-zxdQD6+eMQumJFPOLpOZE34JAAGrZPMXCKvHR7Mtat/l+nHDOxlit5u85HDk5WkBXmvN5PhUMeimiC95KXD9+A==
"@babel/standalone@^7.20.15":
version "7.20.15"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.20.15.tgz#ef82f1a9789d21d8b23f74d9fa8acecbe6ced02c"
integrity sha512-B3LmZ1NHlTb2eFEaw8rftZc730Wh9MlmsH8ubb6IjsNoIk9+SQ2aAA0nrm/1806+PftPRAACPClmKTu8PG7Tew==
"@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7":
version "7.20.7"
@ -1013,6 +1013,20 @@
resolved "https://registry.yarnpkg.com/@discourse/itsatrap/-/itsatrap-2.0.10.tgz#c7e750eeb32b54e769e952c4ecc472213eb1385a"
integrity sha512-Jn1gdiyHMGUsmUfLFf4Q7VnTAv0l7NePbegU6pKhKHEmbzV3FosGxq30fTOYgVyTS1bxqGjlA6LvQttJpv3ROw==
"@discourse/virtual-dom@^2.1.2-0":
version "2.1.2-0"
resolved "https://registry.yarnpkg.com/@discourse/virtual-dom/-/virtual-dom-2.1.2-0.tgz#74e44261c7b0a99b3bf6db0eac37b86e978906a6"
integrity sha512-5sTfdNxyrFK9yb98YLBAChYiO2K6Go7ptErVUQciT7rgueoGyLyw6Sm0FeVkSK1GLfusYFKZG8ch2vGNzJ0wlQ==
dependencies:
browser-split "0.0.1"
error "^4.3.0"
ev-store "^7.0.0"
global "^4.3.0"
is-object "^1.0.1"
next-tick "^0.2.2"
x-is-array "0.1.0"
x-is-string "0.1.0"
"@ember-compat/tracked-built-ins@^0.9.1":
version "0.9.1"
resolved "https://registry.yarnpkg.com/@ember-compat/tracked-built-ins/-/tracked-built-ins-0.9.1.tgz#4cc97c1841425fbf812ef3c63c00ab4790fc32a0"
@ -9315,20 +9329,6 @@ vary@^1, vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
virtual-dom@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/virtual-dom/-/virtual-dom-2.1.1.tgz#80eda2d481b9ede0c049118cefcb4a05f21d1375"
integrity sha1-gO2i1IG57eDASRGM78tKBfIdE3U=
dependencies:
browser-split "0.0.1"
error "^4.3.0"
ev-store "^7.0.0"
global "^4.3.0"
is-object "^1.0.1"
next-tick "^0.2.2"
x-is-array "0.1.0"
x-is-string "0.1.0"
w3c-xmlserializer@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073"

View File

@ -7,6 +7,7 @@
@import "conditional-loading-section";
@import "convert-to-public-topic-modal";
@import "d-tooltip";
@import "d-toggle-switch";
@import "date-input";
@import "date-picker";
@import "date-time-input-range";

View File

@ -0,0 +1,82 @@
.d-toggle-switch {
--toggle-switch-width: 45px;
--toggle-switch-height: 24px;
&:focus {
.d-toggle-switch__checkbox-slider {
outline: 2px solid var(--tertiary);
}
}
&:hover {
.d-toggle-switch__checkbox-slider {
background-color: var(--primary-high);
}
.d-toggle-switch__checkbox[aria-checked="true"]
+ .d-toggle-switch__checkbox-slider {
background-color: var(--tertiary-hover);
}
}
display: flex;
align-items: center;
&__label {
position: relative;
display: inline-block;
cursor: pointer;
}
&__checkbox {
position: absolute;
visibility: hidden;
}
&__checkbox[aria-checked="true"] + .d-toggle-switch__checkbox-slider {
background-color: var(--tertiary);
}
&__checkbox[aria-checked="true"] + .d-toggle-switch__checkbox-slider::before {
left: calc(var(--toggle-switch-width) - 22px);
}
&__checkbox-slider {
display: inline-block;
cursor: pointer;
background: var(--primary-low-mid);
border-radius: 16px;
width: var(--toggle-switch-width);
height: var(--toggle-switch-height);
margin-right: 0.5em;
position: relative;
vertical-align: middle;
transition: background 0.25s;
.d-icon {
font-size: var(--font-down-1);
color: var(--secondary);
left: 7px;
top: 7px;
position: absolute;
}
}
&__checkbox-slider::before,
&__checkbox-slider::after {
content: "";
display: block;
position: absolute;
cursor: pointer;
}
&__checkbox-slider::before {
background: var(--secondary);
border-radius: 50%;
width: calc(var(--toggle-switch-width) / 2.5);
height: calc(var(--toggle-switch-width) / 2.5);
top: 3.5px;
left: 4px;
transition: left 0.25s;
}
}

View File

@ -155,8 +155,6 @@ input {
}
.controls {
display: flex;
align-items: center;
margin-left: 160px;
}
}

View File

@ -15,7 +15,7 @@ class Admin::BadgesController < Admin::AdminController
.includes(:badge_grouping)
.includes(:badge_type, :image_upload)
.references(:badge_grouping)
.order("badge_groupings.position, badge_type_id, badges.name")
.order("enabled DESC", "badge_groupings.position, badge_type_id, badges.name")
.to_a,
protected_system_fields: Badge.protected_system_fields,
triggers: Badge.trigger_hash,

View File

@ -4059,6 +4059,7 @@ en:
title: "Composing"
return: "%{shortcut} Return to composer"
fullscreen: "%{shortcut} Fullscreen composer"
insert_current_time: "%{shortcut} Insert current time"
bookmarks:
title: "Bookmarking"
enter: "%{shortcut} Save and close"
@ -6012,7 +6013,8 @@ en:
allow_title: Allow badge to be used as a title
multiple_grant: Can be granted multiple times
listable: Show badge on the public badges page
enabled: Enable badge
enabled: enabled
disabled: disabled
icon: Icon
image: Image
graphic: Graphic

View File

@ -172,7 +172,10 @@ class DiscourseJsProcessor
)
# Widget HBS compiler
widget_hbs_compiler_source = File.read("#{Rails.root}/lib/javascripts/widget-hbs-compiler.js")
widget_hbs_compiler_source =
File.read(
"#{Rails.root}/app/assets/javascripts/discourse-widget-hbs/lib/widget-hbs-compiler.js",
)
widget_hbs_compiler_source = <<~JS
define("widget-hbs-compiler", ["exports"], function(exports){
#{widget_hbs_compiler_source}

View File

@ -22,7 +22,7 @@ class ChatMessage < ActiveRecord::Base
# TODO (martin) Remove this when we drop the ChatUpload table
has_many :chat_uploads, dependent: :destroy
has_one :chat_webhook_event, dependent: :destroy
has_one :chat_mention, dependent: :destroy
has_many :chat_mentions, dependent: :destroy
scope :in_public_channel,
-> {

View File

@ -5,6 +5,8 @@ require "rails_helper"
describe ChatMessage do
fab!(:message) { Fabricate(:chat_message, message: "hey friend, what's up?!") }
it { is_expected.to have_many(:chat_mentions).dependent(:destroy) }
describe ".cook" do
it "does not support HTML tags" do
cooked = ChatMessage.cook("<h1>test</h1>")

View File

@ -217,6 +217,8 @@ export function createData(store) {
{ disabled: true, text: "disabled" },
],
toggleSwitchState: true,
navItems: ["latest", "categories", "top"].map((name) => {
let item = NavItem.fromText(name);

View File

@ -152,4 +152,14 @@
@translatedLabel={{bs.text}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title="DToggleSwitch">
<DToggleSwitch
@state={{this.dummy.toggleSwitchState}}
{{on
"click"
(fn (mut this.dummy.toggleSwitchState) (not this.dummy.toggleSwitchState))
}}
/>
</StyleguideExample>

View File

@ -223,6 +223,7 @@ class ImportScripts::Drupal < ImportScripts::Base
AND c.status = 1
AND n.type IN ('blog', 'forum')
AND n.status = 1
ORDER BY c.cid ASC
LIMIT #{BATCH_SIZE}
OFFSET #{offset}
SQL

View File

@ -137,9 +137,16 @@ RSpec.describe Jobs::CleanUpUploads do
Jobs::CleanUpUploads.new.execute(nil)
[
logo_upload, logo_small_upload, digest_logo_upload, mobile_logo_upload, large_icon_upload,
opengraph_image_upload, twitter_summary_large_image_upload, favicon_upload,
apple_touch_icon_upload, system_upload,
logo_upload,
logo_small_upload,
digest_logo_upload,
mobile_logo_upload,
large_icon_upload,
opengraph_image_upload,
twitter_summary_large_image_upload,
favicon_upload,
apple_touch_icon_upload,
system_upload,
].each { |record| expect(Upload.exists?(id: record.id)).to eq(true) }
fabricate_upload

View File

@ -29,7 +29,7 @@ describe "Admin Customize Form Templates", type: :system, js: true do
it "should prefill form data" do
visit("/admin/customize/form-templates/#{form_template.id}")
expect(form_template_page).to have_name_value(form_template.name)
# difficult to test the ace editor content (todo later)
# TODO(@keegan) difficult to test the ace editor content, todo later
end
end