DEV: Update linting setup and fix issues (#17345)

Re-lands #16119 and #17298

* Update eslint-config-discourse
* Update linting workflow
* Prettier-ignore stuff
* Update template-lint config
* Auto-fix template issues
* Fix various template issues
  Mostly incorrect attributes and unused templates
* Prettier js files
* Fix template auto-fix regressions
* Small css tweak

Co-authored-by: Peter Wagenet <peter.wagenet@gmail.com>
This commit is contained in:
Jarek Radosz 2022-07-06 10:37:54 +02:00 committed by GitHub
parent f7c133ac74
commit c3fd91670e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 3235 additions and 3127 deletions

View File

@ -86,8 +86,9 @@ jobs:
if: ${{ always() }}
run: |
yarn ember-template-lint \
app/assets/javascripts \
plugins/**/assets/javascripts
--no-error-on-unmatched-pattern \
"app/assets/javascripts/**/*.hbs" \
"plugins/**/assets/javascripts/**/*.hbs"
- name: English locale lint (core)
if: ${{ always() }}

View File

@ -22,4 +22,10 @@ app/assets/javascripts/discourse/tests/fixtures
spec/
node_modules/
dist/
tmp/
**/*.rb
**/*.hbs
**/*.html
**/*.json
**/*.md

View File

@ -1,58 +1,9 @@
module.exports = {
extends: "recommended",
ignore: ["**/*.raw"],
plugins: ["ember-template-lint-plugin-discourse"],
extends: "discourse:recommended",
rules: {
"block-indentation": true,
"deprecated-render-helper": true,
"eol-last": "always",
"linebreak-style": true,
"link-rel-noopener": "strict",
"no-abstract-roles": true,
"no-args-paths": true,
"no-attrs-in-components": true,
"no-debugger": true,
"no-duplicate-attributes": true,
"no-extra-mut-helper-argument": true,
"no-html-comments": true,
"no-index-component-invocation": true,
"no-inline-styles": false,
"no-input-block": true,
"no-input-tagname": true,
"no-implicit-this": {
allow: [
'loading-spinner'
]
},
"no-invalid-interactive": true,
"no-invalid-link-text": true,
"no-invalid-meta": true,
"no-invalid-role": true,
"no-log": true,
"no-negated-condition": true,
"no-nested-interactive": true,
"no-multiple-empty-lines": true,
"no-obsolete-elements": true,
"no-outlet-outside-routes": true,
"no-partial": true,
"no-positive-tabindex": false,
"no-quoteless-attributes": true,
"no-shadowed-elements": true,
"no-trailing-spaces": true,
"no-triple-curlies": true,
"no-unbound": true,
"no-unnecessary-concat": true,
"no-unnecessary-component-helper": true,
"no-unused-block-params": true,
quotes: "double",
"require-button-type": true,
"require-iframe-title": true,
"require-valid-alt-text": false,
"self-closing-void-elements": true,
"simple-unless": true,
"style-concatenation": true,
"table-groups": true,
"link-href-attributes": false,
"no-capital-arguments": false, // TODO: we extensively use `args` argument name
"no-curly-component-invocation": {
allow: [
// These are helpers, not components
@ -64,5 +15,8 @@ module.exports = {
"mobile-directory-item-label",
],
},
"no-implicit-this": {
allow: ["loading-spinner"],
},
},
};

View File

@ -5,7 +5,8 @@ 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;
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",

View File

@ -12,7 +12,7 @@ export default Controller.extend({
"filter",
"siteSettings.dashboard_hidden_reports"
)
filterReports(reports, filter) {
filteredReports(reports, filter) {
if (filter) {
filter = filter.toLowerCase();
reports = reports.filter((report) => {

View File

@ -32,8 +32,9 @@ export default Route.extend({
actions: {
installModal() {
const currentTheme = this.controllerFor("adminCustomizeThemes.show")
.model;
const currentTheme = this.controllerFor(
"adminCustomizeThemes.show"
).model;
if (currentTheme && currentTheme.warnUnassignedComponent) {
showUnassignedComponentWarning(currentTheme, (result) => {
if (!result) {

View File

@ -12,8 +12,9 @@ export default DiscourseRoute.extend({
const routeName = "adminUsersList.show";
if (transition.targetName === routeName) {
const params = transition.routeInfos.find((a) => a.name === routeName)
.params;
const params = transition.routeInfos.find(
(a) => a.name === routeName
).params;
const controller = this.controllerFor(routeName);
if (controller) {
controller.setProperties({

View File

@ -46,9 +46,10 @@ export default Service.extend({
});
controller.setProperties({ postId: opts.postId, postEdit: opts.postEdit });
return (user.adminUserView
? Promise.resolve(user)
: AdminUser.find(user.get("id"))
return (
user.adminUserView
? Promise.resolve(user)
: AdminUser.find(user.get("id"))
).then((loadedUser) => {
controller.setProperties({
user: loadedUser,

View File

@ -16,7 +16,7 @@
</AdminFormRow>
{{else}}
<AdminFormRow @label="admin.api.description">
<Input @value={{this.model.description}} @maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
<Input @value={{this.model.description}} maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
</AdminFormRow>
<AdminFormRow @label="admin.api.user_mode">
@ -76,7 +76,7 @@
</td>
<td>
{{#each act.params as |p|}}
<Input @maxlength="255" @value={{get act p}} placeholder={{p}} />
<Input maxlength="255" @value={{get act p}} placeholder={{p}} />
{{/each}}
</td>
</tr>

View File

@ -11,7 +11,7 @@
<AdminFormRow @label="admin.api.description">
{{#if this.editingDescription}}
<Input @value={{this.buffered.description}} @maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
<Input @value={{this.buffered.description}} maxlength="255" placeholder={{i18n "admin.api.description_placeholder"}} />
{{else}}
<span>
{{if this.model.description this.model.description (i18n "admin.api.no_description")}}

View File

@ -3,14 +3,14 @@
<div class="control-group">
<label for="name">{{i18n "admin.badges.name"}}</label>
{{#if this.readOnly}}
<Input @type="text" @name="name" @value={{this.buffered.name}} @disabled={{true}} />
<Input @type="text" name="name" @value={{this.buffered.name}} disabled={{true}} />
<p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "name")}}>
{{i18n "admin.badges.read_only_setting_help"}}
</LinkTo>
</p>
{{else}}
<Input @type="text" @name="name" @value={{this.buffered.name}} />
<Input @type="text" name="name" @value={{this.buffered.name}} />
{{/if}}
</div>
@ -56,28 +56,28 @@
<div class="control-group">
<label for="description">{{i18n "admin.badges.description"}}</label>
{{#if this.buffered.system}}
<Textarea @name="description" @value={{this.buffered.description}} @disabled={{true}} />
<Textarea name="description" @value={{this.buffered.description}} disabled={{true}} />
<p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "description")}}>
{{i18n "admin.badges.read_only_setting_help"}}
</LinkTo>
</p>
{{else}}
<Textarea @name="description" @value={{this.buffered.description}} />
<Textarea name="description" @value={{this.buffered.description}} />
{{/if}}
</div>
<div class="control-group">
<label for="long_description">{{i18n "admin.badges.long_description"}}</label>
{{#if this.buffered.system}}
<Textarea @name="long_description" @value={{this.buffered.long_description}} @disabled={{true}} />
<Textarea name="long_description" @value={{this.buffered.long_description}} disabled={{true}} />
<p class="help">
<LinkTo @route="adminSiteText" @query={{hash q=(concat this.textCustomizationPrefix "long_description")}}>
{{i18n "admin.badges.read_only_setting_help"}}
</LinkTo>
</p>
{{else}}
<Textarea @name="long_description" @value={{this.buffered.long_description}} />
<Textarea name="long_description" @value={{this.buffered.long_description}} />
{{/if}}
</div>
@ -97,14 +97,14 @@
<div class="control-group">
<label>
<Input @type="checkbox" @checked={{this.buffered.auto_revoke}} @disabled={{this.readOnly}} />
<Input @type="checkbox" @checked={{this.buffered.auto_revoke}} disabled={{this.readOnly}} />
{{i18n "admin.badges.auto_revoke"}}
</label>
</div>
<div class="control-group">
<label>
<Input @type="checkbox" @checked={{this.buffered.target_posts}} @disabled={{this.readOnly}} />
<Input @type="checkbox" @checked={{this.buffered.target_posts}} disabled={{this.readOnly}} />
{{i18n "admin.badges.target_posts"}}
</label>
</div>
@ -128,21 +128,21 @@
<div>
<label>
<Input @type="checkbox" @checked={{this.buffered.multiple_grant}} @disabled={{this.readOnly}} />
<Input @type="checkbox" @checked={{this.buffered.multiple_grant}} disabled={{this.readOnly}} />
{{i18n "admin.badges.multiple_grant"}}
</label>
</div>
<div>
<label>
<Input @type="checkbox" @checked={{this.buffered.listable}} @disabled={{this.readOnly}} />
<Input @type="checkbox" @checked={{this.buffered.listable}} disabled={{this.readOnly}} />
{{i18n "admin.badges.listable"}}
</label>
</div>
<div>
<label>
<Input @type="checkbox" @checked={{this.buffered.show_posts}} @disabled={{this.readOnly}} />
<Input @type="checkbox" @checked={{this.buffered.show_posts}} disabled={{this.readOnly}} />
{{i18n "admin.badges.show_posts"}}
</label>
</div>

View File

@ -3,7 +3,7 @@
<ul class="nav nav-pills target">
{{#each this.visibleTargets as |target|}}
<li>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id target.name this.fieldName}} @replace={{true}} @title={{this.field.title}} class={{if target.edited "edited" "blank"}}>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id target.name this.fieldName}} @replace={{true}} title={{this.field.title}} class={{if target.edited "edited" "blank"}}>
{{#if target.error}}{{d-icon "exclamation-triangle"}}{{/if}}
{{#if target.icon}}{{d-icon target.icon}}{{/if}}
{{i18n (concat "admin.customize.theme." target.name)}}
@ -24,7 +24,7 @@
<li class="spacer"></li>
<li>
<label>
<Input @type="checkbox" @checked={{this.onlyOverridden}} @click={{action "onlyOverriddenChanged" value="target.checked"}} />
<Input @type="checkbox" @checked={{this.onlyOverridden}} {{on "click" (action "onlyOverriddenChanged" value="target.checked")}} />
{{i18n "admin.customize.theme.hide_unused_fields"}}
</label>
</li>
@ -37,7 +37,7 @@
<ul class="nav nav-pills fields">
{{#each this.visibleFields as |field|}}
<li>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id this.currentTargetName field.name}} @replace={{true}} @title={{field.title}} class={{if field.edited "edited" "blank"}}>
<LinkTo @route={{this.editRouteName}} @models={{array this.theme.id this.currentTargetName field.name}} @replace={{true}} title={{field.title}} class={{if field.edited "edited" "blank"}}>
{{#if field.error}}{{d-icon "exclamation-triangle"}}{{/if}}
{{#if field.icon}}{{d-icon field.icon}}{{/if}}
{{field.translatedName}}

View File

@ -5,11 +5,11 @@
</AdminFormRow>
<AdminFormRow @label="admin.user_fields.name">
<Input @value={{this.buffered.name}} class="user-field-name" @maxlength="255" />
<Input @value={{this.buffered.name}} class="user-field-name" maxlength="255" />
</AdminFormRow>
<AdminFormRow @label="admin.user_fields.description">
<Input @value={{this.buffered.description}} class="user-field-desc" @maxlength="255" />
<Input @value={{this.buffered.description}} class="user-field-desc" maxlength="255" />
</AdminFormRow>
{{#if this.bufferedFieldType.hasOptions}}

View File

@ -1,3 +1,3 @@
<Input @id={{this.typeName}} @type="checkbox" @name="event-choice" @checked={{this.enabled}} />
<Input id={{this.typeName}} @type="checkbox" name="event-choice" @checked={{this.enabled}} />
<label for={{this.typeName}}>{{this.name}}</label>
<p>{{this.details}}</p>

View File

@ -1,7 +1,7 @@
{{#if this.editing}}
<td class="editing-input">
<div class="label">{{i18n "admin.embedding.host"}}</div>
<Input @value={{this.buffered.host}} placeholder="example.com" @enter={{action "save"}} class="host-name" @autofocus={{true}} />
<Input @value={{this.buffered.host}} placeholder="example.com" @enter={{action "save"}} class="host-name" autofocus={{true}} />
</td>
<td class="editing-input">
<div class="label">{{i18n "admin.embedding.class_name"}}</div>

View File

@ -1,11 +1,11 @@
{{#if this.isCheckbox}}
<label for={{this.inputId}}>
<Input @checked={{this.checked}} @id={{this.inputId}} @type="checkbox" />
<Input @checked={{this.checked}} id={{this.inputId}} @type="checkbox" />
{{i18n this.translationKey}}
</label>
{{else}}
<label for={{this.inputId}}>{{i18n this.translationKey}}</label>
<Input @value={{this.value}} @id={{this.inputId}} placeholder={{this.placeholder}} />
<Input @value={{this.value}} id={{this.inputId}} placeholder={{this.placeholder}} />
{{/if}}
<div class="clearfix"></div>

View File

@ -1,5 +1,5 @@
<label class="checkbox-label">
<Input @type="checkbox" @disabled={{this.disabled}} @checked={{this.buffer}} />
<Input @type="checkbox" disabled={{this.disabled}} @checked={{this.buffer}} />
{{i18n this.labelKey}}
</label>
{{#if this.changed}}

View File

@ -1 +1 @@
<Input @type="checkbox" @checked={{this.checked}} @click={{action "onChange"}} />
<Input @type="checkbox" @checked={{this.checked}} {{on "click" (action "onChange")}} />

View File

@ -3,8 +3,8 @@
{{#each this.collection as |value index|}}
<div class="value" data-index={{index}}>
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @value={{value.key}} class="value-input" @focus-out={{action "changeKey" index}} />
<Input @value={{value.secret}} class="value-input" @focus-out={{action "changeSecret" index}} @type={{if this.isSecret "password" "text"}} />
<Input @value={{value.key}} class="value-input" {{on "focusout" (action "changeKey" index)}} />
<Input @value={{value.secret}} class="value-input" @type={{if this.isSecret "password" "text"}} {{on "focusout" (action "changeSecret" index)}} />
</div>
{{/each}}
</div>

View File

@ -4,21 +4,19 @@
<div data-index={{index}} class="value">
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @title={{value}} @value={{value}} class="value-input" @focus-out={{action "changeValue" index}} />
<Input title={{value}} @value={{value}} class="value-input" {{on "focusout" (action "changeValue" index)}} />
{{#if this.showUpDownButtons}}
<DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" />
<DButton @action={{action "shift" 1 index}} @icon="arrow-down" @class="shift-down-value-btn btn-small" />
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
<div class="simple-list-input">
<Input @type="text" @value={{this.newValue}} @placeholderKey="admin.site_settings.simple_list.add_item" class="add-value-input" @autocomplete="off" @autocorrect="off" @autocapitalize="off" />
<Input @type="text" @value={{this.newValue}} placeholder={{i18n "admin.site_settings.simple_list.add_item"}} class="add-value-input" autocomplete="off" autocorrect="off" autocapitalize="off" />
<DButton @action={{action "addValue"}} @actionParam={{this.newValue}} @disabled={{this.inputEmpty}} @icon="plus" @class="add-value-btn btn-small" />
</div>

View File

@ -2,7 +2,7 @@
<h3>
{{#if this.staffLogFilter}}
{{this.settingName}}
<LinkTo @route="adminLogs.staffActionLogs" @query={{hash filters=this.staffLogFilter force_refresh=true}} @title={{i18n "admin.settings.history"}}>
<LinkTo @route="adminLogs.staffActionLogs" @query={{hash filters=this.staffLogFilter force_refresh=true}} title={{i18n "admin.settings.history"}}>
<span class="history-icon">
{{d-icon "history"}}
</span>

View File

@ -1,9 +1,9 @@
{{#if this.setting.textarea}}
<Textarea @value={{this.value}} @classNames="input-setting-textarea" />
<Textarea @value={{this.value}} class="input-setting-textarea" />
{{else if this.setting.json_schema}}
<DButton @action={{action "launchJsonEditorModal"}} @icon="pencil-alt" @label="admin.site_settings.json_schema.edit" />
{{else if this.isSecret}}
<Input @type="password" @value={{this.value}} @classNames="input-setting-string" />
<Input @type="password" @value={{this.value}} class="input-setting-string" />
{{else}}
<TextField @value={{this.value}} @classNames="input-setting-string" />
{{/if}}

View File

@ -1,4 +1,4 @@
{{!-- template-lint-disable no-invalid-interactive --}}
<div class="table staff-actions" {{on "click" (fn this.openLinks)}}>
<div class="table staff-actions" {{on "click" this.openLinks}}>
{{yield}}
</div>

View File

@ -6,7 +6,7 @@
<div class="themes-list-container">
{{#if this.showFilter}}
<div class="themes-list-filter themes-list-item">
<Input class="filter-input" placeholder={{i18n "admin.customize.theme.filter_placeholder"}} @autocomplete="off" @type="search" @value={{mut this.filterTerm}} />
<Input class="filter-input" placeholder={{i18n "admin.customize.theme.filter_placeholder"}} autocomplete="off" @type="search" @value={{mut this.filterTerm}} />
{{d-icon "search"}}
</div>
{{/if}}

View File

@ -4,7 +4,7 @@
<div data-index={{index}} class="value">
<DButton @action={{action "removeValue"}} @actionParam={{value}} @icon="times" @class="remove-value-btn btn-small" />
<Input @title={{value}} @value={{value}} class="value-input" @focus-out={{action "changeValue" index}} />
<Input title={{value}} @value={{value}} class="value-input" {{on "focusout" (action "changeValue" index)}} />
{{#if this.showUpDownButtons}}
<DButton @action={{action "shift" -1 index}} @icon="arrow-up" @class="shift-up-value-btn btn-small" />

View File

@ -22,8 +22,8 @@
{{#if this.canLink}}
<div class="watched-word-input">
<label for="watched-replacement">{{i18n "admin.watched_words.form.link_label"}}</label>
<TextField @id="watched-replacement" @value={{this.replacement}} @disabled={{this.formSubmitted}} @class="watched-word-input-field" @autocorrect="off" @autocapitalize="off" @placeholderKey="admin.watched_words.form.link_placeholder" />
<label for="watched-link">{{i18n "admin.watched_words.form.link_label"}}</label>
<TextField @id="watched-link" @value={{this.replacement}} @disabled={{this.formSubmitted}} @class="watched-word-input-field" @autocorrect="off" @autocapitalize="off" @placeholderKey="admin.watched_words.form.link_placeholder" />
</div>
{{/if}}

View File

@ -2,11 +2,11 @@
<div class="reports-index section">
<div class="section-title">
<h2>{{i18n "admin.reports.title"}}</h2>
<Input class="filter-reports-input" @input={{action "filterReports" value="target.value"}} placeholder={{i18n "admin.dashboard.filter_reports"}} @autofocus={{true}} />
<Input class="filter-reports-input" placeholder={{i18n "admin.dashboard.filter_reports"}} autofocus={{true}} {{on "input" (action "filterReports" value="target.value")}} />
</div>
<ul class="reports-list">
{{#each this.filterReports as |report|}}
{{#each this.filteredReports as |report|}}
<li class="report">
<LinkTo @route="adminReports.show" @model={{report.type}}>
<h3 class="report-title">{{report.title}}</h3>

View File

@ -2,7 +2,7 @@
<div class="email-advanced-test">
<label for="email">{{i18n "admin.email.advanced_test.email"}}</label>
<Textarea @name="email" @value={{this.email}} class="email-body" /> <DButton @action={{action "run"}} @label="admin.email.advanced_test.run" />
<Textarea name="email" @value={{this.email}} class="email-body" /> <DButton @action={{action "run"}} @label="admin.email.advanced_test.run" />
</div>
<ConditionalLoadingSpinner @condition={{this.loading}}>

View File

@ -1,7 +1,7 @@
<p>
{{i18n "admin.logs.screened_urls.description"}}
</p>
<DButton @class="btn-default" @action={{action "exportScreenedUrlList"}} @title="admin.export_csv.button_title.screened_url" @icon="download" @label="admin.export_csv.button_text" />
<DButton @class="btn-default" @action={{action "exportScreenedUrlList"}} @title="admin.export_csv.button_title.screened_url" @icon="download" @label="admin.export_csv.button_text" />
<br>
<ConditionalLoadingSpinner @condition={{this.loading}}>

View File

@ -6,7 +6,7 @@
</section>
<section class="field">
<label for="theme-variable-name">{{i18n "admin.customize.theme.variable_name"}}</label>
<Input @id="theme-variable-name" @value={{this.name}} />
<Input id="theme-variable-name" @value={{this.name}} />
</section>
{{#if this.fileSelected}}
{{#if this.errorMessage}}

View File

@ -14,7 +14,7 @@
<div class="control-group">
<label>{{i18n "admin.email.incoming_emails.modal.headers"}}</label>
<div class="controls">
<Textarea @value={{this.model.headers}} @wrap="off" />
<Textarea @value={{this.model.headers}} wrap="off" />
</div>
</div>

View File

@ -72,7 +72,7 @@
<div class="public-key">
<div class="label">{{i18n "admin.customize.theme.public_key"}}</div>
<div class="public-key-text-wrapper">
<Textarea class="public-key-value" @readonly={{true}} @value={{this.publicKey}} /> <CopyButton @selector="textarea.public-key-value" />
<Textarea class="public-key-value" readonly={{true}} @value={{this.publicKey}} /> <CopyButton @selector="textarea.public-key-value" />
</div>
</div>
{{else}}

View File

@ -1,6 +1,6 @@
<DModalBody @rawTitle={{i18n "admin.watched_words.test.modal_title" action=this.model.name}} @class="watched-words-test-modal">
<p>{{i18n "admin.watched_words.test.description"}}</p>
<Textarea @name="test_value" @value={{this.value}} @autofocus="autofocus" />
<Textarea name="test_value" @value={{this.value}} autofocus="autofocus" />
{{#if this.matches}}
<p>
{{i18n "admin.watched_words.test.found_matches"}}

View File

@ -14,7 +14,7 @@
</div>
<label>
<Input @type="checkbox" @checked={{this.overridden}} @click={{action "toggleOverridden"}} />
<Input @type="checkbox" @checked={{this.overridden}} {{on "click" (action "toggleOverridden")}} />
{{i18n "admin.site_text.show_overriden"}}
</label>
</p>

View File

@ -22,7 +22,7 @@
{{#if this.currentAction.words}}
<label class="show-words-checkbox">
<Input @type="checkbox" @checked={{this.adminWatchedWords.showWords}} @disabled={{this.adminWatchedWords.disableShowWords}} />
<Input @type="checkbox" @checked={{this.adminWatchedWords.showWords}} disabled={{this.adminWatchedWords.disableShowWords}} />
{{i18n "admin.watched_words.show_words" count=this.currentAction.words.length}}
</label>
{{/if}}

View File

@ -1,9 +1,9 @@
<div class="web-hook-direction">
<LinkTo @route="adminWebHooks" @tagName="button" @classNames="btn">
<LinkTo @route="adminWebHooks" class="btn">
{{d-icon "list"}} {{i18n "admin.web_hooks.events.go_list"}}
</LinkTo>
<DButton @icon="paper-plane" @label="admin.web_hooks.events.ping" @action={{action "ping"}} @disabled={{this.pingDisabled}} />
<LinkTo @route="adminWebHooks.show" @model={{this.model.extras.web_hook_id}} @tagName="button" @classNames="btn">
<LinkTo @route="adminWebHooks.show" @model={{this.model.extras.web_hook_id}} class="btn">
{{d-icon "far-edit"}} {{i18n "admin.web_hooks.events.go_details"}}
</LinkTo>
</div>

View File

@ -66,11 +66,11 @@
<PluginOutlet @name="web-hook-fields" @tagName="span" @connectorTagName="div" @args={{hash model=this.model}} />
<div>
<Input @type="checkbox" @name="verify_certificate" @checked={{this.model.verify_certificate}} /> {{i18n "admin.web_hooks.verify_certificate"}}
<Input @type="checkbox" name="verify_certificate" @checked={{this.model.verify_certificate}} /> {{i18n "admin.web_hooks.verify_certificate"}}
</div>
<div>
<div>
<Input @type="checkbox" @name="active" @checked={{this.model.active}} /> {{i18n "admin.web_hooks.active"}}
<Input @type="checkbox" name="active" @checked={{this.model.active}} /> {{i18n "admin.web_hooks.active"}}
</div>
{{#if this.model.active}}
<div class="instructions">{{i18n "admin.web_hooks.active_notice"}}</div>

View File

@ -1,7 +1,7 @@
<div class="web-hooks-listing">
<p>{{i18n "admin.web_hooks.instruction"}}</p>
<div class="new-webhook">
<LinkTo @route="adminWebHooks.show" @model="new" @tagName="button" @classNames="btn btn-default">
<LinkTo @route="adminWebHooks.show" @model="new" class="btn btn-default">
{{d-icon "plus"}} {{i18n "admin.web_hooks.new"}}
</LinkTo>
</div>
@ -23,7 +23,7 @@
<td class="payload-url"><LinkTo @route="adminWebHooks.show" @model={{webHook}}>{{webHook.payload_url}}</LinkTo></td>
<td class="description">{{webHook.description}}</td>
<td class="controls">
<LinkTo @route="adminWebHooks.show" @model={{webHook}} @tagName="button" @classNames="btn btn-default no-text">{{d-icon "far-edit"}}</LinkTo>
<LinkTo @route="adminWebHooks.show" @model={{webHook}} class="btn btn-default no-text">{{d-icon "far-edit"}}</LinkTo>
<DButton @class="destroy btn-danger" @action={{action "destroy"}} @actionParam={{webHook}} @icon="times" />
</td>
</tr>

View File

@ -10,9 +10,8 @@ if (security) {
.getElementById("security-key-allowed-credential-ids")
.value.split(","),
(credentialData) => {
document.getElementById(
"security-key-credential"
).value = JSON.stringify(credentialData);
document.getElementById("security-key-credential").value =
JSON.stringify(credentialData);
$(e.target).parents("form").submit();
},

View File

@ -130,7 +130,8 @@ TemplateCompiler.prototype.targetExtension = "js";
TemplateCompiler.prototype.registerPlugins = function registerPlugins() {};
TemplateCompiler.prototype.initializeFeatures = function initializeFeatures() {};
TemplateCompiler.prototype.initializeFeatures =
function initializeFeatures() {};
TemplateCompiler.prototype.processString = function (string, relativePath) {
let filename = relativePath.replace(/^templates\//, "").replace(/\.hbr$/, "");

View File

@ -1,7 +1,7 @@
"use strict";
const WidgetHbsCompiler = require("../../../../lib/javascripts/widget-hbs-compiler")
.WidgetHbsCompiler;
const WidgetHbsCompiler =
require("../../../../lib/javascripts/widget-hbs-compiler").WidgetHbsCompiler;
const glimmer = require("@glimmer/syntax");

View File

@ -48,7 +48,8 @@ import userSearch from "discourse/lib/user-search";
// Group 3 is optional. group 4 can match images with or without a markdown title.
// All matches are whitespace tolerant as long it's still valid markdown.
// If the image is inside a code block, we'll ignore it `(?!(.*`))`.
const IMAGE_MARKDOWN_REGEX = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
const IMAGE_MARKDOWN_REGEX =
/!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
let uploadHandlers = [];
export function addComposerUploadHandler(extensions, method) {
@ -565,9 +566,8 @@ export default Component.extend(ComposerUploadUppy, {
);
const scale = event.target.dataset.scale;
const matchingPlaceholder = this.get("composer.reply").match(
IMAGE_MARKDOWN_REGEX
);
const matchingPlaceholder =
this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
if (matchingPlaceholder) {
const match = matchingPlaceholder[index];
@ -608,9 +608,8 @@ export default Component.extend(ComposerUploadUppy, {
commitAltText(buttonWrapper) {
const index = parseInt(buttonWrapper.getAttribute("data-image-index"), 10);
const matchingPlaceholder = this.get("composer.reply").match(
IMAGE_MARKDOWN_REGEX
);
const matchingPlaceholder =
this.get("composer.reply").match(IMAGE_MARKDOWN_REGEX);
const match = matchingPlaceholder[index];
const input = buttonWrapper.querySelector("input.alt-text-input");
const replacement = match.replace(

View File

@ -51,9 +51,8 @@ export default Component.extend({
let userTextFields = document.getElementsByClassName("user-fields")[0];
if (userTextFields) {
userTextFields = userTextFields.getElementsByClassName(
"ember-text-field"
);
userTextFields =
userTextFields.getElementsByClassName("ember-text-field");
}
if (userTextFields) {
@ -76,9 +75,8 @@ export default Component.extend({
let userTextFields = document.getElementsByClassName("user-fields")[0];
if (userTextFields) {
userTextFields = userTextFields.getElementsByClassName(
"ember-text-field"
);
userTextFields =
userTextFields.getElementsByClassName("ember-text-field");
}
if (userTextFields) {

View File

@ -499,9 +499,10 @@ export default Component.extend(TextareaTextManipulation, {
return false;
}
const matches = /(?:^|[\s.\?,@\/#!%&*;:\[\]{}=\-_()])(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gi.exec(
text.substring(0, cp)
);
const matches =
/(?:^|[\s.\?,@\/#!%&*;:\[\]{}=\-_()])(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gi.exec(
text.substring(0, cp)
);
if (matches && matches[1]) {
return [matches[1]];

View File

@ -200,9 +200,8 @@ export default Component.extend({
}
focusableElements = focusableElements + ", button:enabled";
const firstFocusableElement = innerContainer.querySelectorAll(
focusableElements
)?.[0];
const firstFocusableElement =
innerContainer.querySelectorAll(focusableElements)?.[0];
const focusableContent = innerContainer.querySelectorAll(focusableElements);
const lastFocusableElement = focusableContent[focusableContent.length - 1];

View File

@ -17,12 +17,9 @@ export default Component.extend({
"form.imap_port"
)
missingSettings(email_username, email_password, imap_server, imap_port) {
return [
email_username,
email_password,
imap_server,
imap_port,
].some((value) => isEmpty(value));
return [email_username, email_password, imap_server, imap_port].some(
(value) => isEmpty(value)
);
},
@discourseComputed("group.imap_mailboxes")

View File

@ -17,12 +17,9 @@ export default Component.extend({
"form.smtp_port"
)
missingSettings(email_username, email_password, smtp_server, smtp_port) {
return [
email_username,
email_password,
smtp_server,
smtp_port,
].some((value) => isEmpty(value));
return [email_username, email_password, smtp_server, smtp_port].some(
(value) => isEmpty(value)
);
},
@action

View File

@ -206,9 +206,8 @@ export default Controller.extend(ModalFunctionality, {
} else {
this.set("loggedIn", true);
// Trigger the browser's password manager using the hidden static login form:
const hiddenLoginForm = document.getElementById(
"hidden-login-form"
);
const hiddenLoginForm =
document.getElementById("hidden-login-form");
const applyHiddenFormInputValue = (value, key) => {
if (!hiddenLoginForm) {
return;

View File

@ -74,9 +74,10 @@ export default Controller.extend({
saveEmail() {
this.set("saving", true);
return (this.new
? this.model.addEmail(this.newEmail)
: this.model.changeEmail(this.newEmail)
return (
this.new
? this.model.addEmail(this.newEmail)
: this.model.changeEmail(this.newEmail)
).then(
() => {
this.set("success", true);

View File

@ -781,8 +781,8 @@ export default Controller.extend(bufferedProperty("model"), {
Bookmark.create({
bookmarkable_id: post.id,
bookmarkable_type: "Post",
auto_delete_preference: this.currentUser
.bookmark_auto_delete_preference,
auto_delete_preference:
this.currentUser.bookmark_auto_delete_preference,
}),
post
);
@ -1335,8 +1335,8 @@ export default Controller.extend(bufferedProperty("model"), {
Bookmark.create({
bookmarkable_id: this.model.id,
bookmarkable_type: "Topic",
auto_delete_preference: this.currentUser
.bookmark_auto_delete_preference,
auto_delete_preference:
this.currentUser.bookmark_auto_delete_preference,
})
);
}

View File

@ -31,11 +31,9 @@ export default Controller.extend({
discourseDebounce(
this,
function () {
Invite.findInvitedBy(
this.user,
this.filter,
this.searchTerm
).then((invites) => this.set("model", invites));
Invite.findInvitedBy(this.user, this.filter, this.searchTerm).then(
(invites) => this.set("model", invites)
);
},
INPUT_DELAY
);

View File

@ -46,8 +46,8 @@ export default function offsetCalculator() {
const windowHeight = window.innerHeight;
const documentHeight = document.body.clientHeight;
const topicBottomOffsetTop = document.getElementById("topic-bottom")
.offsetTop;
const topicBottomOffsetTop =
document.getElementById("topic-bottom").offsetTop;
// the footer is bigger than the window, we can scroll down past the last post
if (documentHeight - windowHeight > topicBottomOffsetTop) {

View File

@ -1,7 +1,8 @@
import { prioritizeNameFallback } from "discourse/lib/settings";
import { helperContext } from "discourse-common/lib/helpers";
export const QUOTE_REGEXP = /\[quote=([^\]]*)\]((?:[\s\S](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im;
export const QUOTE_REGEXP =
/\[quote=([^\]]*)\]((?:[\s\S](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im;
// Build the BBCode quote around the selected text
export function buildQuote(post, contents, opts = {}) {

View File

@ -90,8 +90,8 @@ export default class StickyAvatars {
return;
}
const postContentHeight = entry.target.querySelector(".contents")
?.clientHeight;
const postContentHeight =
entry.target.querySelector(".contents")?.clientHeight;
if (
this.direction === "⬆️" ||
postContentHeight > window.innerHeight - headerOffset()

View File

@ -127,7 +127,8 @@ export function validateUploadedFile(file, opts) {
return true;
}
export const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|svg|ico|heic|heif|webp)/i;
export const IMAGES_EXTENSIONS_REGEX =
/(png|jpe?g|gif|svg|ico|heic|heif|webp)/i;
function extensionsToArray(exts) {
return exts

View File

@ -51,8 +51,8 @@ export default class UppyMediaOptimization extends UploadPreProcessorPlugin {
@bind
async _optimizeSerial(fileIds) {
let optimizeTasks = fileIds.map((fileId) => () =>
this._optimizeFile(fileId)
let optimizeTasks = fileIds.map(
(fileId) => () => this._optimizeFile(fileId)
);
for (const task of optimizeTasks) {

View File

@ -199,7 +199,8 @@ function organizeResults(r, options) {
// will not find me, which is a reasonable compromise
//
// we also ignore if we notice a double space or a string that is only a space
const ignoreRegex = /([\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*,\/:;<=>?\[\]^`{|}~])|\s\s|^\s$|^[^+]*\+[^@]*$/;
const ignoreRegex =
/([\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*,\/:;<=>?\[\]^`{|}~])|\s\s|^\s$|^[^+]*\+[^@]*$/;
export function skipSearch(term, allowEmails, lastSeenUsers = false) {
if (lastSeenUsers) {

View File

@ -139,13 +139,15 @@ export function highlightPost(postNumber) {
export function emailValid(email) {
// see: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
const re = /^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/;
const re =
/^[a-zA-Z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'\*+\/=?\^_`{|}~\-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/;
return re.test(email);
}
export function hostnameValid(hostname) {
// see: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
const re = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
const re =
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
return hostname && re.test(hostname);
}
@ -457,7 +459,8 @@ export function postRNWebviewMessage(prop, value) {
}
}
const CODE_BLOCKS_REGEX = /^( |\t).*|`[^`]+`|^```[^]*?^```|\[code\][^]*?\[\/code\]/gm;
const CODE_BLOCKS_REGEX =
/^( |\t).*|`[^`]+`|^```[^]*?^```|\[code\][^]*?\[\/code\]/gm;
// | ^ | ^ | ^ | ^ |
// | | | |
// | | | code blocks between [code]

View File

@ -125,8 +125,8 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
user: this.currentUser,
siteSettings: this.siteSettings,
isPrivateMessage,
allowStaffToUploadAnyFileInPm: this.siteSettings
.allow_staff_to_upload_any_file_in_pm,
allowStaffToUploadAnyFileInPm:
this.siteSettings.allow_staff_to_upload_any_file_in_pm,
};
const isUploading = validateUploadedFile(currentFile, validationOpts);

View File

@ -95,9 +95,10 @@ export default Mixin.create({
const post = value.slice(end);
if (opts && opts.lineVal) {
const lineVal = value.split("\n")[
value.slice(0, this._textarea.selectionStart).split("\n").length - 1
];
const lineVal =
value.split("\n")[
value.slice(0, this._textarea.selectionStart).split("\n").length - 1
];
return { start, end, value: selVal, pre, post, lineVal };
} else {
return { start, end, value: selVal, pre, post };

View File

@ -81,9 +81,8 @@ Badge.reopenClass({
if ("badge_groupings" in json) {
json.badge_groupings.forEach(
(badgeGroupingJson) =>
(badgeGroupings[badgeGroupingJson.id] = BadgeGrouping.create(
badgeGroupingJson
))
(badgeGroupings[badgeGroupingJson.id] =
BadgeGrouping.create(badgeGroupingJson))
);
}

View File

@ -221,8 +221,8 @@ const Category = RestModel.extend({
custom_fields: this.custom_fields,
topic_template: this.topic_template,
all_topics_wiki: this.all_topics_wiki,
allow_unlimited_owner_edits_on_first_post: this
.allow_unlimited_owner_edits_on_first_post,
allow_unlimited_owner_edits_on_first_post:
this.allow_unlimited_owner_edits_on_first_post,
allowed_tags: this.allowed_tags,
allowed_tag_groups: this.allowed_tag_groups,
allow_global_tags: this.allow_global_tags,

View File

@ -258,8 +258,8 @@ const Group = RestModel.extend({
default_notification_level: this.default_notification_level,
membership_request_template: this.membership_request_template,
publish_read_state: this.publish_read_state,
allow_unknown_sender_topic_replies: this
.allow_unknown_sender_topic_replies,
allow_unknown_sender_topic_replies:
this.allow_unknown_sender_topic_replies,
};
["muted", "regular", "watching", "tracking", "watching_first_post"].forEach(

View File

@ -26,15 +26,12 @@ export default {
const site = Site.current();
site.get("filters").forEach((filter) => {
const filterCapitalized = capitalize(filter);
app[
`Discovery${filterCapitalized}Controller`
] = DiscoverySortableController.extend();
app[
`Discovery${filterCapitalized}CategoryController`
] = DiscoverySortableController.extend();
app[
`Discovery${filterCapitalized}CategoryNoneController`
] = DiscoverySortableController.extend();
app[`Discovery${filterCapitalized}Controller`] =
DiscoverySortableController.extend();
app[`Discovery${filterCapitalized}CategoryController`] =
DiscoverySortableController.extend();
app[`Discovery${filterCapitalized}CategoryNoneController`] =
DiscoverySortableController.extend();
if (filter === "top") {
app.DiscoveryTopRoute = buildTopicRoute("top", {
@ -50,12 +47,10 @@ export default {
app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter);
}
app[`Discovery${filterCapitalized}CategoryRoute`] = buildCategoryRoute(
filter
);
app[
`Discovery${filterCapitalized}CategoryNoneRoute`
] = buildCategoryRoute(filter, { no_subcategories: true });
app[`Discovery${filterCapitalized}CategoryRoute`] =
buildCategoryRoute(filter);
app[`Discovery${filterCapitalized}CategoryNoneRoute`] =
buildCategoryRoute(filter, { no_subcategories: true });
});
app["TagsShowCategoryRoute"] = TagShowRoute.extend();
@ -70,15 +65,12 @@ export default {
app["TagShow" + capitalize(filter) + "Route"] = TagShowRoute.extend({
navMode: filter,
});
app[
"TagsShowCategory" + capitalize(filter) + "Route"
] = TagShowRoute.extend({ navMode: filter });
app[
"TagsShowCategoryNone" + capitalize(filter) + "Route"
] = TagShowRoute.extend({ navMode: filter, noSubcategories: true });
app[
"TagsShowCategoryAll" + capitalize(filter) + "Route"
] = TagShowRoute.extend({ navMode: filter, noSubcategories: false });
app["TagsShowCategory" + capitalize(filter) + "Route"] =
TagShowRoute.extend({ navMode: filter });
app["TagsShowCategoryNone" + capitalize(filter) + "Route"] =
TagShowRoute.extend({ navMode: filter, noSubcategories: true });
app["TagsShowCategoryAll" + capitalize(filter) + "Route"] =
TagShowRoute.extend({ navMode: filter, noSubcategories: false });
});
},
};

View File

@ -48,9 +48,8 @@ export default {
caps.isiOSPWA = caps.isPwa && caps.isIOS;
caps.wasLaunchedFromDiscourseHub = window.location.search.includes(
"discourse_app=1"
);
caps.wasLaunchedFromDiscourseHub =
window.location.search.includes("discourse_app=1");
caps.isAppWebview = window.ReactNativeWebView !== undefined;
// Inject it

View File

@ -1,9 +1,8 @@
import Route from "@ember/routing/route";
export default Route.extend({
setupController(controller) {
const accountCreated = this.controllerFor("account-created").get(
"accountCreated"
);
const accountCreated =
this.controllerFor("account-created").get("accountCreated");
controller.set("accountCreated", accountCreated);
controller.set("newEmail", accountCreated.email);
},

View File

@ -6,9 +6,8 @@ const ForgotPasswordRoute = buildStaticRoute("password-reset");
ForgotPasswordRoute.reopen({
beforeModel() {
const loginRequired = this.controllerFor("application").get(
"loginRequired"
);
const loginRequired =
this.controllerFor("application").get("loginRequired");
this.replaceWith(
loginRequired ? "login" : `discovery.${defaultHomepage()}`
).then((e) => {

View File

@ -73,18 +73,23 @@ export default class MediaOptimizationWorkerService extends Service {
width: imageData.width,
height: imageData.height,
settings: {
resize_threshold: this.siteSettings
.composer_media_optimization_image_resize_dimensions_threshold,
resize_target: this.siteSettings
.composer_media_optimization_image_resize_width_target,
resize_pre_multiply: this.siteSettings
.composer_media_optimization_image_resize_pre_multiply,
resize_linear_rgb: this.siteSettings
.composer_media_optimization_image_resize_linear_rgb,
encode_quality: this.siteSettings
.composer_media_optimization_image_encode_quality,
debug_mode: this.siteSettings
.composer_media_optimization_debug_mode,
resize_threshold:
this.siteSettings
.composer_media_optimization_image_resize_dimensions_threshold,
resize_target:
this.siteSettings
.composer_media_optimization_image_resize_width_target,
resize_pre_multiply:
this.siteSettings
.composer_media_optimization_image_resize_pre_multiply,
resize_linear_rgb:
this.siteSettings
.composer_media_optimization_image_resize_linear_rgb,
encode_quality:
this.siteSettings
.composer_media_optimization_image_encode_quality,
debug_mode:
this.siteSettings.composer_media_optimization_debug_mode,
},
},
[imageData.data.buffer]

View File

@ -293,9 +293,8 @@ export default class PresenceService extends Service {
_getInitialData(channelName) {
let promiseProxy = this._initialDataRequests[channelName];
if (!promiseProxy) {
promiseProxy = this._initialDataRequests[
channelName
] = createPromiseProxy();
promiseProxy = this._initialDataRequests[channelName] =
createPromiseProxy();
}
once(this, this._makeInitialDataRequest);

View File

@ -13,7 +13,7 @@
<tbody class="topic-list-body">
{{#each this.content as |bookmark|}}
<tr class="topic-list-item bookmark-list-item">
<td class="main-link topic-list-data" role="rowheader">
<th scope="row" class="main-link topic-list-data">
<span class="link-top-line">
<div class="bookmark-metadata">
{{#if bookmark.reminder_at}}
@ -58,7 +58,7 @@
{{/if}}
{{!-- template-lint-disable --}}
<p class="post-excerpt" {{on "click" this.screenExcerptForExternalLink}}>{{html-safe bookmark.excerpt}}</p>
</td>
</th>
{{#unless this.site.mobileView}}
<td class="topic-list-data">
{{#if bookmark.user.avatar_template}}

View File

@ -8,7 +8,7 @@
{{/if}}
<div class="control-group bookmark-name-wrap">
<Input @id="bookmark-name" @value={{this.model.name}} @name="bookmark-name" class="bookmark-name" @enter={{action "saveAndClose"}} placeholder={{i18n "post.bookmarks.name_placeholder"}} @maxlength="100" />
<Input id="bookmark-name" @value={{this.model.name}} name="bookmark-name" class="bookmark-name" @enter={{action "saveAndClose"}} placeholder={{i18n "post.bookmarks.name_placeholder"}} maxlength="100" />
<DButton @icon="cog" @action={{action "toggleShowOptions"}} @class="bookmark-options-button" @ariaLabel="post.bookmarks.options" />
</div>

View File

@ -17,7 +17,7 @@
{{#each this.topics as |t|}}
<div class="controls existing-topic">
<label class="radio">
<Input @id={{concat "choose-topic-" t.id}} @checked={{eq t.id this.selectedTopicId}} @click={{action "chooseTopic" t}} @type="radio" @name="choose_topic_id" />
<Input id={{concat "choose-topic-" t.id}} @checked={{eq t.id this.selectedTopicId}} @type="radio" name="choose_topic_id" {{on "click" (action "chooseTopic" t)}} />
<TopicStatus @topic={{t}} @disableActions={{true}} />
<span class="topic-title">
{{replace-emoji t.fancy_title}}

View File

@ -1,4 +1,4 @@
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{readonly this.value}} @input={{action "onChangeDate"}} @id={{this.inputId}} />
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{readonly this.value}} id={{this.inputId}} {{on "input" (action "onChangeDate")}} />
{{#unless this.useGlobalPickerContainer}}
<div class="picker-container"></div>

View File

@ -1 +1 @@
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{this.value}} @autocomplete="off" />
<Input @type={{this.inputType}} class="date-picker" placeholder={{this.placeholder}} @value={{this.value}} autocomplete="off" />

View File

@ -13,7 +13,7 @@
<section class="field allow-global-tags">
<label>
<Input @type="checkbox" @checked={{this.category.allow_global_tags}} @id="allow_global_tags" @disabled={{this.disableAllowGlobalTags}} />
<Input @type="checkbox" @checked={{this.category.allow_global_tags}} id="allow_global_tags" disabled={{this.disableAllowGlobalTags}} />
{{i18n "category.allow_global_tags_label"}}
</label>
</section>

View File

@ -1,7 +1,7 @@
{{#if this.isActive}}
{{!-- template-lint-disable no-invalid-interactive --}}
{{!-- template-lint-disable no-invalid-interactive no-down-event-binding --}}
<div {{on "keydown" (action "keydown")}} class="emoji-picker {{if this.isActive "opened"}}">
{{!-- template-lint-enable no-invalid-interactive --}}
{{!-- template-lint-enable no-invalid-interactive no-down-event-binding --}}
<div class="emoji-picker-category-buttons">
{{#if this.recentEmojis.length}}
<button type="button" data-section="recent" {{action "onCategorySelection" "recent"}} class="btn btn-default category-button emoji">
@ -20,7 +20,7 @@
<div class="emoji-picker-content">
<div class="emoji-picker-search-container">
<Input class="filter" @name="filter" @value={{@initialFilter}} placeholder={{i18n "emoji_picker.filter_placeholder"}} @autocomplete="off" @type="search" @autocorrect="off" @autocapitalize="off" @input={{action "onFilterChange"}} />
<Input class="filter" name="filter" @value={{@initialFilter}} placeholder={{i18n "emoji_picker.filter_placeholder"}} autocomplete="off" @type="search" autocorrect="off" autocapitalize="off" {{on "input" (action "onFilterChange")}} />
{{d-icon "search"}}
</div>

View File

@ -4,7 +4,7 @@
{{i18n "admin.emoji.name"}}
</span>
<div class="input">
<Input @id="emoji-name" @name="name" @placeholderKey="admin.emoji.name" @value={{readonly this.name}} @input={{action (mut this.name) value="target.value"}} />
<Input id="emoji-name" name="name" placeholder={{i18n "admin.emoji.name"}} @value={{readonly this.name}} {{on "input" (action (mut this.name) value="target.value")}} />
</div>
</div>
<div class="control-group">

View File

@ -7,7 +7,7 @@
<div class="flag-action-type-details">
<span class="description">{{html-safe this.flag.description}}</span>
{{#if this.showMessageInput}}
<Textarea @name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
<Textarea name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
{{/if}}
</div>
</label>
@ -26,7 +26,7 @@
<div class="description">{{html-safe this.description}}</div>
{{/if}}
{{#if this.showMessageInput}}
<Textarea @name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
<Textarea name="message" class="flag-message" placeholder={{this.customPlaceholder}} @value={{this.message}} /> <div class="custom-message-length {{this.customMessageLengthClasses}}">{{this.customMessageLength}}</div>
{{/if}}
</div>
</label>

View File

@ -16,7 +16,7 @@
<div class="control-group future-date-input-time-picker">
{{d-icon "far-clock"}}
<Input placeholder="--:--" @type="time" class="time-input" @value={{this._time}} @disabled={{this.timeInputDisabled}} @input={{action "onChangeTime" value="target.value"}} />
<Input placeholder="--:--" @type="time" class="time-input" @value={{this._time}} disabled={{this.timeInputDisabled}} {{on "input" (action "onChangeTime" value="target.value")}} />
</div>
{{/if}}
</div>

View File

@ -3,11 +3,11 @@
<div>
<div class="control-group">
<label for="imap_server">{{i18n "groups.manage.email.credentials.imap_server"}}</label>
<Input @type="text" @name="imap_server" @value={{this.form.imap_server}} @tabindex="8" @onChange={{action "resetSettingsValid"}} />
<Input @type="text" name="imap_server" @value={{this.form.imap_server}} tabindex="8" {{on "change" (action "resetSettingsValid")}} />
</div>
<label for="enable_ssl_imap">
<Input @type="checkbox" @checked={{this.form.imap_ssl}} @id="enable_ssl_imap" @tabindex="11" @onChange={{action "resetSettingsValid"}} />
<Input @type="checkbox" @checked={{this.form.imap_ssl}} id="enable_ssl_imap" tabindex="11" {{on "change" (action "resetSettingsValid")}} />
{{i18n "groups.manage.email.credentials.imap_ssl"}}
</label>
</div>
@ -15,7 +15,7 @@
<div>
<div class="control-group">
<label for="imap_port">{{i18n "groups.manage.email.credentials.imap_port"}}</label>
<Input @type="text" @name="imap_port" @value={{this.form.imap_port}} @tabindex="9" @onChange={{action "resetSettingsValid" this.form.imap_port}} />
<Input @type="text" name="imap_port" @value={{this.form.imap_port}} tabindex="9" {{on "change" (action "resetSettingsValid" this.form.imap_port)}} />
</div>
</div>

View File

@ -3,7 +3,7 @@
<p>{{i18n "groups.manage.email.smtp_instructions"}}</p>
<label for="enable_smtp">
<Input @type="checkbox" @checked={{this.group.smtp_enabled}} @id="enable_smtp" @change={{action "smtpEnabledChange"}} @tabindex="1" />
<Input @type="checkbox" @checked={{this.group.smtp_enabled}} id="enable_smtp" tabindex="1" {{on "change" (action "smtpEnabledChange")}} />
{{i18n "groups.manage.email.enable_smtp"}}
</label>
@ -23,7 +23,7 @@
<div class="alert alert-warning">{{i18n "groups.manage.email.imap_alpha_warning"}}</div>
<label for="enable_imap">
<Input @type="checkbox" @disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} @id="enable_imap" @change={{action "imapEnabledChange"}} @tabindex="8" />
<Input @type="checkbox" disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} id="enable_imap" tabindex="8" {{on "change" (action "imapEnabledChange")}} />
{{i18n "groups.manage.email.enable_imap"}}
</label>
@ -37,7 +37,7 @@
<div class="control-group">
<h3>{{i18n "groups.manage.email.imap_additional_settings"}}</h3>
<label class="control-group-inline" for="allow_unknown_sender_topic_replies">
<Input @type="checkbox" @name="allow_unknown_sender_topic_replies" @id="allow_unknown_sender_topic_replies" @checked={{this.group.allow_unknown_sender_topic_replies}} @tabindex="13" />
<Input @type="checkbox" name="allow_unknown_sender_topic_replies" id="allow_unknown_sender_topic_replies" @checked={{this.group.allow_unknown_sender_topic_replies}} tabindex="13" />
<span>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies"}}</span>
</label>
<p>{{i18n "groups.manage.email.settings.allow_unknown_sender_topic_replies_hint"}}</p>

View File

@ -13,7 +13,7 @@
{{#each this.tabs as |tab|}}
<li>
<LinkTo @route={{tab.route}} @model={{this.group}} @title={{tab.message}} class={{tab.name}}>
<LinkTo @route={{tab.route}} @model={{this.group}} title={{tab.message}} class={{tab.name}}>
{{#if tab.icon}}{{d-icon tab.icon}}{{/if}}
{{tab.message}}
{{#if tab.count}}<span class="count">({{tab.count}})</span>{{/if}}

View File

@ -3,16 +3,16 @@
<div>
<div class="control-group">
<label for="username">{{i18n "groups.manage.email.credentials.username"}}</label>
<Input @type="text" @name="username" @value={{this.form.email_username}} @tabindex="1" @onChange={{action "resetSettingsValid"}} />
<Input @type="text" name="username" @value={{this.form.email_username}} tabindex="1" {{on "change" (action "resetSettingsValid")}} />
</div>
<div class="control-group">
<label for="smtp_server">{{i18n "groups.manage.email.credentials.smtp_server"}}</label>
<Input @type="text" @name="smtp_server" @value={{this.form.smtp_server}} @tabindex="4" @onChange={{action "resetSettingsValid"}} />
<Input @type="text" name="smtp_server" @value={{this.form.smtp_server}} tabindex="4" {{on "change" (action "resetSettingsValid")}} />
</div>
<label for="enable_ssl">
<Input @type="checkbox" @checked={{this.form.smtp_ssl}} @id="enable_ssl" @tabindex="6" @onChange={{action "resetSettingsValid"}} />
<Input @type="checkbox" @checked={{this.form.smtp_ssl}} id="enable_ssl" tabindex="6" {{on "change" (action "resetSettingsValid")}} />
{{i18n "groups.manage.email.credentials.smtp_ssl"}}
</label>
</div>
@ -20,19 +20,19 @@
<div>
<div class="control-group">
<label for="password">{{i18n "groups.manage.email.credentials.password"}}</label>
<Input @type="password" @name="password" @value={{this.form.email_password}} @tabindex="2" @onChange={{action "resetSettingsValid"}} />
<Input @type="password" name="password" @value={{this.form.email_password}} tabindex="2" {{on "change" (action "resetSettingsValid")}} />
</div>
<div class="control-group">
<label for="smtp_port">{{i18n "groups.manage.email.credentials.smtp_port"}}</label>
<Input @type="text" @name="smtp_port" @value={{this.form.smtp_port}} @tabindex="5" @onChange={{action "resetSettingsValid" this.form.smtp_port}} />
<Input @type="text" name="smtp_port" @value={{this.form.smtp_port}} tabindex="5" {{on "change" (action "resetSettingsValid" this.form.smtp_port)}} />
</div>
</div>
<div>
<div class="control-group">
<label for="from_alias">{{i18n "groups.manage.email.settings.from_alias"}}</label>
<Input @type="text" @name="from_alias" @id="from_alias" @value={{this.form.email_from_alias}} @onChange={{action "resetSettingsValid"}} @tabindex="3" />
<Input @type="text" name="from_alias" id="from_alias" @value={{this.form.email_from_alias}} {{on "change" (action "resetSettingsValid")}} tabindex="3" />
<p>{{i18n "groups.manage.email.settings.from_alias_hint"}}</p>
</div>
</div>

View File

@ -2,7 +2,7 @@
<label class="control-label">{{i18n "groups.manage.membership.access"}}</label>
<label>
<Input @type="checkbox" class="group-form-public-admission" @checked={{this.model.public_admission}} @disabled={{this.disablePublicSetting}} />
<Input @type="checkbox" class="group-form-public-admission" @checked={{this.model.public_admission}} disabled={{this.disablePublicSetting}} />
{{i18n "groups.public_admission"}}
</label>
@ -14,7 +14,7 @@
</label>
<label>
<Input @type="checkbox" class="group-form-allow-membership-requests" @checked={{this.model.allow_membership_requests}} @disabled={{this.disableMembershipRequestSetting}} />
<Input @type="checkbox" class="group-form-allow-membership-requests" @checked={{this.model.allow_membership_requests}} disabled={{this.disableMembershipRequestSetting}} />
{{i18n "groups.allow_membership_requests"}}
</label>
@ -68,7 +68,7 @@
{{i18n "admin.groups.default_title"}}
</label>
<Input @value={{this.model.title}} @name="title" class="input-xxlarge" />
<Input @value={{this.model.title}} name="title" class="input-xxlarge" />
<div class="control-instructions">
{{i18n "admin.groups.default_title_description"}}

View File

@ -1,4 +1,4 @@
<label class="checkbox-label">
<Input @type="checkbox" @disabled={{this.disabled}} @checked={{this.checked}} />
<Input @type="checkbox" disabled={{this.disabled}} @checked={{this.checked}} />
{{this.label}}
</label>

View File

@ -29,7 +29,7 @@
{{#if this.siteSettings.enable_fast_edit}}
{{#if this._displayFastEditInput}}
<div class="fast-edit-container">
<Textarea @id="fast-edit-input" @value={{this._fastEditNewSelection}} /> <DButton @action={{action "_saveFastEdit"}} @class="btn-small btn-primary save-fast-edit" @icon="pencil-alt" @label="composer.save_edit" @translatedTitle={{this._saveEditButtonTitle}} @disabled={{this._saveFastEditDisabled}} @isLoading={{this._isSavingFastEdit}} />
<Textarea id="fast-edit-input" @value={{this._fastEditNewSelection}} /> <DButton @action={{action "_saveFastEdit"}} @class="btn-small btn-primary save-fast-edit" @icon="pencil-alt" @label="composer.save_edit" @translatedTitle={{this._saveEditButtonTitle}} @disabled={{this._saveFastEditDisabled}} @isLoading={{this._isSavingFastEdit}} />
</div>
{{/if}}
{{/if}}

View File

@ -1,4 +1,4 @@
<div class="relative-time-picker">
<Input class="relative-time-duration" @min={{this.durationMin}} @step={{this.durationStep}} @type="number" @value={{this.duration}} @onChange={{action "onChangeDuration"}} @id={{this.id}} />
<Input class="relative-time-duration" min={{this.durationMin}} step={{this.durationStep}} @type="number" @value={{this.duration}} {{on "change" (action "onChangeDuration")}} id={{this.id}} />
<ComboBox @content={{this.intervals}} @value={{this.selectedInterval}} @class="relative-time-intervals" @onChange={{action "onChangeInterval"}} />
</div>

View File

@ -1 +1 @@
<Input @value={{this.value}} @change={{this.valueChanged}} class="reviewable-input-text" />
<Input @value={{this.value}} class="reviewable-input-text" {{on "change" this.valueChanged}} />

View File

@ -1 +1 @@
<Textarea @value={{this.value}} @change={{this.valueChanged}} class="reviewable-input-textarea" />
<Textarea @value={{this.value}} {{on "change" this.valueChanged}} class="reviewable-input-textarea" />

View File

@ -23,7 +23,7 @@
{{#if this.showAllTagsCheckbox}}
<section class="field">
<label>
<Input @type="checkbox" class="all-tags" @checked={{this.searchedTerms.special.all_tags}} @click={{action "onChangeSearchTermForAllTags" value="target.checked"}} />
<Input @type="checkbox" class="all-tags" @checked={{this.searchedTerms.special.all_tags}} {{on "click" (action "onChangeSearchTermForAllTags" value="target.checked")}} />
{{i18n "search.advanced.filters.all_tags"}}
</label>
</section>
@ -39,24 +39,24 @@
{{#if this.currentUser}}
<div class="grouped-control-field">
<Input @id="matching-title-only" @type="checkbox" class="in-title" @checked={{this.searchedTerms.special.in.title}} @click={{action "onChangeSearchTermForSpecialInTitle" value="target.checked"}} />
<Input id="matching-title-only" @type="checkbox" class="in-title" @checked={{this.searchedTerms.special.in.title}} {{on "click" (action "onChangeSearchTermForSpecialInTitle" value="target.checked")}} />
<label for="matching-title-only">
{{i18n "search.advanced.filters.title"}}
</label>
</div>
<div class="grouped-control-field">
<Input @id="matching-liked" @type="checkbox" class="in-likes" @checked={{this.searchedTerms.special.in.likes}} @click={{action "onChangeSearchTermForSpecialInLikes" value="target.checked"}} />
<Input id="matching-liked" @type="checkbox" class="in-likes" @checked={{this.searchedTerms.special.in.likes}} {{on "click" (action "onChangeSearchTermForSpecialInLikes" value="target.checked")}} />
<label for="matching-liked">{{i18n "search.advanced.filters.likes"}}</label>
</div>
<div class="grouped-control-field">
<Input @id="matching-in-messages" @type="checkbox" class="in-private" @checked={{this.searchedTerms.special.in.messages}} @click={{action "onChangeSearchTermForSpecialInMessages" value="target.checked"}} />
<Input id="matching-in-messages" @type="checkbox" class="in-private" @checked={{this.searchedTerms.special.in.messages}} {{on "click" (action "onChangeSearchTermForSpecialInMessages" value="target.checked")}} />
<label for="matching-in-messages">{{i18n "search.advanced.filters.private"}}</label>
</div>
<div class="grouped-control-field">
<Input @id="matching-seen" @type="checkbox" class="in-seen" @checked={{this.searchedTerms.special.in.seen}} @click={{action "onChangeSearchTermForSpecialInSeen" value="target.checked"}} />
<Input id="matching-seen" @type="checkbox" class="in-seen" @checked={{this.searchedTerms.special.in.seen}} {{on "click" (action "onChangeSearchTermForSpecialInSeen" value="target.checked")}} />
<label for="matching-seen">{{i18n "search.advanced.filters.seen"}}</label>
</div>
{{/if}}
@ -114,9 +114,9 @@
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
<span class="control-label">{{i18n "search.advanced.post.count.label"}}</span>
<div class="controls">
<Input @type="number" @value={{readonly this.searchedTerms.min_posts}} class="input-small" @id="search-min-post-count" @input={{action "onChangeSearchTermMinPostCount" value="target.value"}} placeholder={{i18n "search.advanced.post.min.placeholder"}} @aria-label={{i18n "search.advanced.post.min.aria_label"}} />
<Input @type="number" @value={{readonly this.searchedTerms.min_posts}} class="input-small" id="search-min-post-count" placeholder={{i18n "search.advanced.post.min.placeholder"}} aria-label={{i18n "search.advanced.post.min.aria_label"}} {{on "input" (action "onChangeSearchTermMinPostCount" value="target.value")}} />
{{d-icon "arrows-alt-h"}}
<Input @type="number" @value={{readonly this.searchedTerms.max_posts}} class="input-small" @id="search-max-post-count" @input={{action "onChangeSearchTermMaxPostCount" value="target.value"}} placeholder={{i18n "search.advanced.post.max.placeholder"}} @aria-label={{i18n "search.advanced.post.max.aria_label"}} />
<Input @type="number" @value={{readonly this.searchedTerms.max_posts}} class="input-small" id="search-max-post-count" placeholder={{i18n "search.advanced.post.max.placeholder"}} aria-label={{i18n "search.advanced.post.max.aria_label"}} {{on "input" (action "onChangeSearchTermMaxPostCount" value="target.value")}} />
</div>
</div>
@ -124,9 +124,9 @@
{{!-- TODO: Using a label here fails no-nested-interactive lint rule --}}
<span class="control-label">{{i18n "search.advanced.views.label"}}</span>
<div class="controls">
<Input @type="number" @value={{readonly this.searchedTerms.min_views}} class="input-small" @id="search-min-views" @input={{action "onChangeSearchTermMinViews" value="target.value"}} placeholder={{i18n "search.advanced.min_views.placeholder"}} @aria-label={{i18n "search.advanced.min_views.aria_label"}} />
<Input @type="number" @value={{readonly this.searchedTerms.min_views}} class="input-small" id="search-min-views" placeholder={{i18n "search.advanced.min_views.placeholder"}} aria-label={{i18n "search.advanced.min_views.aria_label"}} {{on "input" (action "onChangeSearchTermMinViews" value="target.value")}} />
{{d-icon "arrows-alt-h"}}
<Input @type="number" @value={{readonly this.searchedTerms.max_views}} class="input-small" @id="search-max-views" @input={{action "onChangeSearchTermMaxViews" value="target.value"}} placeholder={{i18n "search.advanced.max_views.placeholder"}} @aria-label={{i18n "search.advanced.max_views.aria_label"}} />
<Input @type="number" @value={{readonly this.searchedTerms.max_views}} class="input-small" id="search-max-views" placeholder={{i18n "search.advanced.max_views.placeholder"}} aria-label={{i18n "search.advanced.max_views.aria_label"}} {{on "input" (action "onChangeSearchTermMaxViews" value="target.value")}} />
</div>
</div>
</details>

View File

@ -8,7 +8,7 @@
@route={{@headerRoute}}
@query={{@headerQuery}}
@models={{if @headerModel (array @headerModel) (if @headerModels @headerModels (array))}}
@class="sidebar-section-header-link"
class="sidebar-section-header-link"
title={{@headerLinkTitle}}>
{{@headerLinkText}}

View File

@ -25,7 +25,7 @@
<section class="group-one-per-topic">
<label>
<Input @type="checkbox" @checked={{this.buffered.one_per_topic}} @name="onepertopic" />
<Input @type="checkbox" @checked={{this.buffered.one_per_topic}} name="onepertopic" />
{{i18n "tagging.groups.one_per_topic_label"}}
</label>
</section>

View File

@ -16,7 +16,7 @@
</div>
<div class="tap-tile-time-input">
{{d-icon "far-clock"}}
<Input placeholder="--:--" @id="custom-time" @type="time" class="time-input" @value={{this.customTime}} />
<Input placeholder="--:--" id="custom-time" @type="time" class="time-input" @value={{this.customTime}} />
</div>
</div>
<div class="control-group custom-date-time-wrap custom-relative-wrap">

View File

@ -6,7 +6,7 @@
<div class="controls">
<label class="control-label checkbox-label">
<Input @id={{concat "user-" this.elementId}} @checked={{this.value}} @type="checkbox" />
<Input id={{concat "user-" this.elementId}} @checked={{this.value}} @type="checkbox" />
<span>
{{html-safe this.field.description}} {{#unless this.field.name}}{{#if this.field.required}}<span class="required">*</span>{{/if}}{{/unless}}
</span>

View File

@ -3,6 +3,6 @@
{{#if this.field.required}}<span class="required">*</span>{{/if}}
</label>
<div class="controls">
<Input @id={{concat "user-" this.elementId}} @value={{this.value}} @maxlength={{this.site.user_field_max_length}} />
<Input id={{concat "user-" this.elementId}} @value={{this.value}} maxlength={{this.site.user_field_max_length}} />
<div class="instructions">{{html-safe this.field.description}}</div>
</div>

View File

@ -23,7 +23,7 @@
{{#if this.context}}
<div class="search-context">
<label>
<Input @type="checkbox" @name="searchContext" @checked={{this.searchContextEnabled}} /> {{this.searchContextDescription}}
<Input @type="checkbox" name="searchContext" @checked={{this.searchContextEnabled}} /> {{this.searchContextDescription}}
</label>
</div>
{{/if}}

View File

@ -50,7 +50,7 @@
<tr>
{{#if this.isBulk}}
<td class="bulk-select">
<Input @type="checkbox" class="bulk-select" @click={{action "selectMember" m}} />
<Input @type="checkbox" class="bulk-select" {{on "click" (action "selectMember" m)}} />
</td>
{{/if}}

View File

@ -7,7 +7,7 @@
{{/if}}
<div class="groups-header-filters">
<Input @value={{readonly this.filter}} @placeholderKey="groups.index.all" class="groups-header-filters-name no-blur" @input={{action "onFilterChanged" value="target.value"}} />
<Input @value={{readonly this.filter}} placeholder={{i18n "groups.index.all"}} class="groups-header-filters-name no-blur" {{on "input" (action "onFilterChanged" value="target.value")}} />
<ComboBox @value={{this.type}} @content={{this.types}} @class="groups-header-filters-type" @onChange={{action (mut this.type)}} @options={{hash
clearable=true
@ -22,7 +22,7 @@
<div class="container">
<div class="groups-boxes">
{{#each this.groups as |group|}}
<LinkTo @route="group.members" @model={{group.name}} @classNames={{concat "group-box " group.name}}>
<LinkTo @route="group.members" @model={{group.name}} class={{concat "group-box " group.name}}>
<div class="group-box-inner">
<div class="group-info-wrapper">
{{#if group.flair_url}}

Some files were not shown because too many files have changed in this diff Show More