DEV: [gjs-codemod] Convert automation/styleguide/other to gjs

Co-authored-by: Jarek Radosz <jarek@cvx.dev>
This commit is contained in:
David Taylor
2025-04-14 15:36:16 +01:00
parent 3462113bd4
commit 7b2b08cf89
144 changed files with 4859 additions and 3715 deletions

View File

@ -794,3 +794,7 @@ export function isPrimaryTab() {
}
});
}
export function optionalRequire(path, name = "default") {
return require.has(path) && require(path)[name];
}

View File

@ -1,31 +1,36 @@
import Component from "@ember/component";
import Component, { Input } from "@ember/component";
import { hash } from "@ember/helper";
import { tagName } from "@ember-decorators/component";
import PluginOutlet from "discourse/components/plugin-outlet";
import icon from "discourse/helpers/d-icon";
@tagName("")
export default class Checkbox extends Component {}
export default class Checkbox extends Component {
<template>
<label class="wizard-container__label">
<PluginOutlet
@name="wizard-checkbox"
@outletArgs={{hash disabled=this.field.disabled}}
>
<Input
@type="checkbox"
disabled={{this.field.disabled}}
class="wizard-container__checkbox"
@checked={{this.field.value}}
/>
<span class="wizard-container__checkbox-slider"></span>
{{#if this.field.icon}}
{{icon this.field.icon}}
{{/if}}
<span class="wizard-container__checkbox-label">
{{this.field.placeholder}}
</span>
</PluginOutlet>
<label class="wizard-container__label">
<PluginOutlet
@name="wizard-checkbox"
@outletArgs={{hash disabled=this.field.disabled}}
>
<Input
@type="checkbox"
disabled={{this.field.disabled}}
class="wizard-container__checkbox"
@checked={{this.field.value}}
/>
<span class="wizard-container__checkbox-slider"></span>
{{#if this.field.icon}}
{{d-icon this.field.icon}}
{{/if}}
<span class="wizard-container__checkbox-label">
{{this.field.placeholder}}
</span>
</PluginOutlet>
<PluginOutlet
@name="below-wizard-checkbox"
@outletArgs={{hash disabled=this.field.disabled}}
/>
</label>
<PluginOutlet
@name="below-wizard-checkbox"
@outletArgs={{hash disabled=this.field.disabled}}
/>
</label>
</template>
}

View File

@ -1,5 +1,7 @@
import Component from "@ember/component";
import Component, { Input } from "@ember/component";
import { on } from "@ember/modifier";
import { action, set } from "@ember/object";
import icon from "discourse/helpers/d-icon";
export default class Checkboxes extends Component {
init(...args) {
@ -30,21 +32,23 @@ export default class Checkboxes extends Component {
}
this.set("field.value", newFieldValue);
}
}
{{#each this.field.choices as |c|}}
<div class="checkbox-field-choice {{this.fieldClass}}">
<label id={{c.id}} value={{c.label}}>
<Input
@type="checkbox"
class="wizard-container__checkbox"
@checked={{c.checked}}
{{on "click" (action "changed")}}
/>
{{#if c.icon}}
{{d-icon c.icon}}
{{/if}}
{{c.label}}
</label>
</div>
{{/each}}
<template>
{{#each this.field.choices as |c|}}
<div class="checkbox-field-choice {{this.fieldClass}}">
<label id={{c.id}} value={{c.label}}>
<Input
@type="checkbox"
class="wizard-container__checkbox"
@checked={{c.checked}}
{{on "click" (action "changed")}}
/>
{{#if c.icon}}
{{icon c.icon}}
{{/if}}
{{c.label}}
</label>
</div>
{{/each}}
</template>
}

View File

@ -2,6 +2,8 @@ import Component from "@ember/component";
import { classNameBindings } from "@ember-decorators/component";
@classNameBindings(":wizard-image-preview", "fieldClass")
export default class Generic extends Component {}
<img src={{this.field.value}} class={{this.fieldClass}} />
export default class Generic extends Component {
<template>
<img src={{this.field.value}} class={{this.fieldClass}} />
</template>
}

View File

@ -446,6 +446,17 @@ export default class PreviewBase extends Component {
unreadTextX + ctx.measureText(unreadText).width + headerMargin * 2.0;
ctx.fillText(topText, topTextX, pillButtonTextY);
}
<template>
<div class="wizard-container__preview">
<canvas
width={{this.elementWidth}}
height={{this.elementHeight}}
style={{this.canvasStyle}}
>
</canvas>
</div>
</template>
}
function loadImage(src) {
@ -457,12 +468,3 @@ function loadImage(src) {
img.src = getUrl(src);
return new Promise((resolve) => (img.onload = () => resolve(img)));
}
<div class="wizard-container__preview">
<canvas
width={{this.elementWidth}}
height={{this.elementHeight}}
style={{this.canvasStyle}}
>
</canvas>
</div>

View File

@ -1,3 +1,4 @@
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { observes } from "@ember-decorators/object";
import { bind } from "discourse/lib/decorators";
@ -247,35 +248,37 @@ export default class Index extends PreviewBaseComponent {
event?.preventDefault();
this.set("previewTopic", true);
}
<template>
<div class="previews {{if this.draggingActive 'dragging'}}">
<div class="wizard-container__preview topic-preview">
<canvas
width={{this.elementWidth}}
height={{this.elementHeight}}
style={{this.canvasStyle}}
>
</canvas>
</div>
<div class="wizard-container__preview homepage-preview">
<this.HomepagePreview @wizard={{this.wizard}} @step={{this.step}} />
</div>
</div>
<div class="preview-nav">
<a
href
class="preview-nav-button {{if this.previewTopic 'active'}}"
{{on "click" this.setPreviewTopic}}
>
{{i18n "wizard.previews.topic_preview"}}
</a>
<a
href
class="preview-nav-button {{unless this.previewTopic 'active'}}"
{{on "click" this.setPreviewHomepage}}
>
{{i18n "wizard.previews.homepage_preview"}}
</a>
</div>
</template>
}
<div class="previews {{if this.draggingActive 'dragging'}}">
<div class="wizard-container__preview topic-preview">
<canvas
width={{this.elementWidth}}
height={{this.elementHeight}}
style={{this.canvasStyle}}
>
</canvas>
</div>
<div class="wizard-container__preview homepage-preview">
<this.HomepagePreview @wizard={{this.wizard}} @step={{this.step}} />
</div>
</div>
<div class="preview-nav">
<a
href
class="preview-nav-button {{if this.previewTopic 'active'}}"
{{on "click" this.setPreviewTopic}}
>
{{i18n "wizard.previews.topic_preview"}}
</a>
<a
href
class="preview-nav-button {{unless this.previewTopic 'active'}}"
{{on "click" this.setPreviewHomepage}}
>
{{i18n "wizard.previews.homepage_preview"}}
</a>
</div>

View File

@ -1,11 +1,13 @@
import Component from "@ember/component";
import Component, { Input } from "@ember/component";
export default class Text extends Component {}
<Input
id={{this.field.id}}
@value={{this.field.value}}
class="wizard-container__text-input"
placeholder={{this.field.placeholder}}
tabindex="9"
/>
export default class Text extends Component {
<template>
<Input
id={{this.field.id}}
@value={{this.field.value}}
class="wizard-container__text-input"
placeholder={{this.field.placeholder}}
tabindex="9"
/>
</template>
}

View File

@ -29,14 +29,16 @@ export default class ColorPalettesRow extends SelectKitRowComponent {
return "";
}
}
<template>
<span class="name">
{{this.label}}
</span>
{{#if this.item.colors}}
<div class="palettes" style={{this.backgroundColor}}>
{{this.palettes}}
</div>
{{/if}}
</template>
}
<span class="name">
{{this.label}}
</span>
{{#if this.item.colors}}
<div class="palettes" style={{this.backgroundColor}}>
{{this.palettes}}
</div>
{{/if}}

View File

@ -15,6 +15,8 @@ export default class CreateColorRow extends SelectKitRowComponent {
: `#${color}`;
});
}
}
<span>{{this.label}}</span>
<template>
<span>{{this.label}}</span>
</template>
}

View File

@ -1,24 +1,28 @@
import { readOnly } from "@ember/object/computed";
import { htmlSafe } from "@ember/template";
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("dropdown-select-box-row")
export default class DropdownSelectBoxRow extends SelectKitRowComponent {
@readOnly("item.description") description;
<template>
{{#if this.icons}}
<div class="icons">
<span class="selection-indicator"></span>
{{#each this.icons as |i|}}
{{icon i}}
{{/each}}
</div>
{{/if}}
<div class="texts">
<span class="name">{{htmlSafe this.label}}</span>
{{#if this.description}}
<span class="desc">{{htmlSafe this.description}}</span>
{{/if}}
</div>
</template>
}
{{#if this.icons}}
<div class="icons">
<span class="selection-indicator"></span>
{{#each this.icons as |icon|}}
{{d-icon icon}}
{{/each}}
</div>
{{/if}}
<div class="texts">
<span class="name">{{html-safe this.label}}</span>
{{#if this.description}}
<span class="desc">{{html-safe this.description}}</span>
{{/if}}
</div>

View File

@ -1,26 +1,37 @@
import { classNames } from "@ember-decorators/component";
import { and } from "truth-helpers";
import UserStatusMessage from "discourse/components/user-status-message";
import avatar from "discourse/helpers/avatar";
import icon from "discourse/helpers/d-icon";
import decorateUsernameSelector from "discourse/helpers/decorate-username-selector";
import formatUsername from "discourse/helpers/format-username";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("email-group-user-chooser-row")
export default class EmailGroupUserChooserRow extends SelectKitRowComponent {}
{{#if this.item.isUser}}
{{avatar this.item imageSize="tiny"}}
<div>
<span class="identifier">{{format-username this.item.id}}</span>
<span class="name">{{this.item.name}}</span>
</div>
{{#if (and this.item.showUserStatus this.item.status)}}
<UserStatusMessage @status={{this.item.status}} @showDescription={{true}} />
{{/if}}
{{decorate-username-selector this.item.id}}
{{else if this.item.isGroup}}
{{d-icon "users"}}
<div>
<span class="identifier">{{this.item.id}}</span>
<span class="name">{{this.item.full_name}}</span>
</div>
{{else}}
{{d-icon "envelope"}}
<span class="identifier">{{this.item.id}}</span>
{{/if}}
export default class EmailGroupUserChooserRow extends SelectKitRowComponent {
<template>
{{#if this.item.isUser}}
{{avatar this.item imageSize="tiny"}}
<div>
<span class="identifier">{{formatUsername this.item.id}}</span>
<span class="name">{{this.item.name}}</span>
</div>
{{#if (and this.item.showUserStatus this.item.status)}}
<UserStatusMessage
@status={{this.item.status}}
@showDescription={{true}}
/>
{{/if}}
{{decorateUsernameSelector this.item.id}}
{{else if this.item.isGroup}}
{{icon "users"}}
<div>
<span class="identifier">{{this.item.id}}</span>
<span class="name">{{this.item.full_name}}</span>
</div>
{{else}}
{{icon "envelope"}}
<span class="identifier">{{this.item.id}}</span>
{{/if}}
</template>
}

View File

@ -1,16 +1,19 @@
import { classNames } from "@ember-decorators/component";
import AvatarFlair from "discourse/components/avatar-flair";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("flair-row")
export default class FlairRow extends SelectKitRowComponent {}
export default class FlairRow extends SelectKitRowComponent {
<template>
{{#if this.item.url}}
<AvatarFlair
@flairName={{this.item.name}}
@flairUrl={{this.item.url}}
@flairBgColor={{this.item.bgColor}}
@flairColor={{this.item.color}}
/>
{{/if}}
{{#if this.item.url}}
<AvatarFlair
@flairName={{this.item.name}}
@flairUrl={{this.item.url}}
@flairBgColor={{this.item.bgColor}}
@flairColor={{this.item.color}}
/>
{{/if}}
<span>{{this.label}}</span>
<span>{{this.label}}</span>
</template>
}

View File

@ -1,19 +1,22 @@
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("future-date-input-selector-row")
export default class FutureDateInputSelectorRow extends SelectKitRowComponent {}
export default class FutureDateInputSelectorRow extends SelectKitRowComponent {
<template>
{{#if this.item.icon}}
<div class="future-date-input-selector-icons">
{{icon this.item.icon}}
</div>
{{/if}}
{{#if this.item.icon}}
<div class="future-date-input-selector-icons">
{{d-icon this.item.icon}}
</div>
{{/if}}
<span class="name">{{this.label}}</span>
<span class="name">{{this.label}}</span>
{{#if this.item.timeFormatted}}
<span class="future-date-input-selector-datetime">
{{this.item.timeFormatted}}
</span>
{{/if}}
{{#if this.item.timeFormatted}}
<span class="future-date-input-selector-datetime">
{{this.item.timeFormatted}}
</span>
{{/if}}
</template>
}

View File

@ -1,12 +1,15 @@
import { htmlSafe } from "@ember/template";
import { classNames } from "@ember-decorators/component";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("homepage-style-selector-row")
export default class HomepageStyleSelectorRow extends SelectKitRowComponent {}
<div class="texts">
<span class="name">{{html-safe this.label}}</span>
{{#if this.item.description}}
<span class="desc">{{html-safe this.item.description}}</span>
{{/if}}
</div>
export default class HomepageStyleSelectorRow extends SelectKitRowComponent {
<template>
<div class="texts">
<span class="name">{{htmlSafe this.label}}</span>
{{#if this.item.description}}
<span class="desc">{{htmlSafe this.item.description}}</span>
{{/if}}
</div>
</template>
}

View File

@ -1,7 +1,10 @@
import Component from "@ember/component";
import { fn } from "@ember/helper";
import { computed } from "@ember/object";
import { reads } from "@ember/object/computed";
import { tagName } from "@ember-decorators/component";
import DButton from "discourse/components/d-button";
import discourseTag from "discourse/helpers/discourse-tag";
@tagName("")
export default class SelectedCollection extends Component {
@ -27,20 +30,22 @@ export default class SelectedCollection extends Component {
};
});
}
}
{{#if this.tags}}
<div class="mini-tag-chooser-selected-collection selected-tags">
{{#each this.tags as |tag|}}
<DButton
@translatedTitle={{tag.value}}
@icon="xmark"
@action={{fn (action this.selectKit.deselect) tag.value}}
tabindex="0"
class={{tag.classNames}}
>
{{discourse-tag tag.value noHref=true}}
</DButton>
{{/each}}
</div>
{{/if}}
<template>
{{#if this.tags}}
<div class="mini-tag-chooser-selected-collection selected-tags">
{{#each this.tags as |tag|}}
<DButton
@translatedTitle={{tag.value}}
@icon="xmark"
@action={{fn (action this.selectKit.deselect) tag.value}}
tabindex="0"
class={{tag.classNames}}
>
{{discourseTag tag.value noHref=true}}
</DButton>
{{/each}}
</div>
{{/if}}
</template>
}

View File

@ -21,8 +21,10 @@ export default class FormatSelectedContent extends Component.extend(
return this.getName(this.selectKit.noneItem);
}
}
}
<span class="formatted-selection">
{{this.formattedContent}}
</span>
<template>
<span class="formatted-selection">
{{this.formattedContent}}
</span>
</template>
}

View File

@ -1,6 +1,9 @@
import { Input } from "@ember/component";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { isEmpty } from "@ember/utils";
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import discourseComputed from "discourse/lib/decorators";
import SelectKitFilterComponent from "select-kit/components/select-kit/select-kit-filter";
@ -34,30 +37,32 @@ export default class MultiSelectFilter extends SelectKitFilterComponent {
return false;
}
}
<template>
{{#unless this.isHidden}}
{{! filter-input-search prevents 1password from attempting autocomplete }}
{{! template-lint-disable no-pointer-down-event-binding }}
<Input
tabindex={{0}}
class="filter-input"
placeholder={{this.computedPlaceholder}}
autocomplete="off"
autocorrect="off"
autocapitalize="off"
name="filter-input-search"
spellcheck={{false}}
@value={{readonly this.selectKit.filter}}
@type="search"
{{on "paste" (action "onPaste")}}
{{on "keydown" (action "onKeydown")}}
{{on "keyup" (action "onKeyup")}}
{{on "input" (action "onInput")}}
/>
{{#if this.selectKit.options.filterIcon}}
{{icon this.selectKit.options.filterIcon class="filter-icon"}}
{{/if}}
{{/unless}}
</template>
}
{{#unless this.isHidden}}
{{! filter-input-search prevents 1password from attempting autocomplete }}
{{! template-lint-disable no-pointer-down-event-binding }}
<Input
tabindex={{0}}
class="filter-input"
placeholder={{this.computedPlaceholder}}
autocomplete="off"
autocorrect="off"
autocapitalize="off"
name="filter-input-search"
spellcheck={{false}}
@value={{readonly this.selectKit.filter}}
@type="search"
{{on "paste" (action "onPaste")}}
{{on "keydown" (action "onKeydown")}}
{{on "keyup" (action "onKeyup")}}
{{on "input" (action "onInput")}}
/>
{{#if this.selectKit.options.filterIcon}}
{{d-icon this.selectKit.options.filterIcon class="filter-icon"}}
{{/if}}
{{/unless}}

View File

@ -1,7 +1,9 @@
import { on } from "@ember/modifier";
import { computed } from "@ember/object";
import { htmlSafe } from "@ember/template";
import { classNames } from "@ember-decorators/component";
import { categoryBadgeHTML } from "discourse/helpers/category-link";
import icon from "discourse/helpers/d-icon";
import SelectedNameComponent from "select-kit/components/selected-name";
@classNames("selected-category")
@ -15,18 +17,20 @@ export default class SelectedCategory extends SelectedNameComponent {
})
);
}
}
<div
{{on "click" this.onSelectedNameClick}}
tabindex="0"
title={{this.title}}
data-value={{this.value}}
data-name={{this.name}}
class="select-kit-selected-name selected-name choice"
>
<div class="body">
{{this.badge}}
{{d-icon "xmark"}}
</div>
</div>
<template>
<div
{{on "click" this.onSelectedNameClick}}
tabindex="0"
title={{this.title}}
data-value={{this.value}}
data-name={{this.name}}
class="select-kit-selected-name selected-name choice"
>
<div class="body">
{{this.badge}}
{{icon "xmark"}}
</div>
</div>
</template>
}

View File

@ -1,6 +1,7 @@
import { htmlSafe } from "@ember/template";
import { classNames } from "@ember-decorators/component";
import { categoryBadgeHTML } from "discourse/helpers/category-link";
import dirSpan from "discourse/helpers/dir-span";
import discourseComputed from "discourse/lib/decorators";
import CategoryRowComponent from "select-kit/components/category-row";
@ -16,24 +17,26 @@ export default class NoneCategoryRow extends CategoryRowComponent {
})
);
}
}
{{#if this.category}}
<div class="category-status" aria-hidden="true">
{{#if this.hasParentCategory}}
{{#unless this.hideParentCategory}}
{{this.badgeForParentCategory}}
{{/unless}}
<template>
{{#if this.category}}
<div class="category-status" aria-hidden="true">
{{#if this.hasParentCategory}}
{{#unless this.hideParentCategory}}
{{this.badgeForParentCategory}}
{{/unless}}
{{/if}}
{{this.badgeForCategory}}
</div>
{{#if this.shouldDisplayDescription}}
<div class="category-desc" aria-hidden="true">{{dirSpan
this.descriptionText
htmlSafe="true"
}}</div>
{{/if}}
{{else}}
{{htmlSafe this.label}}
{{/if}}
{{this.badgeForCategory}}
</div>
{{#if this.shouldDisplayDescription}}
<div class="category-desc" aria-hidden="true">{{dir-span
this.descriptionText
htmlSafe="true"
}}</div>
{{/if}}
{{else}}
{{html-safe this.label}}
{{/if}}
</template>
}

View File

@ -1,6 +1,8 @@
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import { fmt } from "discourse/lib/computed";
import discourseComputed from "discourse/lib/decorators";
import { i18n } from "discourse-i18n";
import DropdownSelectBoxHeaderComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-header";
@classNames("notifications-filter-header", "btn-flat")
@ -11,14 +13,16 @@ export default class NotificationsFilterHeader extends DropdownSelectBoxHeaderCo
caretIcon(isExpanded) {
return isExpanded ? "caret-up" : "caret-down";
}
}
<div class="select-kit-header-wrapper">
<span class="filter-text">
{{i18n "user.user_notifications.filters.filter_by"}}
</span>
<span class="header-text">
{{i18n this.label}}
</span>
{{d-icon this.caretIcon class="caret-icon"}}
</div>
<template>
<div class="select-kit-header-wrapper">
<span class="filter-text">
{{i18n "user.user_notifications.filters.filter_by"}}
</span>
<span class="header-text">
{{i18n this.label}}
</span>
{{icon this.caretIcon class="caret-icon"}}
</div>
</template>
}

View File

@ -1,4 +1,6 @@
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import periodTitle from "discourse/helpers/period-title";
import discourseComputed from "discourse/lib/decorators";
import DropdownSelectBoxHeaderComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-header";
@ -8,14 +10,16 @@ export default class PeriodChooserHeader extends DropdownSelectBoxHeaderComponen
caretIcon(isExpanded) {
return isExpanded ? "caret-up" : "caret-down";
}
<template>
<h2 class="selected-name" title={{this.title}}>
{{periodTitle
this.value
showDateRange=true
fullDay=this.selectKit.options.fullDay
}}
</h2>
{{icon this.caretIcon class="caret-icon"}}
</template>
}
<h2 class="selected-name" title={{this.title}}>
{{period-title
this.value
showDateRange=true
fullDay=this.selectKit.options.fullDay
}}
</h2>
{{d-icon this.caretIcon class="caret-icon"}}

View File

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import periodTitle from "discourse/helpers/period-title";
import discourseComputed from "discourse/lib/decorators";
import { i18n } from "discourse-i18n";
import DropdownSelectBoxRowComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-row";
@ -9,14 +10,16 @@ export default class PeriodChooserRow extends DropdownSelectBoxRowComponent {
title(rowName) {
return i18n(`filters.top.${rowName || "this_week"}`).title;
}
<template>
<span class="selection-indicator"></span>
<span class="period-title">
{{periodTitle
this.rowValue
showDateRange=true
fullDay=this.selectKit.options.fullDay
}}
</span>
</template>
}
<span class="selection-indicator"></span>
<span class="period-title">
{{period-title
this.rowValue
showDateRange=true
fullDay=this.selectKit.options.fullDay
}}
</span>

View File

@ -2,12 +2,14 @@ import Component from "@ember/component";
import { tagName } from "@ember-decorators/component";
@tagName("")
export default class ErrorsCollection extends Component {}
{{#if this.collection.content}}
<ul class="select-kit-errors-collection">
{{#each this.collection.content as |item|}}
<li class="select-kit-error">{{item}}</li>
{{/each}}
</ul>
{{/if}}
export default class ErrorsCollection extends Component {
<template>
{{#if this.collection.content}}
<ul class="select-kit-errors-collection">
{{#each this.collection.content as |item|}}
<li class="select-kit-error">{{item}}</li>
{{/each}}
</ul>
{{/if}}
</template>
}

View File

@ -61,8 +61,10 @@ export default class SelectKitBody extends Component {
this.selectKit.close(event);
});
}
}
{{#if this.selectKit.isExpanded}}
{{yield}}
{{/if}}
<template>
{{#if this.selectKit.isExpanded}}
{{yield}}
{{/if}}
</template>
}

View File

@ -1,13 +1,16 @@
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("create")
export default class SelectKitCreateRow extends SelectKitRowComponent {}
export default class SelectKitCreateRow extends SelectKitRowComponent {
<template>
{{#each this.icons as |i|}}
{{icon i translatedTitle=this.dasherizedTitle}}
{{/each}}
{{#each this.icons as |icon|}}
{{d-icon icon translatedTitle=this.dasherizedTitle}}
{{/each}}
<span class="name">
{{this.label}}
</span>
<span class="name">
{{this.label}}
</span>
</template>
}

View File

@ -1,4 +1,5 @@
import Component from "@ember/component";
import Component, { Input } from "@ember/component";
import { on } from "@ember/modifier";
import { action, computed } from "@ember/object";
import { not } from "@ember/object/computed";
import { isPresent } from "@ember/utils";
@ -7,6 +8,7 @@ import {
classNameBindings,
classNames,
} from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import discourseComputed from "discourse/lib/decorators";
import { i18n } from "discourse-i18n";
import UtilsMixin from "select-kit/mixins/utils";
@ -137,30 +139,32 @@ export default class SelectKitFilter extends Component.extend(UtilsMixin) {
this.selectKit.set("highlighted", null);
}
<template>
{{#unless this.isHidden}}
{{! filter-input-search prevents 1password from attempting autocomplete }}
{{! template-lint-disable no-pointer-down-event-binding }}
<Input
tabindex={{0}}
class="filter-input"
placeholder={{this.placeholder}}
autocomplete="off"
autocorrect="off"
autocapitalize="off"
name="filter-input-search"
spellcheck={{false}}
@value={{readonly this.selectKit.filter}}
@type="search"
{{on "paste" (action "onPaste")}}
{{on "keydown" (action "onKeydown")}}
{{on "keyup" (action "onKeyup")}}
{{on "input" (action "onInput")}}
/>
{{#if this.selectKit.options.filterIcon}}
{{icon this.selectKit.options.filterIcon class="filter-icon"}}
{{/if}}
{{/unless}}
</template>
}
{{#unless this.isHidden}}
{{! filter-input-search prevents 1password from attempting autocomplete }}
{{! template-lint-disable no-pointer-down-event-binding }}
<Input
tabindex={{0}}
class="filter-input"
placeholder={{this.placeholder}}
autocomplete="off"
autocorrect="off"
autocapitalize="off"
name="filter-input-search"
spellcheck={{false}}
@value={{readonly this.selectKit.filter}}
@type="search"
{{on "paste" (action "onPaste")}}
{{on "keydown" (action "onKeydown")}}
{{on "keyup" (action "onKeyup")}}
{{on "input" (action "onInput")}}
/>
{{#if this.selectKit.options.filterIcon}}
{{d-icon this.selectKit.options.filterIcon class="filter-icon"}}
{{/if}}
{{/unless}}

View File

@ -1,13 +1,16 @@
import { classNames } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("none")
export default class SelectKitNoneRow extends SelectKitRowComponent {}
export default class SelectKitNoneRow extends SelectKitRowComponent {
<template>
{{#each this.icons as |i|}}
{{icon i translatedTitle=this.dasherizedTitle}}
{{/each}}
{{#each this.icons as |icon|}}
{{d-icon icon translatedTitle=this.dasherizedTitle}}
{{/each}}
<span class="name">
{{this.label}}
</span>
<span class="name">
{{this.label}}
</span>
</template>
}

View File

@ -9,6 +9,7 @@ import {
classNames,
tagName,
} from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import { makeArray } from "discourse/lib/helpers";
import { i18n } from "discourse-i18n";
import UtilsMixin from "select-kit/mixins/utils";
@ -117,9 +118,9 @@ export default class SelectKitRow extends Component.extend(UtilsMixin) {
@computed("item.{icon,icons}")
get icons() {
const icon = makeArray(this.getProperty(this.item, "icon"));
const _icon = makeArray(this.getProperty(this.item, "icon"));
const icons = makeArray(this.getProperty(this.item, "icons"));
return icon.concat(icons).filter(Boolean);
return _icon.concat(icons).filter(Boolean);
}
@computed("selectKit.highlighted")
@ -203,12 +204,14 @@ export default class SelectKitRow extends Component.extend(UtilsMixin) {
}
}
}
<template>
{{#each this.icons as |i|}}
{{icon i translatedTitle=this.dasherizedTitle}}
{{/each}}
<span class="name">
{{this.label}}
</span>
</template>
}
{{#each this.icons as |icon|}}
{{d-icon icon translatedTitle=this.dasherizedTitle}}
{{/each}}
<span class="name">
{{this.label}}
</span>

View File

@ -1,7 +1,11 @@
import Component from "@ember/component";
import { fn } from "@ember/helper";
import { on } from "@ember/modifier";
import { computed } from "@ember/object";
import { guidFor } from "@ember/object/internals";
import { tagName } from "@ember-decorators/component";
import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n";
import UtilsMixin from "select-kit/mixins/utils";
@tagName("")
@ -39,30 +43,32 @@ export default class SelectedChoice extends Component.extend(UtilsMixin) {
}
return this.mandatoryValuesArray.includes(this.item.id);
}
}
{{#if this.readOnly}}
<button
class="btn btn-default disabled"
title={{I18n "admin.site_settings.mandatory_group"}}
>{{this.itemName}}</button>
{{else}}
<button
{{on "click" (fn this.selectKit.deselect this.item)}}
aria-label={{i18n "select_kit.delete_item" name=this.itemName}}
data-value={{this.itemValue}}
data-name={{this.itemName}}
type="button"
id="{{this.id}}-choice"
class="btn btn-default selected-choice {{this.extraClass}}"
>
{{d-icon "xmark"}}
{{#if (has-block)}}
{{yield}}
<template>
{{#if this.readOnly}}
<button
class="btn btn-default disabled"
title={{i18n "admin.site_settings.mandatory_group"}}
>{{this.itemName}}</button>
{{else}}
<span class="d-button-label">
{{this.itemName}}
</span>
<button
{{on "click" (fn this.selectKit.deselect this.item)}}
aria-label={{i18n "select_kit.delete_item" name=this.itemName}}
data-value={{this.itemValue}}
data-name={{this.itemName}}
type="button"
id="{{this.id}}-choice"
class="btn btn-default selected-choice {{this.extraClass}}"
>
{{icon "xmark"}}
{{#if (has-block)}}
{{yield}}
{{else}}
<span class="d-button-label">
{{this.itemName}}
</span>
{{/if}}
</button>
{{/if}}
</button>
{{/if}}
</template>
}

View File

@ -1,16 +1,19 @@
import { tagName } from "@ember-decorators/component";
import AvatarFlair from "discourse/components/avatar-flair";
import SelectedNameComponent from "select-kit/components/selected-name";
@tagName("")
export default class SelectedFlair extends SelectedNameComponent {}
export default class SelectedFlair extends SelectedNameComponent {
<template>
{{#if this.item.url}}
<AvatarFlair
@flairName={{this.item.name}}
@flairUrl={{this.item.url}}
@flairBgColor={{this.item.bgColor}}
@flairColor={{this.item.color}}
/>
{{/if}}
{{#if this.item.url}}
<AvatarFlair
@flairName={{this.item.name}}
@flairUrl={{this.item.url}}
@flairBgColor={{this.item.bgColor}}
@flairColor={{this.item.color}}
/>
{{/if}}
<span>{{this.label}}</span>
<span>{{this.label}}</span>
</template>
}

View File

@ -1,8 +1,12 @@
import Component from "@ember/component";
import { fn } from "@ember/helper";
import { computed, get } from "@ember/object";
import { reads } from "@ember/object/computed";
import { guidFor } from "@ember/object/internals";
import { tagName } from "@ember-decorators/component";
import { and } from "truth-helpers";
import DButton from "discourse/components/d-button";
import icon from "discourse/helpers/d-icon";
import { makeArray } from "discourse/lib/helpers";
import UtilsMixin from "select-kit/mixins/utils";
@ -77,9 +81,9 @@ export default class SelectedName extends Component.extend(UtilsMixin) {
@computed("item.{icon,icons}")
get icons() {
const icon = makeArray(this._safeProperty("icon", this.item));
const _icon = makeArray(this._safeProperty("icon", this.item));
const icons = makeArray(this._safeProperty("icons", this.item));
return icon.concat(icons).filter(Boolean);
return _icon.concat(icons).filter(Boolean);
}
_safeProperty(name, content) {
@ -89,48 +93,50 @@ export default class SelectedName extends Component.extend(UtilsMixin) {
return get(content, name);
}
<template>
{{#if this.selectKit.options.showFullTitle}}
<div
lang={{this.lang}}
title={{this.title}}
data-value={{this.value}}
data-name={{this.name}}
class="select-kit-selected-name selected-name choice"
>
{{#if this.selectKit.options.formName}}
<input
type="hidden"
name={{this.selectKit.options.formName}}
value={{this.value}}
/>
{{/if}}
{{#if (and this.renderIcon this.item.icon)}}
{{icon this.item.icon}}
{{/if}}
<span class="name">
{{this.label}}
</span>
{{#if this.shouldDisplayClearableButton}}
<DButton
@icon="xmark"
@action={{fn this.selectKit.deselect this.item}}
@ariaLabel="clear_input"
class="btn-clear"
/>
{{/if}}
</div>
{{else}}
{{#if this.item.icon}}
<div
lang={{this.lang}}
class="select-kit-selected-name selected-name choice"
>
{{icon this.item.icon}}
</div>
{{/if}}
{{/if}}
</template>
}
{{#if this.selectKit.options.showFullTitle}}
<div
lang={{this.lang}}
title={{this.title}}
data-value={{this.value}}
data-name={{this.name}}
class="select-kit-selected-name selected-name choice"
>
{{#if this.selectKit.options.formName}}
<input
type="hidden"
name={{this.selectKit.options.formName}}
value={{this.value}}
/>
{{/if}}
{{#if (and this.renderIcon this.item.icon)}}
{{d-icon this.item.icon}}
{{/if}}
<span class="name">
{{this.label}}
</span>
{{#if this.shouldDisplayClearableButton}}
<DButton
@icon="xmark"
@action={{fn this.selectKit.deselect this.item}}
@ariaLabel="clear_input"
class="btn-clear"
/>
{{/if}}
</div>
{{else}}
{{#if this.item.icon}}
<div
lang={{this.lang}}
class="select-kit-selected-name selected-name choice"
>
{{d-icon this.item.icon}}
</div>
{{/if}}
{{/if}}

View File

@ -1,7 +1,10 @@
import { classNames } from "@ember-decorators/component";
import discourseTag from "discourse/helpers/discourse-tag";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("tag-chooser-row")
export default class TagChooserRow extends SelectKitRowComponent {}
{{discourse-tag this.rowValue count=this.item.count noHref=true}}
export default class TagChooserRow extends SelectKitRowComponent {
<template>
{{discourseTag this.rowValue count=this.item.count noHref=true}}
</template>
}

View File

@ -1,4 +1,5 @@
import { classNames } from "@ember-decorators/component";
import discourseTag from "discourse/helpers/discourse-tag";
import discourseComputed from "discourse/lib/decorators";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@ -8,15 +9,17 @@ export default class TagRow extends SelectKitRowComponent {
isTag(item) {
return item.id !== "no-tags" && item.id !== "all-tags";
}
}
{{#if this.isTag}}
{{discourse-tag
this.rowValue
noHref=true
description=this.item.description
count=this.item.count
}}
{{else}}
<span class="name">{{this.item.name}}</span>
{{/if}}
<template>
{{#if this.isTag}}
{{discourseTag
this.rowValue
noHref=true
description=this.item.description
count=this.item.count
}}
{{else}}
<span class="name">{{this.item.name}}</span>
{{/if}}
</template>
}

View File

@ -1,5 +1,5 @@
import Component from "@ember/component";
export default class ToolbarPopupMenuOptionsHeading extends Component {}
{{this.heading}}
export default class ToolbarPopupMenuOptionsHeading extends Component {
<template>{{this.heading}}</template>
}

View File

@ -1,16 +1,21 @@
import { classNames } from "@ember-decorators/component";
import TopicStatus from "discourse/components/topic-status";
import boundCategoryLink from "discourse/helpers/bound-category-link";
import replaceEmoji from "discourse/helpers/replace-emoji";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("topic-row")
export default class TopicRow extends SelectKitRowComponent {}
<TopicStatus @topic={{this.item}} @disableActions={{true}} />
<div class="topic-title">{{replace-emoji this.item.title}}</div>
<div class="topic-categories">
{{bound-category-link
this.item.category
ancestors=this.item.category.predecessors
hideParent=true
link=false
}}
</div>
export default class TopicRow extends SelectKitRowComponent {
<template>
<TopicStatus @topic={{this.item}} @disableActions={{true}} />
<div class="topic-title">{{replaceEmoji this.item.title}}</div>
<div class="topic-categories">
{{boundCategoryLink
this.item.category
ancestors=this.item.category.predecessors
hideParent=true
link=false
}}
</div>
</template>
}

View File

@ -1,13 +1,17 @@
import { classNames } from "@ember-decorators/component";
import avatar from "discourse/helpers/avatar";
import formatUsername from "discourse/helpers/format-username";
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
@classNames("user-row")
export default class UserRow extends SelectKitRowComponent {}
export default class UserRow extends SelectKitRowComponent {
<template>
{{avatar this.item imageSize="tiny"}}
{{avatar this.item imageSize="tiny"}}
<span class="username">{{formatUsername this.item.username}}</span>
<span class="username">{{format-username this.item.username}}</span>
{{#if this.item.name}}
<span class="name">{{this.item.name}}</span>
{{/if}}
{{#if this.item.name}}
<span class="name">{{this.item.name}}</span>
{{/if}}
</template>
}

View File

@ -20,7 +20,8 @@
"ember-auto-import": "^2.10.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.3.0",
"ember-template-imports": "^4.3.0"
"ember-template-imports": "^4.3.0",
"truth-helpers": "workspace:*"
},
"devDependencies": {
"@ember/optional-features": "^2.2.0",

View File

@ -3,7 +3,7 @@ import I18n, { i18n } from "discourse-i18n";
import DaBooleanField from "./fields/da-boolean-field";
import DaCategoriesField from "./fields/da-categories-field";
import DaCategoryField from "./fields/da-category-field";
import DaCategoryNotificationlevelField from "./fields/da-category-notification-level-field";
import DaCategoryNotificationLevelField from "./fields/da-category-notification-level-field";
import DaChoicesField from "./fields/da-choices-field";
import DaCustomField from "./fields/da-custom-field";
import DaCustomFields from "./fields/da-custom-fields";
@ -44,7 +44,7 @@ const FIELD_COMPONENTS = {
group: DaGroupField,
groups: DaGroupsField,
choices: DaChoicesField,
category_notification_level: DaCategoryNotificationlevelField,
category_notification_level: DaCategoryNotificationLevelField,
email_group_user: DaEmailGroupUserField,
custom_field: DaCustomField,
custom_fields: DaCustomFields,

View File

@ -3,7 +3,7 @@ import BaseField from "./da-base-field";
import DAFieldDescription from "./da-field-description";
import DAFieldLabel from "./da-field-label";
export default class CategoryNotficationLevelField extends BaseField {
export default class CategoryNotificationLevelField extends BaseField {
<template>
<section class="field category-notification-level-field">
<div class="control-group">

View File

@ -0,0 +1,10 @@
import htmlSafe from "discourse/helpers/html-safe";
const FormError = <template>
{{#if @error}}
<div class="alert alert-error form-errors">
{{htmlSafe @error}}
</div>
{{/if}}
</template>;
export default FormError;

View File

@ -0,0 +1,22 @@
import { Input } from "@ember/component";
import { on } from "@ember/modifier";
import { i18n } from "discourse-i18n";
const TopicTrigger = <template>
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.triggerables.topic.topic_id.label"}}
</label>
<div class="controls">
<Input
@value={{this.metadata.topic_id}}
{{on
"input"
(action (mut this.metadata.topic_id) value="target.value")
}}
/>
</div>
</div>
</template>;
export default TopicTrigger;

View File

@ -1,5 +0,0 @@
{{#if @error}}
<div class="alert alert-error form-errors">
{{html-safe @error}}
</div>
{{/if}}

View File

@ -1,12 +0,0 @@
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.triggerables.topic.topic_id.label"}}
</label>
<div class="controls">
<Input
@value={{this.metadata.topic_id}}
{{on "input" (action (mut this.metadata.topic_id) value="target.value")}}
/>
</div>
</div>

View File

@ -1,189 +1,228 @@
<div class="admin-detail discourse-automation-edit discourse-automation-form">
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<form class="form-horizontal">
<FormError @error={{this.error}} />
import { Input } from "@ember/component";
import { fn, hash } from "@ember/helper";
import { on } from "@ember/modifier";
import RouteTemplate from "ember-route-template";
import { and } from "truth-helpers";
import BackButton from "discourse/components/back-button";
import DButton from "discourse/components/d-button";
import TextField from "discourse/components/text-field";
import withEventValue from "discourse/helpers/with-event-value";
import { i18n } from "discourse-i18n";
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
import ComboBox from "select-kit/components/combo-box";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import FormError from "discourse/plugins/automation/admin/components/form-error";
<section class="form-section edit">
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.automation.name.label"}}
</label>
export default RouteTemplate(
<template>
<div
class="admin-detail discourse-automation-edit discourse-automation-form"
>
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<form class="form-horizontal">
<FormError @error={{@controller.error}} />
<div class="controls">
<TextField
@value={{this.automationForm.name}}
@type="text"
@autofocus={{true}}
@name="automation-name"
class="input-large"
@input={{with-event-value (fn (mut this.automationForm.name))}}
/>
</div>
</div>
<section class="form-section edit">
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.automation.name.label"}}
</label>
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.script.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.script}}
@content={{this.model.scriptables}}
@onChange={{this.onChangeScript}}
@options={{hash filterable=true}}
class="scriptables"
/>
</div>
</div>
</section>
<section class="trigger-section form-section edit">
<h2 class="title">
{{i18n
"discourse_automation.edit_automation.trigger_section.title"
}}
</h2>
<div class="control-group">
{{#if this.model.automation.script.forced_triggerable}}
<div class="alert alert-warning">
{{i18n
"discourse_automation.edit_automation.trigger_section.forced"
}}
</div>
{{/if}}
<label class="control-label">
{{i18n "discourse_automation.models.trigger.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.trigger}}
@content={{this.model.triggerables}}
@onChange={{this.onChangeTrigger}}
@options={{hash
filterable=true
none="discourse_automation.select_trigger"
disabled=this.model.automation.script.forced_triggerable
}}
class="triggerables"
/>
</div>
</div>
{{#if this.automationForm.trigger}}
{{#if this.model.automation.trigger.doc}}
<div class="alert alert-info">
<p>{{this.model.automation.trigger.doc}}</p>
</div>
{{/if}}
{{#if
(and
this.model.automation.enabled
this.model.automation.trigger.settings.manual_trigger
)
}}
<div class="alert alert-info next-trigger">
{{#if this.nextPendingAutomationAtFormatted}}
<p>
{{i18n
"discourse_automation.edit_automation.trigger_section.next_pending_automation"
date=this.nextPendingAutomationAtFormatted
<div class="controls">
<TextField
@value={{@controller.automationForm.name}}
@type="text"
@autofocus={{true}}
@name="automation-name"
class="input-large"
@input={{withEventValue
(fn (mut @controller.automationForm.name))
}}
</p>
{{/if}}
<DButton
@label="discourse_automation.edit_automation.trigger_section.trigger_now"
@isLoading={{this.isTriggeringAutomation}}
@action={{fn
this.onManualAutomationTrigger
this.model.automation.id
}}
class="btn-primary trigger-now-btn"
/>
/>
</div>
</div>
{{/if}}
{{#each this.triggerFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
{{/if}}
</section>
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.script.name.label"}}
</label>
{{#if this.automationForm.trigger}}
{{#if this.scriptFields}}
<section class="fields-section form-section edit">
<div class="controls">
<ComboBox
@value={{@controller.automationForm.script}}
@content={{@controller.model.scriptables}}
@onChange={{@controller.onChangeScript}}
@options={{hash filterable=true}}
class="scriptables"
/>
</div>
</div>
</section>
<section class="trigger-section form-section edit">
<h2 class="title">
{{i18n
"discourse_automation.edit_automation.fields_section.title"
"discourse_automation.edit_automation.trigger_section.title"
}}
</h2>
{{#if this.model.automation.script.with_trigger_doc}}
<div class="alert alert-info">
<p>{{this.model.automation.script.with_trigger_doc}}</p>
<div class="control-group">
{{#if @controller.model.automation.script.forced_triggerable}}
<div class="alert alert-warning">
{{i18n
"discourse_automation.edit_automation.trigger_section.forced"
}}
</div>
{{/if}}
<label class="control-label">
{{i18n "discourse_automation.models.trigger.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{@controller.automationForm.trigger}}
@content={{@controller.model.triggerables}}
@onChange={{@controller.onChangeTrigger}}
@options={{hash
filterable=true
none="discourse_automation.select_trigger"
disabled=@controller.model.automation.script.forced_triggerable
}}
class="triggerables"
/>
</div>
</div>
{{#if @controller.automationForm.trigger}}
{{#if @controller.model.automation.trigger.doc}}
<div class="alert alert-info">
<p>{{@controller.model.automation.trigger.doc}}</p>
</div>
{{/if}}
{{#if
(and
@controller.model.automation.enabled
@controller.model.automation.trigger.settings.manual_trigger
)
}}
<div class="alert alert-info next-trigger">
{{#if @controller.nextPendingAutomationAtFormatted}}
<p>
{{i18n
"discourse_automation.edit_automation.trigger_section.next_pending_automation"
date=@controller.nextPendingAutomationAtFormatted
}}
</p>
{{/if}}
<DButton
@label="discourse_automation.edit_automation.trigger_section.trigger_now"
@isLoading={{@controller.isTriggeringAutomation}}
@action={{fn
@controller.onManualAutomationTrigger
@controller.model.automation.id
}}
class="btn-primary trigger-now-btn"
/>
</div>
{{/if}}
{{#each @controller.triggerFields as |field|}}
<AutomationField
@automation={{@controller.automation}}
@field={{field}}
@saveAutomation={{fn
@controller.saveAutomation
@controller.automation
}}
/>
{{/each}}
{{/if}}
</section>
{{#if @controller.automationForm.trigger}}
{{#if @controller.scriptFields}}
<section class="fields-section form-section edit">
<h2 class="title">
{{i18n
"discourse_automation.edit_automation.fields_section.title"
}}
</h2>
{{#if @controller.model.automation.script.with_trigger_doc}}
<div class="alert alert-info">
<p
>{{@controller.model.automation.script.with_trigger_doc}}</p>
</div>
{{/if}}
<div class="control-group">
{{#each @controller.scriptFields as |field|}}
<AutomationField
@automation={{@controller.automation}}
@field={{field}}
@saveAutomation={{fn
@controller.saveAutomation
@controller.automation
}}
/>
{{/each}}
</div>
</section>
{{/if}}
{{#if @controller.automationForm.trigger}}
<div
class="control-group automation-enabled alert
{{if
@controller.automationForm.enabled
'alert-info'
'alert-warning'
}}"
>
<span>{{i18n
"discourse_automation.models.automation.enabled.label"
}}</span>
<Input
@type="checkbox"
@checked={{@controller.automationForm.enabled}}
{{on
"click"
(action
(mut @controller.automationForm.enabled)
value="target.checked"
)
}}
/>
</div>
{{/if}}
<div class="control-group">
{{#each this.scriptFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
<DButton
@isLoading={{@controller.isUpdatingAutomation}}
@label="discourse_automation.update"
@type="submit"
@action={{fn
@controller.saveAutomation
@controller.automation
true
}}
class="btn-primary update-automation"
/>
</div>
</section>
{{/if}}
{{#if this.automationForm.trigger}}
<div
class="control-group automation-enabled alert
{{if this.automationForm.enabled 'alert-info' 'alert-warning'}}"
>
<span>{{i18n
"discourse_automation.models.automation.enabled.label"
}}</span>
<Input
@type="checkbox"
@checked={{this.automationForm.enabled}}
{{on
"click"
(action
(mut this.automationForm.enabled) value="target.checked"
)
}}
/>
</div>
{{/if}}
<div class="control-group">
<DButton
@isLoading={{this.isUpdatingAutomation}}
@label="discourse_automation.update"
@type="submit"
@action={{fn this.saveAutomation this.automation true}}
class="btn-primary update-automation"
/>
</div>
{{/if}}
</form>
</:content>
</AdminConfigAreaCard>
</div>
{{/if}}
</form>
</:content>
</AdminConfigAreaCard>
</div>
</template>
);

View File

@ -1 +1,6 @@
<AutomationList @model={{this.model}} />
import RouteTemplate from "ember-route-template";
import AutomationList from "discourse/plugins/automation/admin/components/automation-list";
export default RouteTemplate(
<template><AutomationList @model={{@controller.model}} /></template>
);

View File

@ -1,27 +1,41 @@
<div class="admin-detail discourse-automation-new discourse-automation-form">
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<input
type="text"
placeholder={{i18n "discourse_automation.filter_placeholder"}}
{{on "input" this.updateFilterText}}
class="admin-section-landing__header-filter"
/>
import { fn } from "@ember/helper";
import { on } from "@ember/modifier";
import RouteTemplate from "ember-route-template";
import BackButton from "discourse/components/back-button";
import { i18n } from "discourse-i18n";
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
import AdminSectionLandingItem from "admin/components/admin-section-landing-item";
<div class="admin-section-landing__wrapper">
{{#each this.scriptableContent as |script|}}
<AdminSectionLandingItem
{{on "click" (fn this.selectScriptToEdit script)}}
@titleLabelTranslated={{script.name}}
@descriptionLabelTranslated={{script.description}}
export default RouteTemplate(
<template>
<div
class="admin-detail discourse-automation-new discourse-automation-form"
>
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<input
type="text"
placeholder={{i18n "discourse_automation.filter_placeholder"}}
{{on "input" @controller.updateFilterText}}
class="admin-section-landing__header-filter"
/>
{{/each}}
</div>
</:content>
</AdminConfigAreaCard>
</div>
<div class="admin-section-landing__wrapper">
{{#each @controller.scriptableContent as |script|}}
<AdminSectionLandingItem
{{on "click" (fn @controller.selectScriptToEdit script)}}
@titleLabelTranslated={{script.name}}
@descriptionLabelTranslated={{script.description}}
/>
{{/each}}
</div>
</:content>
</AdminConfigAreaCard>
</div>
</template>
);

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { click, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-boolean-field", function (hooks) {
@ -13,10 +13,17 @@ module("Integration | Component | da-boolean-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field();
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await click("input");

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-categories-field", function (hooks) {
@ -14,12 +14,19 @@ module("Integration | Component | da-categories-field", function (hooks) {
});
test("sets values", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "categories",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-category-field", function (hooks) {
@ -14,12 +14,19 @@ module("Integration | Component | da-category-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "category",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import notificationsTracking from "discourse/tests/helpers/notifications-tracking-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module(
@ -16,12 +16,19 @@ module(
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "category_notification_level",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await notificationsTracking().selectLevelId(2);

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-choices-field", function (hooks) {
@ -14,13 +14,20 @@ module("Integration | Component | da-choices-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "choices",
extra: { content: [{ name: "One", id: 1 }] },
});
await render(
hbs` <AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,10 +1,10 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-custom-field", function (hooks) {
@ -34,12 +34,19 @@ module("Integration | Component | da-custom-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "custom_field",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-date-time-field", function (hooks) {
@ -13,12 +13,19 @@ module("Integration | Component | da-date-time-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "date_time",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await fillIn("input", "2023-10-03T12:34");

View File

@ -1,13 +1,15 @@
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import DaEmailGroupUserField from "discourse/plugins/automation/admin/components/fields/da-email-group-user-field";
module("Integration | Component | email-group-user-field", function (hooks) {
setupRenderingTest(hooks);
test("Email group user field uses email-group-user-chooser component", async function (assert) {
const template = hbs` <Fields::DaEmailGroupUserField @label="a label" />`;
const template = <template>
<DaEmailGroupUserField @label="a label" />
</template>;
await render(template);

View File

@ -1,10 +1,10 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-group-field", function (hooks) {
@ -27,12 +27,19 @@ module("Integration | Component | da-group-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "group",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,10 +1,10 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-groups-field", function (hooks) {
@ -34,12 +34,19 @@ module("Integration | Component | da-groups-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "groups",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();
@ -49,13 +56,20 @@ module("Integration | Component | da-groups-field", function (hooks) {
});
test("supports a maxmimum value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "groups",
extra: { maximum: 1 },
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-message-field", function (hooks) {
@ -13,12 +13,19 @@ module("Integration | Component | da-message-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "message",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await fillIn("textarea", "Hello World");
@ -26,13 +33,20 @@ module("Integration | Component | da-message-field", function (hooks) {
});
test("render placeholders", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "message",
});
this.automation.placeholders = ["foo", "bar"];
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
assert.dom(".placeholders-list").hasText("foo bar");

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { click, fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-pms-field", function (hooks) {
@ -13,12 +13,19 @@ module("Integration | Component | da-pms-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "pms",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await click(".insert-pm");

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-post-field", function (hooks) {
@ -13,12 +13,19 @@ module("Integration | Component | da-post-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "post",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await fillIn("textarea", "Hello World");

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-tags-field", function (hooks) {
@ -14,12 +14,19 @@ module("Integration | Component | da-tags-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "tags",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,8 +1,8 @@
import { getOwner } from "@ember/owner";
import { fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-text-field", function (hooks) {
@ -13,12 +13,19 @@ module("Integration | Component | da-text-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "text",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await fillIn("input", "Hello World");

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-text-list-field", function (hooks) {
@ -14,12 +14,19 @@ module("Integration | Component | da-text-list-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "text_list",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();
await selectKit().fillInFilter("test");

View File

@ -1,9 +1,9 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-trust-levels-field", function (hooks) {
@ -14,12 +14,19 @@ module("Integration | Component | da-trust-levels-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "trust-levels",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,10 +1,10 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-user-field", function (hooks) {
@ -27,12 +27,19 @@ module("Integration | Component | da-user-field", function (hooks) {
});
test("set value", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "user",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -1,10 +1,10 @@
import { getOwner } from "@ember/owner";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import AutomationField from "discourse/plugins/automation/admin/components/automation-field";
import AutomationFabricators from "discourse/plugins/automation/admin/lib/fabricators";
module("Integration | Component | da-users-field", function (hooks) {
@ -32,12 +32,19 @@ module("Integration | Component | da-users-field", function (hooks) {
});
test("sets values", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "users",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();
@ -50,12 +57,19 @@ module("Integration | Component | da-users-field", function (hooks) {
});
test("allows emails", async function (assert) {
const self = this;
this.field = new AutomationFabricators(getOwner(this)).field({
component: "users",
});
await render(
hbs`<AutomationField @automation={{this.automation}} @field={{this.field}} />`
<template>
<AutomationField
@automation={{self.automation}}
@field={{self.field}}
/>
</template>
);
await selectKit().expand();

View File

@ -3,8 +3,24 @@ import { cached } from "@glimmer/tracking";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatComposerMessageDetails from "discourse/plugins/chat/discourse/components/chat-composer-message-details";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const StyleguideComponent = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/component"
);
const Controls = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls"
);
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatComposerMessageDetails extends Component {
@service site;
@service session;
@ -28,20 +44,22 @@ export default class ChatStyleguideChatComposerMessageDetails extends Component
this.message.inReplyTo = null;
}
}
<template>
<StyleguideExample @title="<ChatComposerMessageDetails>">
<StyleguideComponent>
<ChatComposerMessageDetails @message={{this.message}} />
</StyleguideComponent>
<Controls>
<Row @name="Mode">
{{#if this.message.editing}}
<DButton @action={{this.toggleMode}} @translatedLabel="Reply" />
{{else}}
<DButton @action={{this.toggleMode}} @translatedLabel="Editing" />
{{/if}}
</Row>
</Controls>
</StyleguideExample>
</template>
}
<StyleguideExample @title="<ChatComposerMessageDetails>">
<Styleguide::Component>
<ChatComposerMessageDetails @message={{this.message}} />
</Styleguide::Component>
<Styleguide::Controls>
<Styleguide::Controls::Row @name="Mode">
{{#if this.message.editing}}
<DButton @action={{this.toggleMode}} @translatedLabel="Reply" />
{{else}}
<DButton @action={{this.toggleMode}} @translatedLabel="Editing" />
{{/if}}
</Styleguide::Controls::Row>
</Styleguide::Controls>
</StyleguideExample>

View File

@ -1,10 +1,27 @@
import Component from "@glimmer/component";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import { optionalRequire } from "discourse/lib/utilities";
import Channel from "discourse/plugins/chat/discourse/components/chat/composer/channel";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
import { CHANNEL_STATUSES } from "discourse/plugins/chat/discourse/models/chat-channel";
const StyleguideComponent = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/component"
);
const Controls = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls"
);
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatComposer extends Component {
@service chatChannelComposer;
@service chatChannelPane;
@ -29,28 +46,30 @@ export default class ChatStyleguideChatComposer extends Component {
onSendMessage() {
this.chatChannelComposer.reset();
}
<template>
<StyleguideExample @title="<ChatComposer>">
<StyleguideComponent>
<Channel
@channel={{this.channel}}
@onSendMessage={{this.onSendMessage}}
/>
</StyleguideComponent>
<Controls>
<Row @name="Disabled">
<DToggleSwitch
@state={{this.channel.isReadOnly}}
{{on "click" this.toggleDisabled}}
/>
</Row>
<Row @name="Sending">
<DToggleSwitch
@state={{this.chatChannelPane.sending}}
{{on "click" this.toggleSending}}
/>
</Row>
</Controls>
</StyleguideExample>
</template>
}
<StyleguideExample @title="<ChatComposer>">
<Styleguide::Component>
<Chat::Composer::Channel
@channel={{this.channel}}
@onSendMessage={{this.onSendMessage}}
/>
</Styleguide::Component>
<Styleguide::Controls>
<Styleguide::Controls::Row @name="Disabled">
<DToggleSwitch
@state={{this.channel.isReadOnly}}
{{on "click" this.toggleDisabled}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Sending">
<DToggleSwitch
@state={{this.chatChannelPane.sending}}
{{on "click" this.toggleSending}}
/>
</Styleguide::Controls::Row>
</Styleguide::Controls>
</StyleguideExample>

View File

@ -1,6 +1,11 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import { optionalRequire } from "discourse/lib/utilities";
import ComboBox from "select-kit/components/combo-box";
import Icon from "discourse/plugins/chat/discourse/components/chat/header/icon";
import {
HEADER_INDICATOR_PREFERENCE_ALL_NEW,
HEADER_INDICATOR_PREFERENCE_DM_AND_MENTIONS,
@ -8,6 +13,19 @@ import {
HEADER_INDICATOR_PREFERENCE_ONLY_MENTIONS,
} from "discourse/plugins/chat/discourse/controllers/preferences-chat";
const StyleguideComponent = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/component"
);
const Controls = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls"
);
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatHeaderIcon extends Component {
@tracked isActive = false;
@tracked currentUserInDnD = false;
@ -48,64 +66,66 @@ export default class ChatStyleguideChatHeaderIcon extends Component {
updateIndicatorPreference(value) {
this.indicatorPreference = value;
}
}
<StyleguideExample @title="<Chat::Header::Icon>">
<Styleguide::Component>
<header
class="d-header"
style="display: flex; align-items: center; justify-content: center;"
>
<ul class="d-header-icons">
<li class="header-dropdown-toggle chat-header-icon">
<Chat::Header::Icon
@isActive={{this.isActive}}
@currentUserInDnD={{this.currentUserInDnD}}
@unreadCount={{this.unreadCount}}
@urgentCount={{this.urgentCount}}
@indicatorPreference={{this.indicatorPreference}}
<template>
<StyleguideExample @title="<Chat::Header::Icon>">
<StyleguideComponent>
<header
class="d-header"
style="display: flex; align-items: center; justify-content: center;"
>
<ul class="d-header-icons">
<li class="header-dropdown-toggle chat-header-icon">
<Icon
@isActive={{this.isActive}}
@currentUserInDnD={{this.currentUserInDnD}}
@unreadCount={{this.unreadCount}}
@urgentCount={{this.urgentCount}}
@indicatorPreference={{this.indicatorPreference}}
/>
</li>
</ul>
</header>
</StyleguideComponent>
<Controls>
<Row @name="isActive">
<DToggleSwitch
@state={{this.isActive}}
{{on "click" this.toggleIsActive}}
/>
</li>
</ul>
</header>
</Styleguide::Component>
</Row>
<Row @name="currentUserInDnD">
<DToggleSwitch
@state={{this.currentUserInDnD}}
{{on "click" this.toggleCurrentUserInDnD}}
/>
</Row>
</Controls>
<Row @name="Unread count">
<input
type="number"
{{on "input" this.updateUnreadCount}}
value={{this.unreadCount}}
/>
</Row>
<Row @name="Urgent count">
<input
type="number"
{{on "input" this.updateUrgentCount}}
value={{this.urgentCount}}
/>
</Row>
<Row @name="Indicator preference">
<ComboBox
@value={{this.indicatorPreference}}
@content={{this.indicatorPreferences}}
@onChange={{this.updateIndicatorPreference}}
@valueProperty={{null}}
@nameProperty={{null}}
/>
<Styleguide::Controls>
<Styleguide::Controls::Row @name="isActive">
<DToggleSwitch
@state={{this.isActive}}
{{on "click" this.toggleIsActive}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="currentUserInDnD">
<DToggleSwitch
@state={{this.currentUserInDnD}}
{{on "click" this.toggleCurrentUserInDnD}}
/>
</Styleguide::Controls::Row>
</Styleguide::Controls>
<Styleguide::Controls::Row @name="Unread count">
<input
type="number"
{{on "input" this.updateUnreadCount}}
value={{this.unreadCount}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Urgent count">
<input
type="number"
{{on "input" this.updateUrgentCount}}
value={{this.urgentCount}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Indicator preference">
<ComboBox
@value={{this.indicatorPreference}}
@content={{this.indicatorPreferences}}
@onChange={{this.updateIndicatorPreference}}
@valueProperty={{null}}
@nameProperty={{null}}
/>
</Styleguide::Controls::Row>
</StyleguideExample>
</Row>
</StyleguideExample>
</template>
}

View File

@ -1,10 +1,28 @@
import Component from "@glimmer/component";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import { not } from "truth-helpers";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import { optionalRequire } from "discourse/lib/utilities";
import ChatMessage from "discourse/plugins/chat/discourse/components/chat-message";
import ChatMessagesManager from "discourse/plugins/chat/discourse/lib/chat-messages-manager";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const StyleguideComponent = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/component"
);
const Controls = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls"
);
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatMessage extends Component {
@service currentUser;
@ -92,48 +110,50 @@ export default class ChatStyleguideChatMessage extends Component {
];
}
}
<template>
<StyleguideExample @title="<ChatMessage>">
<StyleguideComponent>
<ChatMessage @message={{this.message}} @context="channel" />
</StyleguideComponent>
<Controls>
<Row @name="Deleted">
<DToggleSwitch
@state={{not (not this.message.deletedAt)}}
{{on "click" this.toggleDeleted}}
/>
</Row>
<Row @name="Bookmark">
<DToggleSwitch
@state={{not (not this.message.bookmark)}}
{{on "click" this.toggleBookmarked}}
/>
</Row>
<Row @name="Thread">
<DToggleSwitch
@state={{not (not this.message.thread)}}
{{on "click" this.toggleThread}}
/>
</Row>
<Row @name="Reactions">
<DToggleSwitch
@state={{not (not this.message.reactions)}}
{{on "click" this.toggleReaction}}
/>
</Row>
<Row @name="Upload">
<DToggleSwitch
@state={{not (not this.message.uploads)}}
{{on "click" this.toggleUpload}}
/>
</Row>
<Row @name="Message">
<textarea
{{on "input" this.updateMessage}}
>{{this.message.message}}</textarea>
</Row>
</Controls>
</StyleguideExample>
</template>
}
<StyleguideExample @title="<ChatMessage>">
<Styleguide::Component>
<ChatMessage @message={{this.message}} @context="channel" />
</Styleguide::Component>
<Styleguide::Controls>
<Styleguide::Controls::Row @name="Deleted">
<DToggleSwitch
@state={{not (not this.message.deletedAt)}}
{{on "click" this.toggleDeleted}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Bookmark">
<DToggleSwitch
@state={{not (not this.message.bookmark)}}
{{on "click" this.toggleBookmarked}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Thread">
<DToggleSwitch
@state={{not (not this.message.thread)}}
{{on "click" this.toggleThread}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Reactions">
<DToggleSwitch
@state={{not (not this.message.reactions)}}
{{on "click" this.toggleReaction}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Upload">
<DToggleSwitch
@state={{not (not this.message.uploads)}}
{{on "click" this.toggleUpload}}
/>
</Styleguide::Controls::Row>
<Styleguide::Controls::Row @name="Message">
<textarea
{{on "input" this.updateMessage}}
>{{this.message.message}}</textarea>
</Styleguide::Controls::Row>
</Styleguide::Controls>
</StyleguideExample>

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalArchiveChannel from "discourse/plugins/chat/discourse/components/chat/modal/archive-channel";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalArchiveChannel extends Component {
@service modal;
@ -18,10 +27,12 @@ export default class ChatStyleguideChatModalArchiveChannel extends Component {
},
});
}
}
<StyleguideExample @title="<Chat::Modal::ArchiveChannel>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::ArchiveChannel>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -1,8 +1,17 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalCreateChannel from "discourse/plugins/chat/discourse/components/chat/modal/create-channel";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalCreateChannel extends Component {
@service modal;
@ -10,10 +19,12 @@ export default class ChatStyleguideChatModalCreateChannel extends Component {
openModal() {
return this.modal.show(ChatModalCreateChannel);
}
}
<StyleguideExample @title="<Chat::Modal::CreateChannel>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::CreateChannel>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalDeleteChannel from "discourse/plugins/chat/discourse/components/chat/modal/delete-channel";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalDeleteChannel extends Component {
@service modal;
@ -16,10 +25,12 @@ export default class ChatStyleguideChatModalDeleteChannel extends Component {
model: { channel: this.channel },
});
}
}
<StyleguideExample @title="<Chat::Modal::DeleteChannel>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::DeleteChannel>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalEditChannelDescription from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-description";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalEditChannelDescription extends Component {
@service modal;
@ -16,10 +25,12 @@ export default class ChatStyleguideChatModalEditChannelDescription extends Compo
model: this.channel,
});
}
}
<StyleguideExample @title="<Chat::Modal::EditChannelDescription>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::EditChannelDescription>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalEditChannelName extends Component {
@service modal;
@ -16,10 +25,12 @@ export default class ChatStyleguideChatModalEditChannelName extends Component {
model: this.channel,
});
}
}
<StyleguideExample @title="<Chat::Modal::EditChannelName>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::EditChannelName>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalMoveMessageToChannel from "discourse/plugins/chat/discourse/components/chat/modal/move-message-to-channel";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalMoveMessageToChannel extends Component {
@service modal;
@ -26,10 +35,12 @@ export default class ChatStyleguideChatModalMoveMessageToChannel extends Compone
},
});
}
}
<StyleguideExample @title="<Chat::Modal::MoveMessageToChannel>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::MoveMessageToChannel>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -1,8 +1,17 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalNewMessage from "discourse/plugins/chat/discourse/components/chat/modal/new-message";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalNewMessage extends Component {
@service modal;
@ -10,10 +19,12 @@ export default class ChatStyleguideChatModalNewMessage extends Component {
openModal() {
return this.modal.show(ChatModalNewMessage);
}
}
<StyleguideExample @title="<Chat::Modal::NewMessage>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::NewMessage>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalThreadSettings from "discourse/plugins/chat/discourse/components/chat/modal/thread-settings";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalThreadSettings extends Component {
@service modal;
@ -14,10 +23,12 @@ export default class ChatStyleguideChatModalThreadSettings extends Component {
model: new ChatFabricators(getOwner(this)).thread(),
});
}
}
<StyleguideExample @title="<Chat::Modal::ThreadSettings>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::ThreadSettings>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -2,9 +2,18 @@ import Component from "@glimmer/component";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import { optionalRequire } from "discourse/lib/utilities";
import ChatModalToggleChannelStatus from "discourse/plugins/chat/discourse/components/chat/modal/toggle-channel-status";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const Row = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/controls/row"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatModalToggleChannelStatus extends Component {
@service modal;
@ -14,10 +23,12 @@ export default class ChatStyleguideChatModalToggleChannelStatus extends Componen
model: new ChatFabricators(getOwner(this)).channel(),
});
}
}
<StyleguideExample @title="<Chat::Modal::ToggleChannelStatus>">
<Styleguide::Controls::Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Styleguide::Controls::Row>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::Modal::ToggleChannelStatus>">
<Row>
<DButton @translatedLabel="Open modal" @action={{this.openModal}} />
</Row>
</StyleguideExample>
</template>
}

View File

@ -3,8 +3,17 @@ import { tracked } from "@glimmer/tracking";
import { getOwner } from "@ember/owner";
import { next } from "@ember/runloop";
import { service } from "@ember/service";
import { optionalRequire } from "discourse/lib/utilities";
import Item from "discourse/plugins/chat/discourse/components/chat/thread-list/item";
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
const StyleguideComponent = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide/component"
);
const StyleguideExample = optionalRequire(
"discourse/plugins/styleguide/discourse/components/styleguide-example"
);
export default class ChatStyleguideChatThreadListItem extends Component {
@service currentUser;
@ -17,12 +26,14 @@ export default class ChatStyleguideChatThreadListItem extends Component {
this.thread = new ChatFabricators(getOwner(this)).thread();
});
}
}
<StyleguideExample @title="<Chat::ThreadList::Item>">
<Styleguide::Component>
{{#if this.thread}}
<Chat::ThreadList::Item @thread={{this.thread}} />
{{/if}}
</Styleguide::Component>
</StyleguideExample>
<template>
<StyleguideExample @title="<Chat::ThreadList::Item>">
<StyleguideComponent>
{{#if this.thread}}
<Item @thread={{this.thread}} />
{{/if}}
</StyleguideComponent>
</StyleguideExample>
</template>
}

View File

@ -1,14 +1,25 @@
import Component from "@ember/component";
import { fn, hash } from "@ember/helper";
import { on } from "@ember/modifier";
import EmberObject, { action } from "@ember/object";
import { notEmpty } from "@ember/object/computed";
import { schedule } from "@ember/runloop";
import { observes } from "@ember-decorators/object";
import CalendarDateTimeInput from "discourse/components/calendar-date-time-input";
import DButton from "discourse/components/d-button";
import DModal from "discourse/components/d-modal";
import TextField from "discourse/components/text-field";
import icon from "discourse/helpers/d-icon";
import htmlSafe from "discourse/helpers/html-safe";
import { propertyNotEqual } from "discourse/lib/computed";
import computed, { debounce } from "discourse/lib/decorators";
import { INPUT_DELAY } from "discourse/lib/environment";
import { applyLocalDates } from "discourse/lib/local-dates";
import { cook } from "discourse/lib/text";
import { i18n } from "discourse-i18n";
import ComboBox from "select-kit/components/combo-box";
import MultiSelect from "select-kit/components/multi-select";
import TimezoneInput from "select-kit/components/timezone-input";
import generateDateMarkup from "discourse/plugins/discourse-local-dates/lib/local-date-markup-generator";
export default class LocalDatesCreate extends Component {
@ -371,205 +382,213 @@ export default class LocalDatesCreate extends Component {
cancel() {
this.closeModal();
}
}
<DModal
@title={{i18n "discourse_local_dates.title"}}
@closeModal={{@closeModal}}
class="discourse-local-dates-create-modal -large"
>
<:body>
<div class="form">
{{#if this.isValid}}
{{#if this.timezoneIsDifferentFromUserTimezone}}
<div class="preview alert alert-info">
{{i18n "discourse_local_dates.create.form.current_timezone"}}
<b>{{this.formattedCurrentUserTimezone}}</b>{{this.currentPreview}}
</div>
{{/if}}
{{else}}
<div class="validation-error alert alert-error">
{{i18n "discourse_local_dates.create.form.invalid_date"}}
</div>
{{/if}}
<template>
<DModal
@title={{i18n "discourse_local_dates.title"}}
@closeModal={{@closeModal}}
class="discourse-local-dates-create-modal -large"
>
<:body>
<div class="form">
{{#if this.isValid}}
{{#if this.timezoneIsDifferentFromUserTimezone}}
<div class="preview alert alert-info">
{{i18n "discourse_local_dates.create.form.current_timezone"}}
<b
>{{this.formattedCurrentUserTimezone}}</b>{{this.currentPreview}}
</div>
{{/if}}
{{else}}
<div class="validation-error alert alert-error">
{{i18n "discourse_local_dates.create.form.invalid_date"}}
</div>
{{/if}}
{{this.computeDate}}
{{this.computeDate}}
<div class="date-time-configuration">
<div class="inputs-panel">
<div
class="date-time-control from
{{if this.fromSelected 'is-selected'}}
{{if this.fromFilled 'is-filled'}}"
>
{{d-icon "calendar-days"}}
<DButton
@action={{this.focusFrom}}
@translatedLabel={{this.formattedFrom}}
id="from-date-time"
class="date-time"
autofocus
/>
</div>
<div class="date-time-configuration">
<div class="inputs-panel">
<div
class="date-time-control from
{{if this.fromSelected 'is-selected'}}
{{if this.fromFilled 'is-filled'}}"
>
{{icon "calendar-days"}}
<DButton
@action={{this.focusFrom}}
@translatedLabel={{this.formattedFrom}}
id="from-date-time"
class="date-time"
autofocus
/>
</div>
<div
class="date-time-control to
{{if this.toSelected 'is-selected'}}
{{if this.toFilled 'is-filled'}}"
>
{{d-icon "calendar-days"}}
<DButton
@action={{this.focusTo}}
@translatedLabel={{this.formattedTo}}
class="date-time"
/>
{{#if this.toFilled}}
<DButton
@action={{this.eraseToDateTime}}
@icon="xmark"
class="delete-to-date"
<div
class="date-time-control to
{{if this.toSelected 'is-selected'}}
{{if this.toFilled 'is-filled'}}"
>
{{icon "calendar-days"}}
<DButton
@action={{this.focusTo}}
@translatedLabel={{this.formattedTo}}
class="date-time"
/>
{{#if this.toFilled}}
<DButton
@action={{this.eraseToDateTime}}
@icon="xmark"
class="delete-to-date"
/>
{{/if}}
</div>
{{#if this.site.desktopView}}
<TimezoneInput
@options={{hash icon="globe"}}
@value={{this.timezone}}
@onChange={{fn (mut this.timezone)}}
/>
{{/if}}
</div>
<div class="picker-panel">
<CalendarDateTimeInput
@datePickerId="local-date-create-form"
@date={{this.selectedDate}}
@time={{this.selectedTime}}
@minDate={{this.minDate}}
@timeFormat={{this.timeFormat}}
@dateFormat={{this.dateFormat}}
@onChangeDate={{this.changeSelectedDate}}
@onChangeTime={{this.changeSelectedTime}}
/>
</div>
{{#if this.site.mobileView}}
<TimezoneInput
@value={{this.timezone}}
@options={{hash icon="globe"}}
@onChange={{fn (mut this.timezone)}}
/>
{{/if}}
</div>
{{#if this.site.desktopView}}
<TimezoneInput
@options={{hash icon="globe"}}
@value={{this.timezone}}
@onChange={{fn (mut this.timezone)}}
/>
{{/if}}
</div>
{{#if this.advancedMode}}
<div class="advanced-options">
{{#unless this.isRange}}
<div class="control-group recurrence">
<label class="control-label">
{{i18n "discourse_local_dates.create.form.recurring_title"}}
</label>
<p>{{htmlSafe
(i18n
"discourse_local_dates.create.form.recurring_description"
)
}}</p>
<div class="controls">
<ComboBox
@content={{this.recurringOptions}}
@value={{this.recurring}}
@onChange={{fn (mut this.recurring)}}
@options={{hash
none="discourse_local_dates.create.form.recurring_none"
}}
class="recurrence-input"
/>
</div>
</div>
{{/unless}}
<div class="picker-panel">
<CalendarDateTimeInput
@datePickerId="local-date-create-form"
@date={{this.selectedDate}}
@time={{this.selectedTime}}
@minDate={{this.minDate}}
@timeFormat={{this.timeFormat}}
@dateFormat={{this.dateFormat}}
@onChangeDate={{this.changeSelectedDate}}
@onChangeTime={{this.changeSelectedTime}}
/>
</div>
<div class="control-group timezones">
<label>{{i18n
"discourse_local_dates.create.form.timezones_title"
}}</label>
<p>{{i18n
"discourse_local_dates.create.form.timezones_description"
}}</p>
<div class="controls">
<MultiSelect
@valueProperty={{null}}
@nameProperty={{null}}
@content={{this.allTimezones}}
@value={{this.timezones}}
@options={{hash allowAny=false maximum=5}}
class="timezones-input"
/>
</div>
</div>
{{#if this.site.mobileView}}
<TimezoneInput
@value={{this.timezone}}
@options={{hash icon="globe"}}
@onChange={{fn (mut this.timezone)}}
/>
{{/if}}
</div>
{{#if this.advancedMode}}
<div class="advanced-options">
{{#unless this.isRange}}
<div class="control-group recurrence">
<label class="control-label">
{{i18n "discourse_local_dates.create.form.recurring_title"}}
</label>
<p>{{html-safe
(i18n
"discourse_local_dates.create.form.recurring_description"
)
}}</p>
<div class="controls">
<ComboBox
@content={{this.recurringOptions}}
@value={{this.recurring}}
@onChange={{fn (mut this.recurring)}}
@options={{hash
none="discourse_local_dates.create.form.recurring_none"
<div class="control-group format">
<label>{{i18n
"discourse_local_dates.create.form.format_title"
}}</label>
<p>
{{i18n
"discourse_local_dates.create.form.format_description"
}}
class="recurrence-input"
/>
<a
target="_blank"
href="https://momentjs.com/docs/#/parsing/string-format/"
rel="noopener noreferrer"
>
{{icon "circle-question"}}
</a>
</p>
<div class="controls">
<TextField @value={{this.format}} class="format-input" />
</div>
</div>
<div class="control-group">
<ul class="formats">
{{#each this.previewedFormats as |previewedFormat|}}
<li class="format">
<a
class="moment-format"
href
{{on
"click"
(fn this.updateFormat previewedFormat.format)
}}
>
{{previewedFormat.format}}
</a>
<span class="previewed-format">
{{previewedFormat.preview}}
</span>
</li>
{{/each}}
</ul>
</div>
</div>
{{/unless}}
<div class="control-group timezones">
<label>{{i18n
"discourse_local_dates.create.form.timezones_title"
}}</label>
<p>{{i18n
"discourse_local_dates.create.form.timezones_description"
}}</p>
<div class="controls">
<MultiSelect
@valueProperty={{null}}
@nameProperty={{null}}
@content={{this.allTimezones}}
@value={{this.timezones}}
@options={{hash allowAny=false maximum=5}}
class="timezones-input"
/>
</div>
</div>
<div class="control-group format">
<label>{{i18n
"discourse_local_dates.create.form.format_title"
}}</label>
<p>
{{i18n "discourse_local_dates.create.form.format_description"}}
<a
target="_blank"
href="https://momentjs.com/docs/#/parsing/string-format/"
rel="noopener noreferrer"
>
{{d-icon "circle-question"}}
</a>
</p>
<div class="controls">
<TextField @value={{this.format}} class="format-input" />
</div>
</div>
<div class="control-group">
<ul class="formats">
{{#each this.previewedFormats as |previewedFormat|}}
<li class="format">
<a
class="moment-format"
href
{{on "click" (fn this.updateFormat previewedFormat.format)}}
>
{{previewedFormat.format}}
</a>
<span class="previewed-format">
{{previewedFormat.preview}}
</span>
</li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{/if}}
</div>
</:body>
</:body>
<:footer>
<:footer>
{{#if this.isValid}}
<DButton
@action={{this.save}}
@label="discourse_local_dates.create.form.insert"
class="btn-primary"
/>
{{/if}}
{{#if this.isValid}}
<DButton
@action={{this.save}}
@label="discourse_local_dates.create.form.insert"
class="btn-primary"
/>
{{/if}}
<DButton
@action={{this.cancel}}
@translatedLabel={{i18n "cancel"}}
class="btn-flat"
/>
<DButton
@action={{this.cancel}}
@translatedLabel={{i18n "cancel"}}
class="btn-flat"
/>
<DButton
@action={{this.toggleAdvancedMode}}
@icon="gear"
@label={{this.toggleModeBtnLabel}}
class="btn-default advanced-mode-btn"
/>
</:footer>
</DModal>
<DButton
@action={{this.toggleAdvancedMode}}
@icon="gear"
@label={{this.toggleModeBtnLabel}}
class="btn-default advanced-mode-btn"
/>
</:footer>
</DModal>
</template>
}

View File

@ -1 +1,8 @@
<ComposerPresenceDisplay @model={{@outletArgs.model}} />
import ComposerPresenceDisplay from "discourse/plugins/discourse-presence/discourse/components/composer-presence-display";
const Presence = <template>
<div class="before-composer-controls-outlet presence">
<ComposerPresenceDisplay @model={{@outletArgs.model}} />
</div>
</template>;
export default Presence;

View File

@ -1 +1,8 @@
<TopicPresenceDisplay @topic={{@outletArgs.model}} />
import TopicPresenceDisplay from "discourse/plugins/discourse-presence/discourse/components/topic-presence-display";
const Presence = <template>
<div class="topic-above-footer-buttons-outlet presence">
<TopicPresenceDisplay @topic={{@outletArgs.model}} />
</div>
</template>;
export default Presence;

View File

@ -1,13 +1,21 @@
import Component from "@ember/component";
import { fn, get } from "@ember/helper";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { classify } from "@ember/string";
import { htmlSafe } from "@ember/template";
import { eq } from "truth-helpers";
import DModal from "discourse/components/d-modal";
import concatClass from "discourse/helpers/concat-class";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse/lib/decorators";
import loadScript from "discourse/lib/load-script";
import { i18n } from "discourse-i18n";
import ComboBox from "select-kit/components/combo-box";
import PollBreakdownChart from "discourse/plugins/poll/discourse/components/poll-breakdown-chart";
import PollBreakdownOption from "discourse/plugins/poll/discourse/components/poll-breakdown-option";
export default class PollBreakdownModal extends Component {
@service dialog;
@ -88,85 +96,87 @@ export default class PollBreakdownModal extends Component {
onSelectPanel(panel) {
this.set("displayMode", panel.id);
}
<template>
{{! template-lint-disable no-invalid-interactive }}
<DModal
@title={{i18n "poll.breakdown.title"}}
@closeModal={{@closeModal}}
class="poll-breakdown has-tabs"
>
<:headerBelowTitle>
<ul class="modal-tabs">
<li
class={{concatClass
"modal-tab percentage"
(if (eq this.displayMode "percentage") "is-active")
}}
{{on "click" (fn (mut this.displayMode) "percentage")}}
>{{i18n "poll.breakdown.percentage"}}</li>
<li
class={{concatClass
"modal-tab count"
(if (eq this.displayMode "count") "is-active")
}}
{{on "click" (fn (mut this.displayMode) "count")}}
>{{i18n "poll.breakdown.count"}}</li>
</ul>
</:headerBelowTitle>
<:body>
<div class="poll-breakdown-sidebar">
<p class="poll-breakdown-title">
{{this.title}}
</p>
<div class="poll-breakdown-total-votes">{{i18n
"poll.breakdown.votes"
count=this.model.poll.voters
}}</div>
<ul class="poll-breakdown-options">
{{#each this.model.poll.options as |option index|}}
<PollBreakdownOption
@option={{option}}
@index={{index}}
@totalVotes={{this.totalVotes}}
@optionsCount={{this.model.poll.options.length}}
@displayMode={{this.displayMode}}
@highlightedOption={{this.highlightedOption}}
@onMouseOver={{fn (mut this.highlightedOption) index}}
@onMouseOut={{fn (mut this.highlightedOption) null}}
/>
{{/each}}
</ul>
</div>
<div class="poll-breakdown-body">
<div class="poll-breakdown-body-header">
<label class="poll-breakdown-body-header-label">{{i18n
"poll.breakdown.breakdown"
}}</label>
<ComboBox
@content={{this.groupableUserFields}}
@value={{this.groupedBy}}
@nameProperty="label"
@onChange={{this.setGrouping}}
class="poll-breakdown-dropdown"
/>
</div>
<div class="poll-breakdown-charts">
{{#each this.charts as |chart|}}
<PollBreakdownChart
@group={{get chart "group"}}
@options={{get chart "options"}}
@displayMode={{this.displayMode}}
@highlightedOption={{this.highlightedOption}}
@setHighlightedOption={{fn (mut this.highlightedOption)}}
/>
{{/each}}
</div>
</div>
</:body>
</DModal>
</template>
}
{{! template-lint-disable no-invalid-interactive }}
<DModal
@title={{i18n "poll.breakdown.title"}}
@closeModal={{@closeModal}}
class="poll-breakdown has-tabs"
>
<:headerBelowTitle>
<ul class="modal-tabs">
<li
class={{concat-class
"modal-tab percentage"
(if (eq this.displayMode "percentage") "is-active")
}}
{{on "click" (fn (mut this.displayMode) "percentage")}}
>{{i18n "poll.breakdown.percentage"}}</li>
<li
class={{concat-class
"modal-tab count"
(if (eq this.displayMode "count") "is-active")
}}
{{on "click" (fn (mut this.displayMode) "count")}}
>{{i18n "poll.breakdown.count"}}</li>
</ul>
</:headerBelowTitle>
<:body>
<div class="poll-breakdown-sidebar">
<p class="poll-breakdown-title">
{{this.title}}
</p>
<div class="poll-breakdown-total-votes">{{i18n
"poll.breakdown.votes"
count=this.model.poll.voters
}}</div>
<ul class="poll-breakdown-options">
{{#each this.model.poll.options as |option index|}}
<PollBreakdownOption
@option={{option}}
@index={{index}}
@totalVotes={{this.totalVotes}}
@optionsCount={{this.model.poll.options.length}}
@displayMode={{this.displayMode}}
@highlightedOption={{this.highlightedOption}}
@onMouseOver={{fn (mut this.highlightedOption) index}}
@onMouseOut={{fn (mut this.highlightedOption) null}}
/>
{{/each}}
</ul>
</div>
<div class="poll-breakdown-body">
<div class="poll-breakdown-body-header">
<label class="poll-breakdown-body-header-label">{{i18n
"poll.breakdown.breakdown"
}}</label>
<ComboBox
@content={{this.groupableUserFields}}
@value={{this.groupedBy}}
@nameProperty="label"
@onChange={{this.setGrouping}}
class="poll-breakdown-dropdown"
/>
</div>
<div class="poll-breakdown-charts">
{{#each this.charts as |chart|}}
<PollBreakdownChart
@group={{get chart "group"}}
@options={{get chart "options"}}
@displayMode={{this.displayMode}}
@highlightedOption={{this.highlightedOption}}
@setHighlightedOption={{fn (mut this.highlightedOption)}}
/>
{{/each}}
</div>
</div>
</:body>
</DModal>

View File

@ -1,10 +1,24 @@
import Component from "@ember/component";
import Component, { Input, Textarea } from "@ember/component";
import { fn } from "@ember/helper";
import { on } from "@ember/modifier";
import EmberObject, { action } from "@ember/object";
import { gt, or } from "@ember/object/computed";
import { service } from "@ember/service";
import { observes } from "@ember-decorators/object";
import { and, not } from "truth-helpers";
import DButton from "discourse/components/d-button";
import DModal from "discourse/components/d-modal";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import DateTimeInput from "discourse/components/date-time-input";
import InputTip from "discourse/components/input-tip";
import RadioButton from "discourse/components/radio-button";
import concatClass from "discourse/helpers/concat-class";
import icon from "discourse/helpers/d-icon";
import discourseComputed from "discourse/lib/decorators";
import autoFocus from "discourse/modifiers/auto-focus";
import { i18n } from "discourse-i18n";
import ComboBox from "select-kit/components/combo-box";
import GroupChooser from "select-kit/components/group-chooser";
export const BAR_CHART_TYPE = "bar";
export const PIE_CHART_TYPE = "pie";
@ -396,275 +410,277 @@ export default class PollUiBuilderModal extends Component {
togglePublic() {
this.set("publicPoll", !this.publicPoll);
}
}
<DModal
@title={{i18n "poll.ui_builder.title"}}
@closeModal={{@closeModal}}
@inline={{@inline}}
class="poll-ui-builder"
>
<:body>
<ul class="nav nav-pills poll-type">
<li>
<DButton
@action={{fn this.updatePollType "regular"}}
class={{concatClass
"poll-type-value poll-type-value-regular"
(if this.isRegular "active")
}}
>
{{i18n "poll.ui_builder.poll_type.regular"}}
</DButton>
</li>
<li>
<DButton
@action={{fn this.updatePollType "multiple"}}
class={{concatClass
"poll-type-value poll-type-value-multiple"
(if this.isMultiple "active")
}}
>
{{i18n "poll.ui_builder.poll_type.multiple"}}
</DButton>
</li>
{{#if this.showNumber}}
<li>
<DButton
@action={{fn this.updatePollType "number"}}
class={{concatClass
"poll-type-value poll-type-value-number"
(if this.isNumber "active")
}}
>
{{i18n "poll.ui_builder.poll_type.number"}}
</DButton>
</li>
{{/if}}
{{#if this.showRankedChoice}}
<li>
<DButton
@action={{fn this.updatePollType "ranked_choice"}}
class={{concatClass
"poll-type-value poll-type-value-ranked-choice"
(if this.isRankedChoice "active")
}}
>
{{i18n "poll.ui_builder.poll_type.ranked_choice"}}
</DButton>
</li>
{{/if}}
</ul>
{{#if this.showAdvanced}}
<div class="input-group poll-title">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_title.label"
}}</label>
<Input @value={{this.pollTitle}} />
</div>
{{/if}}
{{#unless this.isNumber}}
<div class="poll-options">
{{#if this.showAdvanced}}
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_options.label"
}}</label>
<Textarea
@value={{this.pollOptionsText}}
{{on "input" this.onOptionsTextChange}}
/>
{{#if this.showMinNumOfOptionsValidation}}
{{#unless this.minNumOfOptionsValidation.ok}}
<InputTip @validation={{this.minNumOfOptionsValidation}} />
{{/unless}}
{{/if}}
{{else}}
{{#each this.pollOptions as |option index|}}
<div class="input-group poll-option-value">
<input
type="text"
value={{option.value}}
{{auto-focus}}
{{on "input" (fn this.updateValue option)}}
{{on "keydown" (fn this.onInputKeydown index)}}
/>
{{#if this.canRemoveOption}}
<DButton
@icon="trash-can"
@action={{fn this.removeOption option}}
/>
{{/if}}
</div>
{{/each}}
<div class="poll-option-controls">
<template>
<DModal
@title={{i18n "poll.ui_builder.title"}}
@closeModal={{@closeModal}}
@inline={{@inline}}
class="poll-ui-builder"
>
<:body>
<ul class="nav nav-pills poll-type">
<li>
<DButton
@icon="plus"
@label="poll.ui_builder.poll_options.add"
@action={{fn this.addOption -1}}
class="btn-default poll-option-add"
/>
{{#if
(and
this.showMinNumOfOptionsValidation
(not this.minNumOfOptionsValidation.ok)
)
}}
<InputTip @validation={{this.minNumOfOptionsValidation}} />
@action={{fn this.updatePollType "regular"}}
class={{concatClass
"poll-type-value poll-type-value-regular"
(if this.isRegular "active")
}}
>
{{i18n "poll.ui_builder.poll_type.regular"}}
</DButton>
</li>
<li>
<DButton
@action={{fn this.updatePollType "multiple"}}
class={{concatClass
"poll-type-value poll-type-value-multiple"
(if this.isMultiple "active")
}}
>
{{i18n "poll.ui_builder.poll_type.multiple"}}
</DButton>
</li>
{{#if this.showNumber}}
<li>
<DButton
@action={{fn this.updatePollType "number"}}
class={{concatClass
"poll-type-value poll-type-value-number"
(if this.isNumber "active")
}}
>
{{i18n "poll.ui_builder.poll_type.number"}}
</DButton>
</li>
{{/if}}
{{#if this.showRankedChoice}}
<li>
<DButton
@action={{fn this.updatePollType "ranked_choice"}}
class={{concatClass
"poll-type-value poll-type-value-ranked-choice"
(if this.isRankedChoice "active")
}}
>
{{i18n "poll.ui_builder.poll_type.ranked_choice"}}
</DButton>
</li>
{{/if}}
</ul>
{{#if this.showAdvanced}}
<div class="input-group poll-title">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_title.label"
}}</label>
<Input @value={{this.pollTitle}} />
</div>
{{/if}}
{{#unless this.isNumber}}
<div class="poll-options">
{{#if this.showAdvanced}}
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_options.label"
}}</label>
<Textarea
@value={{this.pollOptionsText}}
{{on "input" this.onOptionsTextChange}}
/>
{{#if this.showMinNumOfOptionsValidation}}
{{#unless this.minNumOfOptionsValidation.ok}}
<InputTip @validation={{this.minNumOfOptionsValidation}} />
{{/unless}}
{{/if}}
{{else}}
{{#each this.pollOptions as |option index|}}
<div class="input-group poll-option-value">
<input
type="text"
value={{option.value}}
{{autoFocus}}
{{on "input" (fn this.updateValue option)}}
{{on "keydown" (fn this.onInputKeydown index)}}
/>
{{#if this.canRemoveOption}}
<DButton
@icon="trash-can"
@action={{fn this.removeOption option}}
/>
{{/if}}
</div>
{{/each}}
<div class="poll-option-controls">
<DButton
@icon="plus"
@label="poll.ui_builder.poll_options.add"
@action={{fn this.addOption -1}}
class="btn-default poll-option-add"
/>
{{#if
(and
this.showMinNumOfOptionsValidation
(not this.minNumOfOptionsValidation.ok)
)
}}
<InputTip @validation={{this.minNumOfOptionsValidation}} />
{{/if}}
</div>
{{/if}}
</div>
{{/if}}
</div>
{{/unless}}
{{/unless}}
{{#unless this.rankedChoiceOrRegular}}
<div class="options">
<div class="input-group poll-number">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.min"
}}</label>
<Input
@type="number"
@value={{this.pollMin}}
class="poll-options-min"
min="1"
{{#unless this.rankedChoiceOrRegular}}
<div class="options">
<div class="input-group poll-number">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.min"
}}</label>
<Input
@type="number"
@value={{this.pollMin}}
class="poll-options-min"
min="1"
/>
</div>
<div class="input-group poll-number">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.max"
}}</label>
<Input
@type="number"
@value={{this.pollMax}}
class="poll-options-max"
min="1"
/>
</div>
{{#if this.isNumber}}
<div class="input-group poll-number">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.step"
}}</label>
<Input
@type="number"
@value={{this.pollStep}}
min="1"
class="poll-options-step"
/>
</div>
{{/if}}
</div>
{{#unless this.minMaxValueValidation.ok}}
<InputTip @validation={{this.minMaxValueValidation}} />
{{/unless}}
{{/unless}}
<div class="input-group poll-public">
<DToggleSwitch
@state={{this.publicPoll}}
@label="poll.ui_builder.poll_public.label"
class="poll-toggle-public"
{{on "click" this.togglePublic}}
/>
</div>
<div class="input-group poll-number">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.max"
}}</label>
<Input
@type="number"
@value={{this.pollMax}}
class="poll-options-max"
min="1"
/>
</div>
{{#if this.isNumber}}
<div class="input-group poll-number">
{{#if this.showAdvanced}}
<div class="input-group poll-allowed-groups">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_config.step"
"poll.ui_builder.poll_groups.label"
}}</label>
<Input
@type="number"
@value={{this.pollStep}}
min="1"
class="poll-options-step"
<GroupChooser
@content={{this.siteGroups}}
@value={{this.pollGroups}}
@onChange={{fn (mut this.pollGroups)}}
@labelProperty="name"
@valueProperty="name"
/>
</div>
<div class="input-group poll-date">
<label class="input-group-label">{{i18n
"poll.ui_builder.automatic_close.label"
}}</label>
<DateTimeInput
@date={{this.pollAutoClose}}
@onChange={{fn (mut this.pollAutoClose)}}
@clearable={{true}}
@useGlobalPickerContainer={{true}}
/>
</div>
<div class="input-group poll-select">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_result.label"
}}</label>
<ComboBox
@content={{this.pollResults}}
@value={{this.pollResult}}
@valueProperty="value"
@onChange={{fn (mut this.pollResult)}}
class="poll-result"
/>
</div>
{{#unless this.rankedChoiceOrNumber}}
<div class="input-group poll-select column">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_chart_type.label"
}}</label>
<div class="radio-group">
<RadioButton
@id="poll-chart-type-bar"
@name="poll-chart-type"
@value="bar"
@selection={{this.chartType}}
/>
<label for="poll-chart-type-bar">{{icon "chart-bar"}}
{{i18n "poll.ui_builder.poll_chart_type.bar"}}</label>
</div>
<div class="radio-group">
<RadioButton
@id="poll-chart-type-pie"
@name="poll-chart-type"
@value="pie"
@selection={{this.chartType}}
/>
<label for="poll-chart-type-pie">{{icon "chart-pie"}}
{{i18n "poll.ui_builder.poll_chart_type.pie"}}</label>
</div>
</div>
{{/unless}}
{{/if}}
</div>
{{#unless this.minMaxValueValidation.ok}}
<InputTip @validation={{this.minMaxValueValidation}} />
{{/unless}}
{{/unless}}
<div class="input-group poll-public">
<DToggleSwitch
@state={{this.publicPoll}}
@label="poll.ui_builder.poll_public.label"
class="poll-toggle-public"
{{on "click" this.togglePublic}}
/>
</div>
{{#if this.showAdvanced}}
<div class="input-group poll-allowed-groups">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_groups.label"
}}</label>
<GroupChooser
@content={{this.siteGroups}}
@value={{this.pollGroups}}
@onChange={{fn (mut this.pollGroups)}}
@labelProperty="name"
@valueProperty="name"
</:body>
<:footer>
<DButton
@action={{this.insertPoll}}
@icon="chart-bar"
@label="poll.ui_builder.insert"
@disabled={{this.disableInsert}}
class="btn-primary insert-poll"
/>
</div>
<div class="input-group poll-date">
<label class="input-group-label">{{i18n
"poll.ui_builder.automatic_close.label"
}}</label>
<DateTimeInput
@date={{this.pollAutoClose}}
@onChange={{fn (mut this.pollAutoClose)}}
@clearable={{true}}
@useGlobalPickerContainer={{true}}
<DButton @label="cancel" @action={{@closeModal}} class="btn-flat" />
<DButton
@action={{this.toggleAdvanced}}
@icon="gear"
@title={{if
this.showAdvanced
"poll.ui_builder.hide_advanced"
"poll.ui_builder.show_advanced"
}}
class="btn-default show-advanced"
/>
</div>
<div class="input-group poll-select">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_result.label"
}}</label>
<ComboBox
@content={{this.pollResults}}
@value={{this.pollResult}}
@valueProperty="value"
@onChange={{fn (mut this.pollResult)}}
class="poll-result"
/>
</div>
{{#unless this.rankedChoiceOrNumber}}
<div class="input-group poll-select column">
<label class="input-group-label">{{i18n
"poll.ui_builder.poll_chart_type.label"
}}</label>
<div class="radio-group">
<RadioButton
@id="poll-chart-type-bar"
@name="poll-chart-type"
@value="bar"
@selection={{this.chartType}}
/>
<label for="poll-chart-type-bar">{{d-icon "chart-bar"}}
{{i18n "poll.ui_builder.poll_chart_type.bar"}}</label>
</div>
<div class="radio-group">
<RadioButton
@id="poll-chart-type-pie"
@name="poll-chart-type"
@value="pie"
@selection={{this.chartType}}
/>
<label for="poll-chart-type-pie">{{d-icon "chart-pie"}}
{{i18n "poll.ui_builder.poll_chart_type.pie"}}</label>
</div>
</div>
{{/unless}}
{{/if}}
</:body>
<:footer>
<DButton
@action={{this.insertPoll}}
@icon="chart-bar"
@label="poll.ui_builder.insert"
@disabled={{this.disableInsert}}
class="btn-primary insert-poll"
/>
<DButton @label="cancel" @action={{@closeModal}} class="btn-flat" />
<DButton
@action={{this.toggleAdvanced}}
@icon="gear"
@title={{if
this.showAdvanced
"poll.ui_builder.hide_advanced"
"poll.ui_builder.show_advanced"
}}
class="btn-default show-advanced"
/>
</:footer>
</DModal>
</:footer>
</DModal>
</template>
}

View File

@ -1,13 +1,15 @@
import { click, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { i18n } from "discourse-i18n";
import PollButtonsDropdown from "discourse/plugins/poll/discourse/components/poll-buttons-dropdown";
module("Poll | Component | poll-buttons-dropdown", function (hooks) {
setupRenderingTest(hooks);
test("Renders a clickable dropdown menu with a close option", async function (assert) {
const self = this;
this.siteSettings.data_explorer_enabled = true;
this.siteSettings.poll_export_data_explorer_query_id = 18;
this.currentUser.setProperties({ admin: true });
@ -23,16 +25,20 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
dropDownClick: () => {},
});
await render(hbs`<PollButtonsDropdown
@closed={{this.closed}}
@voters={{this.voters}}
@isStaff={{this.isStaff}}
@isMe={{this.isMe}}
@topicArchived={{this.topicArchived}}
@groupableUserFields={{this.groupableUserFields}}
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
@dropDownClick={{this.dropDownClick}}
/>`);
await render(
<template>
<PollButtonsDropdown
@closed={{self.closed}}
@voters={{self.voters}}
@isStaff={{self.isStaff}}
@isMe={{self.isMe}}
@topicArchived={{self.topicArchived}}
@groupableUserFields={{self.groupableUserFields}}
@isAutomaticallyClosed={{self.isAutomaticallyClosed}}
@dropDownClick={{self.dropDownClick}}
/>
</template>
);
await click(".widget-dropdown-header");
@ -46,6 +52,8 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
});
test("Renders a show-tally button when poll is a bar chart", async function (assert) {
const self = this;
this.setProperties({
closed: false,
voters: 2,
@ -58,17 +66,21 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
availableDisplayMode: "showTally",
});
await render(hbs`<PollButtonsDropdown
@closed={{this.closed}}
@voters={{this.voters}}
@isStaff={{this.isStaff}}
@isMe={{this.isMe}}
@topicArchived={{this.topicArchived}}
@groupableUserFields={{this.groupableUserFields}}
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
@dropDownClick={{this.dropDownClick}}
@availableDisplayMode={{this.availableDisplayMode}}
/>`);
await render(
<template>
<PollButtonsDropdown
@closed={{self.closed}}
@voters={{self.voters}}
@isStaff={{self.isStaff}}
@isMe={{self.isMe}}
@topicArchived={{self.topicArchived}}
@groupableUserFields={{self.groupableUserFields}}
@isAutomaticallyClosed={{self.isAutomaticallyClosed}}
@dropDownClick={{self.dropDownClick}}
@availableDisplayMode={{self.availableDisplayMode}}
/>
</template>
);
await click(".widget-dropdown-header");
@ -82,6 +94,8 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
});
test("Renders a single button when there is only one authorised action", async function (assert) {
const self = this;
this.setProperties({
closed: false,
voters: 2,
@ -93,16 +107,20 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
dropDownClick: () => {},
});
await render(hbs`<PollButtonsDropdown
@closed={{this.closed}}
@voters={{this.voters}}
@isStaff={{this.isStaff}}
@isMe={{this.isMe}}
@topicArchived={{this.topicArchived}}
@groupableUserFields={{this.groupableUserFields}}
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
@dropDownClick={{this.dropDownClick}}
/>`);
await render(
<template>
<PollButtonsDropdown
@closed={{self.closed}}
@voters={{self.voters}}
@isStaff={{self.isStaff}}
@isMe={{self.isMe}}
@topicArchived={{self.topicArchived}}
@groupableUserFields={{self.groupableUserFields}}
@isAutomaticallyClosed={{self.isAutomaticallyClosed}}
@dropDownClick={{self.dropDownClick}}
/>
</template>
);
assert.dom(".widget-dropdown-header").doesNotExist();
assert.dom("button.widget-button").exists({ count: 1 });
@ -115,6 +133,8 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
});
test("Doesn't render a button when user has no authorised actions", async function (assert) {
const self = this;
this.setProperties({
closed: false,
voters: 0,
@ -126,16 +146,20 @@ module("Poll | Component | poll-buttons-dropdown", function (hooks) {
dropDownClick: () => {},
});
await render(hbs`<PollButtonsDropdown
@closed={{this.closed}}
@voters={{this.voters}}
@isStaff={{this.isStaff}}
@isMe={{this.isMe}}
@topicArchived={{this.topicArchived}}
@groupableUserFields={{this.groupableUserFields}}
@isAutomaticallyClosed={{this.isAutomaticallyClosed}}
@dropDownClick={{this.dropDownClick}}
/>`);
await render(
<template>
<PollButtonsDropdown
@closed={{self.closed}}
@voters={{self.voters}}
@isStaff={{self.isStaff}}
@isMe={{self.isMe}}
@topicArchived={{self.topicArchived}}
@groupableUserFields={{self.groupableUserFields}}
@isAutomaticallyClosed={{self.isAutomaticallyClosed}}
@dropDownClick={{self.dropDownClick}}
/>
</template>
);
assert.dom(".widget-dropdown-header").doesNotExist();
assert.dom("button.widget-button").doesNotExist();

View File

@ -1,8 +1,8 @@
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { i18n } from "discourse-i18n";
import PollInfo from "discourse/plugins/poll/discourse/components/poll-info";
const OPTIONS = [
{ id: "1ddc47be0d2315b9711ee8526ca9d83f", html: "This", votes: 2, rank: 0 },
@ -14,6 +14,8 @@ module("Poll | Component | poll-info", function (hooks) {
setupRenderingTest(hooks);
test("public multiple poll with results anytime", async function (assert) {
const self = this;
this.setProperties({
isMultiple: true,
min: 1,
@ -29,20 +31,24 @@ module("Poll | Component | poll-info", function (hooks) {
voters: [],
});
await render(hbs`<PollInfo
@options={{this.options}}
@min={{this.min}}
@max={{this.max}}
@isMultiple={{this.isMultiple}}
@close={{this.close}}
@closed={{this.closed}}
@results={{this.results}}
@showResults={{this.showResults}}
@postUserId={{this.postUserId}}
@isPublic={{this.isPublic}}
@hasVoted={{this.hasVoted}}
@voters={{this.voters}}
/>`);
await render(
<template>
<PollInfo
@options={{self.options}}
@min={{self.min}}
@max={{self.max}}
@isMultiple={{self.isMultiple}}
@close={{self.close}}
@closed={{self.closed}}
@results={{self.results}}
@showResults={{self.showResults}}
@postUserId={{self.postUserId}}
@isPublic={{self.isPublic}}
@hasVoted={{self.hasVoted}}
@voters={{self.voters}}
/>
</template>
);
assert.dom(".poll-info_instructions li.multiple-help-text").hasText(
i18n("poll.multiple.help.up_to_max_options", {
@ -60,6 +66,8 @@ module("Poll | Component | poll-info", function (hooks) {
});
test("public multiple poll with results only shown on vote", async function (assert) {
const self = this;
this.setProperties({
isMultiple: true,
min: 1,
@ -75,20 +83,24 @@ module("Poll | Component | poll-info", function (hooks) {
voters: [],
});
await render(hbs`<PollInfo
@options={{this.options}}
@min={{this.min}}
@max={{this.max}}
@isMultiple={{this.isMultiple}}
@close={{this.close}}
@closed={{this.closed}}
@results={{this.results}}
@showResults={{this.showResults}}
@postUserId={{this.postUserId}}
@isPublic={{this.isPublic}}
@hasVoted={{this.hasVoted}}
@voters={{this.voters}}
/>`);
await render(
<template>
<PollInfo
@options={{self.options}}
@min={{self.min}}
@max={{self.max}}
@isMultiple={{self.isMultiple}}
@close={{self.close}}
@closed={{self.closed}}
@results={{self.results}}
@showResults={{self.showResults}}
@postUserId={{self.postUserId}}
@isPublic={{self.isPublic}}
@hasVoted={{self.hasVoted}}
@voters={{self.voters}}
/>
</template>
);
assert.dom(".poll-info_instructions li.multiple-help-text").hasText(
i18n("poll.multiple.help.up_to_max_options", {

View File

@ -1,8 +1,8 @@
import { click, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { i18n } from "discourse-i18n";
import PollOptions from "discourse/plugins/poll/discourse/components/poll-options";
const OPTIONS = [
{ id: "1ddc47be0d2315b9711ee8526ca9d83f", html: "This", votes: 0, rank: 0 },
@ -29,6 +29,8 @@ module("Poll | Component | poll-options", function (hooks) {
setupRenderingTest(hooks);
test("single, not selected", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: false,
isRankedChoice: false,
@ -37,19 +39,25 @@ module("Poll | Component | poll-options", function (hooks) {
votes: [],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@isRankedChoice={{this.isRankedChoice}}
@ranked_choice_dropdown_content={{this.ranked_choice_dropdown_content}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@isRankedChoice={{self.isRankedChoice}}
@ranked_choice_dropdown_content={{self.ranked_choice_dropdown_content}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
assert.dom("li .d-icon-far-circle:nth-of-type(1)").exists({ count: 3 });
});
test("single, selected", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: false,
isRankedChoice: false,
@ -58,19 +66,25 @@ module("Poll | Component | poll-options", function (hooks) {
votes: ["6c986ebcde3d5822a6e91a695c388094"],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@isRankedChoice={{this.isRankedChoice}}
@ranked_choice_dropdown_content={{this.ranked_choice_dropdown_content}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@isRankedChoice={{self.isRankedChoice}}
@ranked_choice_dropdown_content={{self.ranked_choice_dropdown_content}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
assert.dom("li .d-icon-circle:nth-of-type(1)").exists({ count: 1 });
});
test("multi, not selected", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: true,
isRankedChoice: false,
@ -79,19 +93,25 @@ module("Poll | Component | poll-options", function (hooks) {
votes: [],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@isRankedChoice={{this.isRankedChoice}}
@ranked_choice_dropdown_content={{this.ranked_choice_dropdown_content}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@isRankedChoice={{self.isRankedChoice}}
@ranked_choice_dropdown_content={{self.ranked_choice_dropdown_content}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
assert.dom("li .d-icon-far-square:nth-of-type(1)").exists({ count: 3 });
});
test("multi, selected", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: true,
isRankedChoice: false,
@ -100,14 +120,18 @@ module("Poll | Component | poll-options", function (hooks) {
votes: ["6c986ebcde3d5822a6e91a695c388094"],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@isRankedChoice={{this.isRankedChoice}}
@ranked_choice_dropdown_content={{this.ranked_choice_dropdown_content}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@isRankedChoice={{self.isRankedChoice}}
@ranked_choice_dropdown_content={{self.ranked_choice_dropdown_content}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
assert
.dom("li .d-icon-far-square-check:nth-of-type(1)")
@ -115,23 +139,31 @@ module("Poll | Component | poll-options", function (hooks) {
});
test("single with images", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: false,
options: IMAGE_OPTIONS,
votes: [],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
assert.dom("li img").exists({ count: 2 });
});
test("ranked choice - priorities", async function (assert) {
const self = this;
this.setProperties({
isCheckbox: false,
isRankedChoice: true,
@ -140,14 +172,18 @@ module("Poll | Component | poll-options", function (hooks) {
votes: [],
});
await render(hbs`<PollOptions
@isCheckbox={{this.isCheckbox}}
@isRankedChoice={{this.isRankedChoice}}
@ranked_choice_dropdown_content={{this.ranked_choice_dropdown_content}}
@options={{this.options}}
@votes={{this.votes}}
@sendRadioClick={{this.toggleOption}}
/>`);
await render(
<template>
<PollOptions
@isCheckbox={{self.isCheckbox}}
@isRankedChoice={{self.isRankedChoice}}
@ranked_choice_dropdown_content={{self.ranked_choice_dropdown_content}}
@options={{self.options}}
@votes={{self.votes}}
@sendRadioClick={{self.toggleOption}}
/>
</template>
);
await click(
`.ranked-choice-poll-option[data-poll-option-id='${OPTIONS[0].id}'] button`

View File

@ -1,7 +1,7 @@
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import PollResultsPie from "discourse/plugins/poll/discourse/components/poll-results-pie";
const OPTIONS = [
{ id: "1ddc47be0d2315b9711ee8526ca9d83f", html: "This", votes: 3, rank: 0 },
@ -15,13 +15,17 @@ module("Poll | Component | poll-results-pie", function (hooks) {
setupRenderingTest(hooks);
test("Renders the pie chart Component correctly", async function (assert) {
const self = this;
this.setProperties({
id: ID,
options: OPTIONS,
});
await render(
hbs`<PollResultsPie @id={{this.id}} @options={{this.options}} />`
<template>
<PollResultsPie @id={{self.id}} @options={{self.options}} />
</template>
);
assert.dom("li.legend").exists({ count: 3 });

View File

@ -1,8 +1,8 @@
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { i18n } from "discourse-i18n";
import PollResultsRankedChoice from "discourse/plugins/poll/discourse/components/poll-results-ranked-choice";
const RANKED_CHOICE_OUTCOME = {
tied: false,
@ -34,12 +34,18 @@ module("Poll | Component | poll-results-ranked-choice", function (hooks) {
setupRenderingTest(hooks);
test("Renders the ranked choice results component correctly", async function (assert) {
const self = this;
this.setProperties({
rankedChoiceOutcome: RANKED_CHOICE_OUTCOME,
});
await render(
hbs`<PollResultsRankedChoice @rankedChoiceOutcome={{this.rankedChoiceOutcome}} />`
<template>
<PollResultsRankedChoice
@rankedChoiceOutcome={{self.rankedChoiceOutcome}}
/>
</template>
);
assert
@ -56,10 +62,16 @@ module("Poll | Component | poll-results-ranked-choice", function (hooks) {
});
test("Renders the ranked choice results component without error when outcome data is empty", async function (assert) {
const self = this;
this.rankedChoiceOutcome = null;
await render(
hbs`<PollResultsRankedChoice @rankedChoiceOutcome={{this.rankedChoiceOutcome}} />`
<template>
<PollResultsRankedChoice
@rankedChoiceOutcome={{self.rankedChoiceOutcome}}
/>
</template>
);
assert

View File

@ -1,9 +1,9 @@
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { queryAll } from "discourse/tests/helpers/qunit-helpers";
import { i18n } from "discourse-i18n";
import PollResultsStandard from "discourse/plugins/poll/discourse/components/poll-results-standard";
const TWO_OPTIONS = [
{ id: "1ddc47be0d2315b9711ee8526ca9d83f", html: "This", votes: 5, rank: 0 },
@ -38,6 +38,8 @@ module("Poll | Component | poll-results-standard", function (hooks) {
setupRenderingTest(hooks);
test("Renders the standard results Component correctly", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS,
pollName: "Two Choice Poll",
@ -50,17 +52,21 @@ module("Poll | Component | poll-results-standard", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsStandard
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@isPublic={{this.isPublic}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsStandard
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@isPublic={{self.isPublic}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom(queryAll(".option .percentage")[0]).hasText("56%");
assert.dom(queryAll(".option .percentage")[1]).hasText("44%");
@ -68,6 +74,8 @@ module("Poll | Component | poll-results-standard", function (hooks) {
});
test("Omits voters for private polls", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS,
pollName: "Two Choice Poll",
@ -80,22 +88,28 @@ module("Poll | Component | poll-results-standard", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsStandard
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@isPublic={{this.isPublic}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsStandard
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@isPublic={{self.isPublic}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom("ul.poll-voters-list").doesNotExist();
});
test("options in ascending order", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS_REVERSED,
pollName: "Two Choice Poll",
@ -107,22 +121,28 @@ module("Poll | Component | poll-results-standard", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsStandard
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsStandard
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom(queryAll(".option .percentage")[0]).hasText("56%");
assert.dom(queryAll(".option .percentage")[1]).hasText("44%");
});
test("options in ascending order", async function (assert) {
const self = this;
this.setProperties({
options: FIVE_OPTIONS,
pollName: "Five Multi Option Poll",
@ -134,16 +154,20 @@ module("Poll | Component | poll-results-standard", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsStandard
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsStandard
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
let percentages = queryAll(".option .percentage");
assert.dom(percentages[0]).hasText("41%");
@ -157,6 +181,8 @@ module("Poll | Component | poll-results-standard", function (hooks) {
});
test("options in ascending order, showing absolute vote number", async function (assert) {
const self = this;
this.setProperties({
options: FIVE_OPTIONS,
pollName: "Five Multi Option Poll",
@ -169,17 +195,21 @@ module("Poll | Component | poll-results-standard", function (hooks) {
showTally: true,
});
await render(hbs`<PollResultsStandard
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
@showTally={{this.showTally}}
/>`);
await render(
<template>
<PollResultsStandard
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
@showTally={{self.showTally}}
/>
</template>
);
let percentages = queryAll(".option .absolute");
assert.dom(percentages[0]).hasText(i18n("poll.votes", { count: 5 }));

View File

@ -1,7 +1,7 @@
import { render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import PollResultsTabs from "discourse/plugins/poll/discourse/components/poll-results-tabs";
const TWO_OPTIONS = [
{
@ -59,6 +59,8 @@ module("Poll | Component | poll-results-tabs", function (hooks) {
setupRenderingTest(hooks);
test("Renders one tab for non-ranked-choice poll", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS,
pollName: "Two Choice Poll",
@ -72,23 +74,29 @@ module("Poll | Component | poll-results-tabs", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsTabs
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@isPublic={{this.isPublic}}
@isRankedChoice={{this.isRankedChoice}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsTabs
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@isPublic={{self.isPublic}}
@isRankedChoice={{self.isRankedChoice}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom("li.tab").exists({ count: 1 });
});
test("Renders two tabs for public ranked choice poll", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS,
pollName: "Two Choice Poll",
@ -103,24 +111,30 @@ module("Poll | Component | poll-results-tabs", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsTabs
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@isPublic={{this.isPublic}}
@isRankedChoice={{this.isRankedChoice}}
@rankedChoiceOutcome={{this.rankedChoiceOutcome}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsTabs
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@isPublic={{self.isPublic}}
@isRankedChoice={{self.isRankedChoice}}
@rankedChoiceOutcome={{self.rankedChoiceOutcome}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom("li.tab").exists({ count: 2 });
});
test("Renders one tab for private ranked choice poll", async function (assert) {
const self = this;
this.setProperties({
options: TWO_OPTIONS,
pollName: "Two Choice Poll",
@ -135,19 +149,23 @@ module("Poll | Component | poll-results-tabs", function (hooks) {
fetchVoters: () => {},
});
await render(hbs`<PollResultsTabs
@options={{this.options}}
@pollName={{this.pollName}}
@pollType={{this.pollType}}
@isPublic={{this.isPublic}}
@isRankedChoice={{this.isRankedChoice}}
@rankedChoiceOutcome={{this.rankedChoiceOutcome}}
@postId={{this.postId}}
@vote={{this.vote}}
@voters={{this.voters}}
@votersCount={{this.votersCount}}
@fetchVoters={{this.fetchVoters}}
/>`);
await render(
<template>
<PollResultsTabs
@options={{self.options}}
@pollName={{self.pollName}}
@pollType={{self.pollType}}
@isPublic={{self.isPublic}}
@isRankedChoice={{self.isRankedChoice}}
@rankedChoiceOutcome={{self.rankedChoiceOutcome}}
@postId={{self.postId}}
@vote={{self.vote}}
@voters={{self.voters}}
@votersCount={{self.votersCount}}
@fetchVoters={{self.fetchVoters}}
/>
</template>
);
assert.dom("li.tab").exists({ count: 1 });
});

View File

@ -1,11 +1,11 @@
import EmberObject from "@ember/object";
import { click, render } from "@ember/test-helpers";
import { TrackedObject } from "@ember-compat/tracked-built-ins";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import { i18n } from "discourse-i18n";
import Poll from "discourse/plugins/poll/discourse/components/poll";
let requests = 0;
@ -42,6 +42,8 @@ module("Poll | Component | poll", function (hooks) {
});
test("valid ranks with which you can vote", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -96,13 +98,17 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
assert.dom(".poll-buttons .cast-votes:disabled").doesNotExist();
assert.dom(".poll-buttons .cast-votes").exists();
});
test("invalid ranks with which you cannot vote", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -141,7 +147,9 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
await click(
".ranked-choice-poll-option[data-poll-option-id='1f972d1df351de3ce35a787c89faad29'] button",
@ -171,6 +179,8 @@ module("Poll | Component | poll", function (hooks) {
});
test("shows vote", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -193,13 +203,17 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
assert.dom(".results li:nth-of-type(1) .option p").hasText("100% yes");
assert.dom(".results li:nth-of-type(2) .option p").hasText("0% no");
});
test("does not show results after voting when results are to be shown only on closed", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -222,13 +236,17 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
assert.dom("ul.options").exists("options are shown");
assert.dom("ul.results").doesNotExist("results are not shown");
});
test("can vote", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -251,7 +269,9 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
requests = 0;
@ -268,6 +288,8 @@ module("Poll | Component | poll", function (hooks) {
});
test("cannot vote if not member of the right group", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -291,7 +313,9 @@ module("Poll | Component | poll", function (hooks) {
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
requests = 0;
@ -306,6 +330,8 @@ module("Poll | Component | poll", function (hooks) {
});
test("voting on a multiple poll with no min attribute", async function (assert) {
const self = this;
this.setProperties({
post: EmberObject.create({
id: 42,
@ -328,7 +354,9 @@ module("Poll | Component | poll", function (hooks) {
chart_type: "bar",
}),
});
await render(hbs`<Poll @post={{this.post}} @poll={{this.poll}} />`);
await render(
<template><Poll @post={{self.post}} @poll={{self.poll}} /></template>
);
assert.dom(".poll-buttons .cast-votes").isDisabled();

View File

@ -1,18 +1,22 @@
import { click, fillIn, render } from "@ember/test-helpers";
import hbs from "htmlbars-inline-precompile";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import PollUiBuilder from "discourse/plugins/poll/discourse/components/modal/poll-ui-builder";
async function setupBuilder(context) {
async function setupBuilder() {
const noop = () => {};
const results = [];
const model = {
toolbarEvent: { getText: () => "", addText: (t) => results.push(t) },
};
context.model = model;
await render(
hbs`<Modal::PollUiBuilder @inline={{true}} @model={{this.model}} @closeModal={{fn (mut this.closeCalled) true}} />`
<template>
<PollUiBuilder @inline={{true}} @model={{model}} @closeModal={{noop}} />
</template>
);
return results;
}
@ -20,7 +24,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
setupRenderingTest(hooks);
test("Can switch poll type", async function (assert) {
await setupBuilder(this);
await setupBuilder();
assert.dom(".poll-type-value-regular").hasClass("active");
@ -45,7 +49,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
});
test("Automatically updates min/max when number of options change", async function (assert) {
await setupBuilder(this);
await setupBuilder();
await click(".poll-type-value-multiple");
assert.dom(".poll-options-min").hasValue("0");
@ -65,7 +69,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
test("disables save button", async function (assert) {
this.siteSettings.poll_maximum_options = 3;
await setupBuilder(this);
await setupBuilder();
assert
.dom(".insert-poll")
.isDisabled("Insert button disabled when no options specified");
@ -88,7 +92,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
});
test("number mode", async function (assert) {
const results = await setupBuilder(this);
const results = await setupBuilder();
await click(".show-advanced");
await click(".poll-type-value-number");
@ -122,7 +126,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
});
test("regular mode", async function (assert) {
const results = await setupBuilder(this);
const results = await setupBuilder();
await fillIn(".poll-option-value input", "a");
await click(".poll-option-add");
@ -160,7 +164,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
});
test("multi-choice mode", async function (assert) {
const results = await setupBuilder(this);
const results = await setupBuilder();
await click(".poll-type-value-multiple");
@ -188,7 +192,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
});
test("staff_only option is not present for non-staff", async function (assert) {
await setupBuilder(this);
await setupBuilder();
await click(".show-advanced");
const resultVisibility = selectKit(".poll-result");
@ -215,7 +219,7 @@ module("Poll | Component | poll-ui-builder", function (hooks) {
test("default public value can be controlled with site setting", async function (assert) {
this.siteSettings.poll_default_public = false;
const results = await setupBuilder(this);
const results = await setupBuilder();
await fillIn(".poll-option-value input", "a");
await click(".poll-option-add");

View File

@ -1,4 +1,7 @@
<section class="color-example">
<div class="color-bg {{@color}}"></div>
<div class="color-name">var(--{{@color}})</div>
</section>
const ColorExample = <template>
<section class="color-example">
<div class="color-bg {{@color}}"></div>
<div class="color-name">var(--{{@color}})</div>
</section>
</template>;
export default ColorExample;

View File

@ -1,114 +1,121 @@
<div class="section-description">
<p>
Discourse users can select from 4 different text sizes in their user
settings, by default these are:
<pre>
import { i18n } from "discourse-i18n";
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
const FontScale = <template>
<div class="section-description">
<p>
Discourse users can select from 4 different text sizes in their user
settings, by default these are:
<pre>
Smaller: 14px Normal: 15px
<span
>(default)</span>
>(default)</span>
Larger: 17px Largest: 19px
</pre>
</p>
</p>
<p>
If you'd like to increase the font size of your entire Discourse community,
you can override the font-size of the HTML element. You can also provide
different font sizes for the user text size settings defined above. The
example below increases all text size options by 1px.
<pre>
<p>
If you'd like to increase the font size of your entire Discourse
community, you can override the font-size of the HTML element. You can
also provide different font sizes for the user text size settings defined
above. The example below increases all text size options by 1px.
<pre>
html {
<span
class="hljs-attribute"
>font-size</span>: 16px;
class="hljs-attribute"
>font-size</span>: 16px;
<span>// default font-size
</span>
</span>
&.text-size-smaller {
<span
class="hljs-attribute"
>font-size</span>: 15px; } &.text-size-larger
class="hljs-attribute"
>font-size</span>: 15px; } &.text-size-larger
{
<span
class="hljs-attribute"
>font-size</span>: 18px; } &.text-size-largest
class="hljs-attribute"
>font-size</span>: 18px; } &.text-size-largest
{
<span
class="hljs-attribute"
>font-size</span>: 20px; } }
class="hljs-attribute"
>font-size</span>: 20px; } }
</pre>
</p>
<p>
If you want to scale the fonts of a specific element, you can use
Discourse's font scaling variables. Using the variable system ensures you're
using a consistent set of font-sizes throughout your community.
<p>
Changing the font-size of a parent element will proportionately scale the
font sizes of all its children.
</p>
<pre>
<p>
If you want to scale the fonts of a specific element, you can use
Discourse's font scaling variables. Using the variable system ensures
you're using a consistent set of font-sizes throughout your community.
<p>
Changing the font-size of a parent element will proportionately scale
the font sizes of all its children.
</p>
<pre>
.parent {
<span
class="hljs-attribute"
>font-size</span>: var(--font-up-3);
<span>// Increases the relative
font-size of this element and its children by 3 steps in the scale</span>
class="hljs-attribute"
>font-size</span>: var(--font-up-3);
<span>// Increases the
relative font-size of this element and its children by 3 steps in the
scale</span>
.child {
<span
>// If this is set to var(--font-down-3) in Discourse's default CSS, the
parent font-size increase above would make this equivalent to
var(--font-0) (var(--font-down-3) + var(--font-up-3) = var(--font-0))</span>
<span>// If this is set to
var(--font-down-3) in Discourse's default CSS, the parent font-size
increase above would make this equivalent to var(--font-0)
(var(--font-down-3) + var(--font-up-3) = var(--font-0))</span>
} }
</pre>
</p>
</div>
</p>
</div>
<StyleguideExample @title="var(--font-up-6), 2.296em">
<p class="font-up-6">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-6), 2.296em">
<p class="font-up-6">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-5), 2em">
<p class="font-up-5">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-5), 2em">
<p class="font-up-5">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-4), 1.7511em">
<p class="font-up-4">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-4), 1.7511em">
<p class="font-up-4">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-3), 1.5157em">
<p class="font-up-3">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-3), 1.5157em">
<p class="font-up-3">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-2), 1.3195em">
<p class="font-up-2">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-2), 1.3195em">
<p class="font-up-2">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-1), 1.1487em">
<p class="font-up-1">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-up-1), 1.1487em">
<p class="font-up-1">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-0), 1em — base font">
<p class="font-0">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-0), 1em — base font">
<p class="font-0">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-1), 0.8706em">
<p class="font-down-1">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-1), 0.8706em">
<p class="font-down-1">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-2), 0.7579em">
<p class="font-down-2">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-2), 0.7579em">
<p class="font-down-2">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-3), 0.6599em">
<p class="font-down-3">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-3), 0.6599em">
<p class="font-down-3">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-4), 0.5745em">
<p class="font-down-4">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-4), 0.5745em">
<p class="font-down-4">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-5), 0.5em">
<p class="font-down-5">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-5), 0.5em">
<p class="font-down-5">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-6), 0.4355em">
<p class="font-down-6">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
<StyleguideExample @title="var(--font-down-6), 0.4355em">
<p class="font-down-6">{{i18n "styleguide.sections.typography.example"}}</p>
</StyleguideExample>
</template>;
export default FontScale;

View File

@ -1,175 +1,187 @@
<StyleguideExample @title=".btn-icon - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="xmark"
@translatedTitle={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
import { fn } from "@ember/helper";
import { on } from "@ember/modifier";
import { not } from "truth-helpers";
import DButton from "discourse/components/d-button";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import FlatButton from "discourse/components/flat-button";
import concatClass from "discourse/helpers/concat-class";
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
<StyleguideExample @title=".btn-icon - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="xmark"
@translatedTitle={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
const Buttons = <template>
<StyleguideExample @title=".btn-icon - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="xmark"
@translatedTitle={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-text - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-icon - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="xmark"
@translatedTitle={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-text - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-default .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-default .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-default .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-primary .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concat-class "btn-primary" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-default .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-primary .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concat-class "btn-primary" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-primary .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concatClass "btn-primary" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-danger .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="trash-can"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concat-class "btn-danger" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-primary .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="plus"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concatClass "btn-primary" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-danger .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="trash-can"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concat-class "btn-danger" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title=".btn-danger .btn-icon-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@icon="trash-can"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concatClass "btn-danger" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-flat - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<FlatButton
@icon="trash-can"
@disabled={{bs.disabled}}
@translatedTitle={{bs.title}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-danger .btn-icon-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@icon="trash-can"
@translatedLabel={{bs.text}}
@disabled={{bs.disabled}}
class={{concatClass "btn-danger" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-flat - states">
{{#each @dummy.buttonStates as |bs|}}
<FlatButton
@icon="trash-can"
@disabled={{bs.disabled}}
@translatedTitle={{bs.title}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-flat - sizes (large, default, small)">
{{#each @dummy.buttonSizes as |bs|}}
<FlatButton
@icon="trash-can"
@disabled={{bs.disabled}}
@translatedTitle={{bs.title}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title="<DButton> btn-flat btn-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@disabled={{bs.disabled}}
@translatedLabel={{bs.text}}
class={{concat-class "btn-flat" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title=".btn-flat - states">
{{#each @dummy.buttonStates as |bs|}}
<FlatButton
@icon="trash-can"
@disabled={{bs.disabled}}
@translatedTitle={{bs.title}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title="<DButton> btn-flat btn-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@disabled={{bs.disabled}}
@translatedLabel={{bs.text}}
class={{concat-class "btn-flat" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample
@title="<DButton> btn-flat btn-text - sizes (large, default, small)"
>
{{#each @dummy.buttonSizes as |bs|}}
<DButton
@disabled={{bs.disabled}}
@translatedLabel={{bs.text}}
class={{concatClass "btn-flat" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title="<DToggleSwitch>">
<DToggleSwitch
@state={{@dummy.toggleSwitchState}}
{{on
"click"
(fn (mut @dummy.toggleSwitchState) (not @dummy.toggleSwitchState))
}}
/>
<DToggleSwitch
disabled="true"
@state={{true}}
title="Disabled with state=true"
/>
<DToggleSwitch
disabled="true"
@state={{false}}
title="Disabled with state=false"
/>
</StyleguideExample>
<StyleguideExample @title="<DButton> btn-flat btn-text - states">
{{#each @dummy.buttonStates as |bs|}}
<DButton
@disabled={{bs.disabled}}
@translatedLabel={{bs.text}}
class={{concatClass "btn-flat" bs.class}}
/>
{{/each}}
</StyleguideExample>
<StyleguideExample @title="<DToggleSwitch>">
<DToggleSwitch
@state={{@dummy.toggleSwitchState}}
{{on
"click"
(fn (mut @dummy.toggleSwitchState) (not @dummy.toggleSwitchState))
}}
/>
<DToggleSwitch
disabled="true"
@state={{true}}
title="Disabled with state=true"
/>
<DToggleSwitch
disabled="true"
@state={{false}}
title="Disabled with state=false"
/>
</StyleguideExample>
</template>;
export default Buttons;

View File

@ -1,120 +1,126 @@
<StyleguideExample @title="primary">
<section class="color-row">
<ColorExample @color="primary-very-low" />
<ColorExample @color="primary-low" />
<ColorExample @color="primary-low-mid" />
</section>
<section class="color-row">
<ColorExample @color="primary-medium" />
<ColorExample @color="primary-high" />
<ColorExample @color="primary" />
</section>
</StyleguideExample>
import ColorExample from "discourse/plugins/styleguide/discourse/components/color-example";
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
<StyleguideExample @title="primary-100">
<section class="color-row">
<ColorExample @color="primary-50" />
<ColorExample @color="primary-100" />
<ColorExample @color="primary-200" />
<ColorExample @color="primary-300" />
<ColorExample @color="primary-400" />
<ColorExample @color="primary-500" />
</section>
<section class="color-row">
<ColorExample @color="primary-600" />
<ColorExample @color="primary-700" />
<ColorExample @color="primary-800" />
<ColorExample @color="primary-900" />
<ColorExample @color="primary" />
</section>
</StyleguideExample>
const Colors = <template>
<StyleguideExample @title="primary">
<section class="color-row">
<ColorExample @color="primary-very-low" />
<ColorExample @color="primary-low" />
<ColorExample @color="primary-low-mid" />
</section>
<section class="color-row">
<ColorExample @color="primary-medium" />
<ColorExample @color="primary-high" />
<ColorExample @color="primary" />
</section>
</StyleguideExample>
<StyleguideExample @title="secondary">
<section class="color-row">
<ColorExample @color="secondary-low" />
<ColorExample @color="secondary-medium" />
<ColorExample @color="secondary-high" />
<ColorExample @color="secondary" />
</section>
</StyleguideExample>
<StyleguideExample @title="primary-100">
<section class="color-row">
<ColorExample @color="primary-50" />
<ColorExample @color="primary-100" />
<ColorExample @color="primary-200" />
<ColorExample @color="primary-300" />
<ColorExample @color="primary-400" />
<ColorExample @color="primary-500" />
</section>
<section class="color-row">
<ColorExample @color="primary-600" />
<ColorExample @color="primary-700" />
<ColorExample @color="primary-800" />
<ColorExample @color="primary-900" />
<ColorExample @color="primary" />
</section>
</StyleguideExample>
<StyleguideExample @title="tertiary">
<section class="color-row">
<ColorExample @color="tertiary-low" />
<ColorExample @color="tertiary-medium" />
<ColorExample @color="tertiary-high" />
<ColorExample @color="tertiary" />
</section>
</StyleguideExample>
<StyleguideExample @title="secondary">
<section class="color-row">
<ColorExample @color="secondary-low" />
<ColorExample @color="secondary-medium" />
<ColorExample @color="secondary-high" />
<ColorExample @color="secondary" />
</section>
</StyleguideExample>
<StyleguideExample @title="tertiary-100">
<section class="color-row">
<ColorExample @color="tertiary-50" />
<ColorExample @color="tertiary-100" />
<ColorExample @color="tertiary-200" />
<ColorExample @color="tertiary-300" />
<ColorExample @color="tertiary-400" />
<ColorExample @color="tertiary-500" />
</section>
<section class="color-row">
<ColorExample @color="tertiary-600" />
<ColorExample @color="tertiary-700" />
<ColorExample @color="tertiary-800" />
<ColorExample @color="tertiary-900" />
<ColorExample @color="tertiary" />
</section>
</StyleguideExample>
<StyleguideExample @title="tertiary">
<section class="color-row">
<ColorExample @color="tertiary-low" />
<ColorExample @color="tertiary-medium" />
<ColorExample @color="tertiary-high" />
<ColorExample @color="tertiary" />
</section>
</StyleguideExample>
<StyleguideExample @title="quaternary">
<section class="color-row">
<ColorExample @color="quaternary-low" />
<ColorExample @color="quaternary" />
</section>
</StyleguideExample>
<StyleguideExample @title="tertiary-100">
<section class="color-row">
<ColorExample @color="tertiary-50" />
<ColorExample @color="tertiary-100" />
<ColorExample @color="tertiary-200" />
<ColorExample @color="tertiary-300" />
<ColorExample @color="tertiary-400" />
<ColorExample @color="tertiary-500" />
</section>
<section class="color-row">
<ColorExample @color="tertiary-600" />
<ColorExample @color="tertiary-700" />
<ColorExample @color="tertiary-800" />
<ColorExample @color="tertiary-900" />
<ColorExample @color="tertiary" />
</section>
</StyleguideExample>
<StyleguideExample @title="highlight">
<section class="color-row">
<ColorExample @color="highlight-bg" />
<ColorExample @color="highlight" />
</section>
</StyleguideExample>
<StyleguideExample @title="quaternary">
<section class="color-row">
<ColorExample @color="quaternary-low" />
<ColorExample @color="quaternary" />
</section>
</StyleguideExample>
<StyleguideExample @title="danger">
<section class="color-row">
<ColorExample @color="danger-low" />
<ColorExample @color="danger-low-mid" />
<ColorExample @color="danger-medium" />
<ColorExample @color="danger" />
</section>
</StyleguideExample>
<StyleguideExample @title="highlight">
<section class="color-row">
<ColorExample @color="highlight-bg" />
<ColorExample @color="highlight" />
</section>
</StyleguideExample>
<StyleguideExample @title="success">
<section class="color-row">
<ColorExample @color="success-low" />
<ColorExample @color="success-medium" />
<ColorExample @color="success" />
</section>
</StyleguideExample>
<StyleguideExample @title="danger">
<section class="color-row">
<ColorExample @color="danger-low" />
<ColorExample @color="danger-low-mid" />
<ColorExample @color="danger-medium" />
<ColorExample @color="danger" />
</section>
</StyleguideExample>
<StyleguideExample @title="love">
<section class="color-row">
<ColorExample @color="love-low" />
<ColorExample @color="love" />
</section>
</StyleguideExample>
<StyleguideExample @title="success">
<section class="color-row">
<ColorExample @color="success-low" />
<ColorExample @color="success-medium" />
<ColorExample @color="success" />
</section>
</StyleguideExample>
<StyleguideExample @title="header_primary">
<section class="color-row">
<ColorExample @color="header_background" />
</section>
<section class="color-row">
<ColorExample @color="header_primary" />
<ColorExample @color="header_primary-very-high" />
<ColorExample @color="header_primary-high" />
</section>
<section class="color-row">
<ColorExample @color="header_primary-medium" />
<ColorExample @color="header_primary-low-mid" />
<ColorExample @color="header_primary-low" />
</section>
</StyleguideExample>
<StyleguideExample @title="love">
<section class="color-row">
<ColorExample @color="love-low" />
<ColorExample @color="love" />
</section>
</StyleguideExample>
<StyleguideExample @title="header_primary">
<section class="color-row">
<ColorExample @color="header_background" />
</section>
<section class="color-row">
<ColorExample @color="header_primary" />
<ColorExample @color="header_primary-very-high" />
<ColorExample @color="header_primary-high" />
</section>
<section class="color-row">
<ColorExample @color="header_primary-medium" />
<ColorExample @color="header_primary-low-mid" />
<ColorExample @color="header_primary-low" />
</section>
</StyleguideExample>
</template>;
export default Colors;

View File

@ -1,25 +1,32 @@
<div class="section-description">
<p>Discourse uses a free set of SVG icons from Font Awesome (<a
href="https://fontawesome.com/icons?d=gallery&m=free"
>{{i18n "styleguide.sections.icons.full_list"}}</a>).</p>
<p>Plugins and themes can add SVG icons to the SVG spritesheet, or replace
existing icons entirely.</p>
<p>
<ul>
<li><a
href="https://meta.discourse.org/t/introducing-font-awesome-5-and-svg-icons/101643"
>How to use SVG icons in your plugin or theme</a></li>
<li><a
href="https://meta.discourse.org/t/replace-discourses-default-svg-icons-with-custom-icons-in-a-theme/115736/1"
>How to replace Discourse's default icons in a theme</a></li>
</ul>
</p>
<p>By default, all icons have the
<pre class="pre-inline">.d-icon</pre>
class applied along with a class containing the name of the icon (e.g.,
<pre class="pre-inline">.d-icon-link</pre>)</p>
</div>
import { i18n } from "discourse-i18n";
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
import StyleguideIcons from "discourse/plugins/styleguide/discourse/components/styleguide-icons";
<StyleguideExample @title="d-icon - all available icons">
<StyleguideIcons />
</StyleguideExample>
const Icons = <template>
<div class="section-description">
<p>Discourse uses a free set of SVG icons from Font Awesome (<a
href="https://fontawesome.com/icons?d=gallery&m=free"
>{{i18n "styleguide.sections.icons.full_list"}}</a>).</p>
<p>Plugins and themes can add SVG icons to the SVG spritesheet, or replace
existing icons entirely.</p>
<p>
<ul>
<li><a
href="https://meta.discourse.org/t/introducing-font-awesome-5-and-svg-icons/101643"
>How to use SVG icons in your plugin or theme</a></li>
<li><a
href="https://meta.discourse.org/t/replace-discourses-default-svg-icons-with-custom-icons-in-a-theme/115736/1"
>How to replace Discourse's default icons in a theme</a></li>
</ul>
</p>
<p>By default, all icons have the
<pre class="pre-inline">.d-icon</pre>
class applied along with a class containing the name of the icon (e.g.,
<pre class="pre-inline">.d-icon-link</pre>)</p>
</div>
<StyleguideExample @title="d-icon - all available icons">
<StyleguideIcons />
</StyleguideExample>
</template>;
export default Icons;

View File

@ -1,274 +1,284 @@
<h2>Controls</h2>
<StyleguideExample @title="Input">
<Form as |form|>
<form.Field @title="Username" @name="username" as |field|>
<field.Input placeholder="Username" />
</form.Field>
<form.Field @title="Age" @name="age" as |field|>
<field.Input placeholder="Age" @type="number" @format="small" />
</form.Field>
<form.Field @title="Website" @name="website" as |field|>
<field.Input @before="https://" @after=".com" @format="large" />
</form.Field>
<form.Field @title="After" @name="after" as |field|>
<field.Input @after=".com" />
</form.Field>
<form.Field @title="Before" @name="before" as |field|>
<field.Input @before="https://" />
</form.Field>
<form.Field
@title="Secret"
@name="secret"
@description="An important password"
as |field|
import { array, fn, hash } from "@ember/helper";
import Form from "discourse/components/form";
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
const Forms = <template>
<h2>Controls</h2>
<StyleguideExample @title="Input">
<Form as |form|>
<form.Field @title="Username" @name="username" as |field|>
<field.Input placeholder="Username" />
</form.Field>
<form.Field @title="Age" @name="age" as |field|>
<field.Input placeholder="Age" @type="number" @format="small" />
</form.Field>
<form.Field @title="Website" @name="website" as |field|>
<field.Input @before="https://" @after=".com" @format="large" />
</form.Field>
<form.Field @title="After" @name="after" as |field|>
<field.Input @after=".com" />
</form.Field>
<form.Field @title="Before" @name="before" as |field|>
<field.Input @before="https://" />
</form.Field>
<form.Field
@title="Secret"
@name="secret"
@description="An important password"
as |field|
>
<field.Password />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Question">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Question />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Toggle">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Toggle />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Composer">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Composer />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Code">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Code />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Textarea">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Textarea />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Select">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Select as |select|>
<select.Option @value="true">Yes</select.Option>
<select.Option @value="false">No</select.Option>
</field.Select>
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="CheckboxGroup">
<Form as |form|>
<form.CheckboxGroup
@title="I give explicit permission"
as |checkboxGroup|
>
<checkboxGroup.Field
@title="Use my email for any purpose."
@name="contract"
as |field|
>
<field.Checkbox>Including signing up for services I can't unsubscribe
to.</field.Checkbox>
</checkboxGroup.Field>
<checkboxGroup.Field
@title="Sign my soul away."
@name="contract2"
as |field|
>
<field.Checkbox>Will severly impact the afterlife experience.</field.Checkbox>
</checkboxGroup.Field>
</form.CheckboxGroup>
</Form>
</StyleguideExample>
<StyleguideExample @title="Image">
<Form as |form|>
<form.Field @title="Image" @name="image" as |field|>
<field.Image @type="avatar" />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Icon">
<Form as |form|>
<form.Field @title="Icon" @name="icon" as |field|>
<field.Icon />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Menu">
<Form as |form data|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Menu @selection={{data.enabled}} as |menu|>
<menu.Item @value="true">Yes</menu.Item>
<menu.Divider />
<menu.Item @value="false">No</menu.Item>
</field.Menu>
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="RadioGroup">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" @format="full" as |field|>
<field.RadioGroup as |radioGroup|>
<radioGroup.Radio @value="true">Yes</radioGroup.Radio>
<radioGroup.Radio @value="false" as |radio|>
<radio.Title>No</radio.Title>
<radio.Description>
Choosing no, will make you inelligible for the contest.
</radio.Description>
</radioGroup.Radio>
</field.RadioGroup>
</form.Field>
</Form>
</StyleguideExample>
<h2>Layout</h2>
<StyleguideExample @title="Section">
<Form as |form|>
<form.Section @title="Section title">
Content
</form.Section>
</Form>
</StyleguideExample>
<StyleguideExample @title="Alert">
<Form as |form|>
<form.Alert @icon="pencil">
You can edit this form.
</form.Alert>
</Form>
</StyleguideExample>
<StyleguideExample @title="InputGroup">
<Form as |form|>
<form.InputGroup as |inputGroup|>
<inputGroup.Field @title="Username" @name="username" as |field|>
<field.Input />
</inputGroup.Field>
<inputGroup.Field @title="Email" @name="email" as |field|>
<field.Input />
</inputGroup.Field>
</form.InputGroup>
</Form>
</StyleguideExample>
<StyleguideExample @title="Collection">
<Form
@data={{hash foo=(array (hash bar=1 baz=2) (hash bar=3 baz=4))}}
as |form|
>
<field.Password />
</form.Field>
</Form>
</StyleguideExample>
<form.Button @action={{fn form.addItemToCollection "foo"}} @icon="plus" />
<StyleguideExample @title="Question">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Question />
</form.Field>
</Form>
</StyleguideExample>
<form.Collection @name="foo" as |collection index|>
<form.Row as |row|>
<row.Col @size={{6}}>
<collection.Field @title="Bar" @name="bar" as |field|>
<field.Input />
</collection.Field>
</row.Col>
<StyleguideExample @title="Toggle">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Toggle />
</form.Field>
</Form>
</StyleguideExample>
<row.Col @size={{4}}>
<collection.Field @title="Baz" @name="baz" as |field|>
<field.Input />
</collection.Field>
</row.Col>
<StyleguideExample @title="Composer">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Composer />
</form.Field>
</Form>
</StyleguideExample>
<row.Col @size={{2}}>
<form.Button @action={{fn collection.remove index}} @icon="minus" />
</row.Col>
</form.Row>
</form.Collection>
<StyleguideExample @title="Code">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Code />
</form.Field>
</Form>
</StyleguideExample>
</Form>
</StyleguideExample>
<StyleguideExample @title="Textarea">
<Form as |form|>
<form.Field @title="Query" @name="query" as |field|>
<field.Textarea />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Select">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Select as |select|>
<select.Option @value="true">Yes</select.Option>
<select.Option @value="false">No</select.Option>
</field.Select>
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="CheckboxGroup">
<Form as |form|>
<form.CheckboxGroup @title="I give explicit permission" as |checkboxGroup|>
<checkboxGroup.Field
@title="Use my email for any purpose."
@name="contract"
as |field|
>
<field.Checkbox>Including signing up for services I can't unsubscribe
to.</field.Checkbox>
</checkboxGroup.Field>
<checkboxGroup.Field
@title="Sign my soul away."
@name="contract2"
as |field|
>
<field.Checkbox>Will severly impact the afterlife experience.</field.Checkbox>
</checkboxGroup.Field>
</form.CheckboxGroup>
</Form>
</StyleguideExample>
<StyleguideExample @title="Image">
<Form as |form|>
<form.Field @title="Image" @name="image" as |field|>
<field.Image @type="avatar" />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Icon">
<Form as |form|>
<form.Field @title="Icon" @name="icon" as |field|>
<field.Icon />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Menu">
<Form as |form data|>
<form.Field @title="Enabled" @name="enabled" as |field|>
<field.Menu @selection={{data.enabled}} as |menu|>
<menu.Item @value="true">Yes</menu.Item>
<menu.Divider />
<menu.Item @value="false">No</menu.Item>
</field.Menu>
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="RadioGroup">
<Form as |form|>
<form.Field @title="Enabled" @name="enabled" @format="full" as |field|>
<field.RadioGroup as |radioGroup|>
<radioGroup.Radio @value="true">Yes</radioGroup.Radio>
<radioGroup.Radio @value="false" as |radio|>
<radio.Title>No</radio.Title>
<radio.Description>
Choosing no, will make you inelligible for the contest.
</radio.Description>
</radioGroup.Radio>
</field.RadioGroup>
</form.Field>
</Form>
</StyleguideExample>
<h2>Layout</h2>
<StyleguideExample @title="Section">
<Form as |form|>
<form.Section @title="Section title">
Content
</form.Section>
</Form>
</StyleguideExample>
<StyleguideExample @title="Alert">
<Form as |form|>
<form.Alert @icon="pencil">
You can edit this form.
</form.Alert>
</Form>
</StyleguideExample>
<StyleguideExample @title="InputGroup">
<Form as |form|>
<form.InputGroup as |inputGroup|>
<inputGroup.Field @title="Username" @name="username" as |field|>
<field.Input />
</inputGroup.Field>
<inputGroup.Field @title="Email" @name="email" as |field|>
<field.Input />
</inputGroup.Field>
</form.InputGroup>
</Form>
</StyleguideExample>
<StyleguideExample @title="Collection">
<Form
@data={{hash foo=(array (hash bar=1 baz=2) (hash bar=3 baz=4))}}
as |form|
>
<form.Button @action={{fn form.addItemToCollection "foo"}} @icon="plus" />
<form.Collection @name="foo" as |collection index|>
<StyleguideExample @title="Row/Col">
<Form as |form|>
<form.Row as |row|>
<row.Col @size={{6}}>
<collection.Field @title="Bar" @name="bar" as |field|>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</collection.Field>
</form.Field>
</row.Col>
<row.Col @size={{4}}>
<collection.Field @title="Baz" @name="baz" as |field|>
<form.Field @title="Email" @name="email" as |field|>
<field.Input />
</collection.Field>
</form.Field>
</row.Col>
<row.Col @size={{2}}>
<form.Button @action={{fn collection.remove index}} @icon="minus" />
<form.Submit />
</row.Col>
</form.Row>
</form.Collection>
</Form>
</StyleguideExample>
</Form>
</StyleguideExample>
<StyleguideExample @title="Multiline">
<Form as |form|>
<form.Row as |row|>
<row.Col @size={{6}}>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
</row.Col>
<row.Col @size={{6}}>
<form.Field @title="Email" @name="email" as |field|>
<field.Input />
</form.Field>
</row.Col>
<StyleguideExample @title="Row/Col">
<Form as |form|>
<form.Row as |row|>
<row.Col @size={{6}}>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
</row.Col>
<row.Col @size={{4}}>
<form.Field @title="Email" @name="email" as |field|>
<field.Input />
</form.Field>
</row.Col>
<row.Col @size={{2}}>
<form.Submit />
</row.Col>
</form.Row>
</Form>
</StyleguideExample>
<row.Col @size={{12}}>
<form.Field @title="Adress" @name="adress" as |field|>
<field.Input />
</form.Field>
</row.Col>
</form.Row>
</Form>
</StyleguideExample>
<StyleguideExample @title="Multiline">
<Form as |form|>
<form.Row as |row|>
<row.Col @size={{6}}>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
</row.Col>
<row.Col @size={{6}}>
<form.Field @title="Email" @name="email" as |field|>
<field.Input />
</form.Field>
</row.Col>
<h2>Validation</h2>
<row.Col @size={{12}}>
<form.Field @title="Adress" @name="adress" as |field|>
<field.Input />
</form.Field>
</row.Col>
</form.Row>
</Form>
</StyleguideExample>
<h2>Validation</h2>
<StyleguideExample @title="Input">
<Form @validateOn="change" as |form|>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
</Form>
</StyleguideExample>
<StyleguideExample @title="Input">
<Form @validateOn="change" as |form|>
<form.Field
@title="Username"
@name="username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
</Form>
</StyleguideExample>
</template>;
export default Forms;

View File

@ -1,7 +1,12 @@
<StyleguideExample @title="spinner - small">
<div class="spinner small"></div>
</StyleguideExample>
import StyleguideExample from "discourse/plugins/styleguide/discourse/components/styleguide-example";
<StyleguideExample @title="spinner - regular">
<div class="spinner"></div>
</StyleguideExample>
const Spinners = <template>
<StyleguideExample @title="spinner - small">
<div class="spinner small"></div>
</StyleguideExample>
<StyleguideExample @title="spinner - regular">
<div class="spinner"></div>
</StyleguideExample>
</template>;
export default Spinners;

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