Update dependency ember-template-lint to v5.3.0 (#16062)

refs https://github.com/TryGhost/Ghost/pull/15550

Pulled out of the rolled up node+ember-js+ember-template rollup linter update PR as it required fairly extensive changes.

- bumped package
- renamed `no-down-event-binding` to `no-pointer-down-event-binding`
- disabled `no-pointer-down-event-binding` rule
- disabled `no-triple-curlies` rule
- ran `yarn lint:hbs --fix`
- updated integration tests to match Octane syntax
- fixed various one-off errors
- updated .lint-todo
This commit is contained in:
Kevin Ansfield 2023-01-04 09:39:32 +00:00 committed by GitHub
parent 789e2c96c0
commit ea9c8c03fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 379 additions and 311 deletions

View File

@ -1103,3 +1103,36 @@ add|ember-template-lint|no-passed-in-event-handlers|23|16|23|16|d47dcf0c8eea7584
add|ember-template-lint|no-passed-in-event-handlers|24|16|24|16|14a806b3f993ec777b1a5ff7e00887e5840bbb77|1670976000000|1681340400000|1686524400000|app/components/gh-benefit-item.hbs
remove|ember-template-lint|no-passed-in-event-handlers|150|56|150|56|37bf29e93ffc35c71cdddd0ab98edeb60097e826|1662681600000|1673053200000|1678237200000|app/templates/offer.hbs
remove|ember-template-lint|no-passed-in-event-handlers|161|56|161|56|37bf29e93ffc35c71cdddd0ab98edeb60097e826|1662681600000|1673053200000|1678237200000|app/templates/offer.hbs
remove|ember-template-lint|simple-unless|19|34|19|34|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|app/components/gh-member-details-activity.hbs
remove|ember-template-lint|simple-unless|18|30|18|30|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|app/components/gh-member-details.hbs
remove|ember-template-lint|simple-unless|64|30|64|30|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|app/components/gh-post-settings-menu.hbs
remove|ember-template-lint|simple-unless|190|62|190|62|5d9203e10703908836b537481cf012f167ded239|1662681600000|1673053200000|1678237200000|app/components/gh-post-settings-menu.hbs
remove|ember-template-lint|simple-unless|84|30|84|30|5d9203e10703908836b537481cf012f167ded239|1662681600000|1673053200000|1678237200000|app/components/modal-import-members.hbs
remove|ember-template-lint|simple-unless|86|30|86|30|17d2867a6155411eaf3c32cb83391e3118c2afc8|1667520000000|1677888000000|1683072000000|app/components/posts/links-table.hbs
remove|ember-template-lint|simple-unless|98|26|98|26|17d2867a6155411eaf3c32cb83391e3118c2afc8|1667520000000|1677888000000|1683072000000|app/components/posts/links-table.hbs
remove|ember-template-lint|simple-unless|37|41|37|41|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-image.hbs
remove|ember-template-lint|simple-unless|36|37|36|37|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-video.hbs
remove|ember-template-lint|simple-unless|41|26|41|26|ca177565b6e1c5a6175982047708732f5dde7e59|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-video.hbs
remove|ember-template-lint|simple-unless|4|79|4|79|5d9203e10703908836b537481cf012f167ded239|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-menu-content.hbs
remove|ember-template-lint|no-duplicate-attributes|9|4|9|4|1bd74ed221db1070a4ef257ccb712285f6e4ebc6|1663977600000|1674349200000|1679533200000|app/components/gh-members-segment-select.hbs
remove|ember-template-lint|table-groups|29|12|29|12|22a05b8f3ce6682814afd256f64d33aa86cd5063|1667433600000|1677801600000|1682985600000|app/templates/offers.hbs
remove|ember-template-lint|require-input-label|4|0|4|0|ce9c488b3c6a110afe45e2242fb068fd4ed61f22|1662681600000|1673053200000|1678237200000|app/components/gh-input-with-select/trigger.hbs
remove|ember-template-lint|simple-unless|7|16|7|16|02b279bc993a1ee6632c7e6edf341a2aabc519cb|1662681600000|1673053200000|1678237200000|app/components/modals/design/theme-errors.hbs
remove|ember-template-lint|simple-unless|54|44|54|44|02b279bc993a1ee6632c7e6edf341a2aabc519cb|1662681600000|1673053200000|1678237200000|app/templates/settings/integrations/slack.hbs
remove|ember-template-lint|no-unused-block-params|1|0|1|0|156821bab3e9e1e1fe662b997173fa21ba6ec8ff|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-file.hbs
remove|ember-template-lint|no-autofocus-attribute|14|4|14|4|bc0a12a01d16038dd3224726d5c4fe81b2d458b6|1662681600000|1673053200000|1678237200000|app/components/gh-input-with-select/trigger.hbs
remove|ember-template-lint|no-triple-curlies|1|0|1|0|26e1d2a3fcc165e3eb94cec903dc0fbff0e26e0e|1662681600000|1673053200000|1678237200000|app/components/gh-blog-url.hbs
remove|ember-template-lint|no-triple-curlies|3|0|3|0|7ceb921960f42e312847d43c601bc98f2eced9f4|1662681600000|1673053200000|1678237200000|app/components/gh-feature-flag.hbs
remove|ember-template-lint|no-triple-curlies|5|12|5|12|5ccce366ce8389f55dc57b1d684c310e65eb26a6|1662681600000|1673053200000|1678237200000|app/components/gh-theme-error-li.hbs
remove|ember-template-lint|no-triple-curlies|19|8|19|8|87b1676e19127a8136984abf3f6b3947569afc25|1662681600000|1673053200000|1678237200000|app/components/gh-theme-error-li.hbs
remove|ember-template-lint|no-triple-curlies|29|28|29|28|9f944c7207ff6f368ea28436c94ff67977fb6823|1662681600000|1673053200000|1678237200000|app/templates/whatsnew.hbs
remove|ember-template-lint|no-triple-curlies|146|20|146|20|9a305980cd2c3469773e4adafa4e02a949dbc919|1662681600000|1673053200000|1678237200000|app/components/gh-nav-menu/main.hbs
remove|ember-template-lint|no-triple-curlies|81|20|81|20|5fc0b56a3c059cf57b60432ba413d490074e3315|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-callout.hbs
remove|ember-template-lint|no-triple-curlies|167|23|167|23|9109f8baf6d3a4cce8e0ceb13f5bca99bdbe4004|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-email-cta.hbs
remove|ember-template-lint|no-triple-curlies|38|11|38|11|9109f8baf6d3a4cce8e0ceb13f5bca99bdbe4004|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-email.hbs
remove|ember-template-lint|no-triple-curlies|172|46|172|46|f85a33dff9dc1a580ba55ca8e6f73bf1cd671f69|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-header.hbs
remove|ember-template-lint|no-triple-curlies|174|53|174|53|8aa6418d946a4a6de4a9f7e963860014b0dd68ee|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-header.hbs
remove|ember-template-lint|no-triple-curlies|25|47|25|47|8336bb2ae349079452ea98bf142c3e7dd649c549|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-html.hbs
remove|ember-template-lint|no-triple-curlies|63|24|63|24|b4fdf1937520db3f14f6f93ec84f03b7653414c0|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-toggle.hbs
remove|ember-template-lint|no-triple-curlies|72|16|72|16|9197e9050977ef47965e1b6e8d99bee542a7c559|1662681600000|1673053200000|1678237200000|lib/koenig-editor/addon/components/koenig-card-toggle.hbs
remove|ember-template-lint|no-invalid-interactive|93|36|93|36|fc4eb64cc0ad0cc9c500c7ef026e44649bc4778b|1662681600000|1673053200000|1678237200000|app/templates/offers.hbs

View File

@ -5,6 +5,8 @@ module.exports = {
'no-forbidden-elements': ['meta', 'html', 'script'],
'no-implicit-this': {allow: ['noop', 'now', 'site-icon-style', 'accent-color-background']},
'no-inline-styles': false,
'no-duplicate-landmark-elements': false
'no-duplicate-landmark-elements': false,
'no-pointer-down-event-binding': false,
'no-triple-curlies': false
}
};

View File

@ -10,7 +10,6 @@
>
<dp.Trigger @tabindex="-1" data-test-date-picker-trigger>
<div class="{{if this.error "error"}}">
{{!-- template-lint-disable no-down-event-binding --}}
<input
type="text"
placeholder={{this.dateFormat}}

View File

@ -1,6 +1,7 @@
{{#if @extra.inputIcon}}
{{svg-jar @extra.inputIcon class=@extra.inputIconClass}}
{{/if}}
{{!-- template-lint-disable no-autofocus-attribute --}}
<input
{{did-insert this.registerInput}}
{{did-update this.closeWhenEmpty @select.results}}
@ -18,7 +19,7 @@
value={{@extra.value}}
name="selectSearchTerm" {{!-- contains "search" to prevent Safari showing autocomplete --}}
spellcheck="false"
role="combobox"
placeholder={{@placeholder}}
disabled={{@select.disabled}}
aria-label={{@extra.label}}
>

View File

@ -1,6 +1,6 @@
<div class="gh-koenig-editor relative w-100 vh-100 overflow-x-hidden overflow-y-auto z-0" {{did-insert this.registerElement}} ...attributes>
{{!-- full height content pane --}}
{{!-- template-lint-disable no-down-event-binding no-invalid-interactive no-passed-in-event-handlers --}}
{{!-- template-lint-disable no-invalid-interactive no-passed-in-event-handlers --}}
<div
class="gh-koenig-editor-pane flex flex-column mih-100"
{{on "mousedown" this.trackMousedown}}

View File

@ -1,6 +1,6 @@
<div class="gh-koenig-editor relative w-100 vh-100 overflow-x-hidden overflow-y-auto z-0" {{did-insert this.registerElement}} ...attributes>
{{!-- full height content pane --}}
{{!-- template-lint-disable no-down-event-binding no-invalid-interactive no-passed-in-event-handlers --}}
{{!-- template-lint-disable no-invalid-interactive no-passed-in-event-handlers --}}
<div
class="gh-koenig-editor-pane flex flex-column mih-100"
{{on "mousedown" this.trackMousedown}}

View File

@ -6,7 +6,6 @@
@allowCreation={{false}}
@renderInPlace={{this.renderInPlace}}
@onChange={{this.setSegment}}
@disabled={{@disabled}}
@class="select-members"
@placeholder="Select a tier"
as |option|

View File

@ -1,7 +1,7 @@
<div class="flex justify-between items-center">
<label>Tiers</label>
<div>
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not (eq this.selectedType.value "active")) "gh-contentfilter-selected"}}" data-test-type-select="true">
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not-eq this.selectedType.value "active") "gh-contentfilter-selected"}}" data-test-type-select="true">
<PowerSelect
@selected={{this.selectedType}}
@options={{this.availableTypes}}

View File

@ -6,7 +6,7 @@ import {inject} from 'ghost-admin/decorators/inject';
/*
Example usage:
{{gh-url-preview prefix="tag" slug=theSlugValue tagName="p" classNames="description"}}
<GhUrlPreview @prefix="tag" @slug={{theSlugValue}} @tagName="p" @classNames="description" />
*/
@classic
@classNames('ghost-url-preview')

View File

@ -1,5 +1,5 @@
<button type="button" class="flex pointer flex-row items-center gh-cp-membertier-details {{if this.showDetails "
rotate"}}" {{on "click" this.toggleSubscriptionExpanded}} role="button" aria-label="Show details">
rotate"}}" {{on "click" this.toggleSubscriptionExpanded}} aria-label="Show details">
Subscription details {{svg-jar "arrow-right-stroke"}}
</button>
<div class="gh-membertier-advanced {{unless this.showDetails " hide"}}" data-test-subscription={{@index}}>

View File

@ -67,7 +67,6 @@
type="button"
{{on "click" this.close}}
{{!-- disable mouseDown so it does not trigger focus-out validations --}}
{{!-- template-lint-disable no-down-event-binding --}}
{{on "mousedown" (optional this.noop)}}
data-test-button="cancel-webhook"
>

View File

@ -2,7 +2,7 @@
<header class="modal-header">
<h1>Are you sure you want to leave this page?</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" (fn @close false)}} data-test-button="close">{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" (fn @close false)}} data-test-button="close">{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>

View File

@ -2,7 +2,7 @@
<header class="modal-header">
<h1>Are you sure you want to delete this?</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>You're about to delete "<strong>{{@data.theme.name}}</strong>". This is permanent! We warned you, k? Maybe <a href="#" {{on "click" this.downloadTheme}}>download your theme before continuing</a></p>

View File

@ -2,11 +2,11 @@
<div class="theme-validation-container" data-test-modal="theme-errors">
<header class="modal-header">
<h1 data-test-theme-warnings-title>
{{#unless @data.canActivate}}
{{@data.title}}
{{else}}
{{#if @data.canActivate}}
{{@data.title}} with {{#if @data.errors}}errors{{else}}warnings{{/if}}
{{/unless}}
{{else}}
{{@data.title}}
{{/if}}
</h1>
</header>
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>

View File

@ -2,7 +2,7 @@
<header class="modal-header" data-test-modal="confirm-newsletter-archive">
<h1>Archive newsletter</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" (fn @close false)}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" (fn @close false)}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>

View File

@ -2,7 +2,7 @@
<header class="modal-header">
<h1>Confirm newsletter email address</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>

View File

@ -2,7 +2,7 @@
<header class="modal-header" data-test-modal="confirm-newsletter-reactivate">
<h1>Reactivate newsletter</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" (fn @close false)}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" (fn @close false)}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>

View File

@ -8,7 +8,7 @@
<h1>Email address verification failed</h1>
{{/if}}
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
{{#if this.verifyEmailTask.isRunning}}

View File

@ -2,7 +2,7 @@
<header class="modal-header">
<h1>Confirm email address</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span
class="hidden">Close</span></button>
<div class="modal-body">

View File

@ -2,7 +2,7 @@
<header class="modal-header" data-test-modal="verify-email">
<h1>Verifying email address</h1>
</header>
<button type="button" class="close" role="button" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<button type="button" class="close" title="Close" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
{{#if this.verifyEmailTask.isRunning}}

View File

@ -2,7 +2,7 @@
<ul role="listbox" aria-controls="ember-power-select-trigger-{{@select.uniqueId}}" {{did-insert this.addHandlers}} ...attributes>
{{#if @select.loading}}
{{#if @loadingMessage}}
<li class="ember-power-select-option ember-power-select-option--loading-message" role="option">{{@loadingMessage}}</li>
<li class="ember-power-select-option ember-power-select-option--loading-message" role="option" aria-selected="false" aria-disabled="true">{{@loadingMessage}}</li>
{{/if}}
{{/if}}

View File

@ -25,7 +25,7 @@
{{#if ev.contextResource}}
<span>
<span>{{capitalize-first-letter ev.contextResource.first}}</span>
{{#if (not (eq ev.contextResource.first ev.contextResource.second))}}
{{#if (not-eq ev.contextResource.first ev.contextResource.second)}}
<code>({{ev.contextResource.second}})</code>
{{/if}}
</span>

View File

@ -2,7 +2,6 @@
<header class="modal-header" data-test-modal="webhook-form">
<h1 data-test-text="title">{{if @data.webhook.isNew "New" "Edit"}} webhook</h1>
</header>
{{!-- template-lint-disable no-down-event-binding --}}
<button class="close" href title="Close" type="button" {{on "click" @close}} {{on "mousedown" this.noop}}>
{{svg-jar "close"}}
</button>

View File

@ -5,7 +5,7 @@
<section class="error-message">
<h1 class="error-code">{{this.model.code}}</h1>
<h2 class="error-description">
{{or this.model.payload.errors.firstObject.message this.model.message}}
{{or (get this.model.payload.errors "0.message") this.model.message}}
</h2>
</section>
</section>

View File

@ -4,7 +4,7 @@
<section class="gh-offers-actions view-actions">
{{#if this.membersUtils.hasActiveTiers}}
<div>
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not (eq this.selectedType.value "active")) "gh-contentfilter-selected"}}" data-test-type-select="true">
<div class="gh-contentfilter-menu gh-contentfilter-type {{if (not-eq this.selectedType.value "active") "gh-contentfilter-selected"}}" data-test-type-select="true">
<PowerSelect
@selected={{this.selectedType}}
@options={{this.availableTypes}}
@ -36,78 +36,84 @@
</div>
{{else if (and this.offersExist this.filteredOffers.length)}}
<table class="gh-list gh-offers-list">
<tr class="gh-list-row header">
<th class="gh-list-header">
{{#if (eq this.selectedType.value "active")}}
{{gh-pluralize this.filteredOffers.length "active offer"}}
{{else}}
{{gh-pluralize this.filteredOffers.length "archived offer"}}
{{/if}}
</th>
<th class="gh-list-header">Tier</th>
<th class="gh-list-header">Terms</th>
<th class="gh-list-header">Price</th>
<th class="gh-list-header">Redemptions</th>
<th class="gh-list-header gh-list-cellwidth-10"></th>
</tr>
{{#each this.filteredOffers as |offer|}}
<tr class="gh-list-row" data-test-list="offers-list-item">
<LinkTo @route="offer" @model={{offer}} class="gh-list-data" data-test-list="offer-name">
<h3>{{offer.name}}</h3>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span>{{offer.tier.name}}</span>
<span class="midgrey">-</span>
<span class="midgrey">{{if (eq offer.cadence 'month') 'Monthly' 'Yearly'}} </span>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span class="offer-value">
{{#if (eq offer.type 'percent')}}
{{svg-jar "offer"}}
<span class="green fw6">{{offer.amount}}% OFF</span>
{{/if}}
{{#if (eq offer.type 'fixed')}}
<span class="blue">{{svg-jar "offer"}}</span>
<span class="blue fw6">{{gh-price-amount offer.amount}} <span class="ttu">{{offer.currency}}</span> OFF</span>
{{/if}}
{{#if (eq offer.type 'trial')}}
<span class="pink">{{svg-jar "offer"}}</span>
<span class="pink fw6"><span class="ttu">{{offer.amount}}</span> DAYS FREE</span>
{{/if}}
{{#if (not (eq offer.type 'trial'))}}
<span class="dib ml1 midgrey ttc">
{{if (eq offer.duration 'once') "First-payment" "Repeating"}}
</span>
{{/if}}
</span>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
{{#if (eq offer.type 'trial')}}
<span>{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.originalPrice}}</span>
<thead>
<tr class="gh-list-row header">
<th class="gh-list-header">
{{#if (eq this.selectedType.value "active")}}
{{gh-pluralize this.filteredOffers.length "active offer"}}
{{else}}
<span>{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.updatedPrice}}</span>
<span class="midgrey strike ml2">{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.originalPrice}}</span>
{{gh-pluralize this.filteredOffers.length "archived offer"}}
{{/if}}
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span class="midgrey">{{offer.redemptionCount}}</span>
</LinkTo>
<div class="gh-list-data gh-list-cellwidth-10 gh-list-chevron">
<div class="flex items-center justify-end w-100 h-100">
<div
class="gh-btn gh-btn-icon gh-btn-text gh-offer-link-button"
data-tooltip="Get shareable link"
{{on "click" (fn this.openLinkDialog offer)}}
>
<span>{{svg-jar "link"}}</span>
</div>
<LinkTo @route="offer" @model={{offer}}>
<span class="nr2 lh-1">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
</LinkTo>
</div>
</div>
</th>
<th class="gh-list-header">Tier</th>
<th class="gh-list-header">Terms</th>
<th class="gh-list-header">Price</th>
<th class="gh-list-header">Redemptions</th>
<th class="gh-list-header gh-list-cellwidth-10"></th>
</tr>
{{/each}}
</thead>
<tbody>
{{#each this.filteredOffers as |offer|}}
<tr class="gh-list-row" data-test-list="offers-list-item">
<LinkTo @route="offer" @model={{offer}} class="gh-list-data" data-test-list="offer-name">
<h3>{{offer.name}}</h3>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span>{{offer.tier.name}}</span>
<span class="midgrey">-</span>
<span class="midgrey">{{if (eq offer.cadence 'month') 'Monthly' 'Yearly'}} </span>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span class="offer-value">
{{#if (eq offer.type 'percent')}}
{{svg-jar "offer"}}
<span class="green fw6">{{offer.amount}}% OFF</span>
{{/if}}
{{#if (eq offer.type 'fixed')}}
<span class="blue">{{svg-jar "offer"}}</span>
<span class="blue fw6">{{gh-price-amount offer.amount}} <span class="ttu">{{offer.currency}}</span> OFF</span>
{{/if}}
{{#if (eq offer.type 'trial')}}
<span class="pink">{{svg-jar "offer"}}</span>
<span class="pink fw6"><span class="ttu">{{offer.amount}}</span> DAYS FREE</span>
{{/if}}
{{#if (not-eq offer.type 'trial')}}
<span class="dib ml1 midgrey ttc">
{{if (eq offer.duration 'once') "First-payment" "Repeating"}}
</span>
{{/if}}
</span>
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
{{#if (eq offer.type 'trial')}}
<span>{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.originalPrice}}</span>
{{else}}
<span>{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.updatedPrice}}</span>
<span class="midgrey strike ml2">{{currency-symbol offer.finalCurrency}}{{gh-price-amount offer.originalPrice}}</span>
{{/if}}
</LinkTo>
<LinkTo @route="offer" @model={{offer}} class="gh-list-data">
<span class="midgrey">{{offer.redemptionCount}}</span>
</LinkTo>
<div class="gh-list-data gh-list-cellwidth-10 gh-list-chevron">
<div class="flex items-center justify-end w-100 h-100">
<button
type="button"
class="gh-btn gh-btn-icon gh-btn-text gh-offer-link-button"
data-tooltip="Get shareable link"
aria-label="Get shareable link"
{{on "click" (fn this.openLinkDialog offer)}}
>
<span>{{svg-jar "link"}}</span>
</button>
<LinkTo @route="offer" @model={{offer}}>
<span class="nr2 lh-1">{{svg-jar "arrow-right" class="w6 h6 fill-midgrey pa1"}}</span>
</LinkTo>
</div>
</div>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
{{#if (eq this.selectedType.value "active")}}

View File

@ -54,11 +54,11 @@
}}
data-test-slack-url-input={{true}}
/>
{{#unless this.settings.errors}}
<p>Set up a new incoming webhook <a href="https://my.slack.com/apps/new/A0F7XDUAZ-incoming-webhooks" target="_blank" rel="noopener noreferrer">here</a>, and grab the URL.</p>
{{else}}
{{#if this.settings.errors}}
<GhErrorMessage @errors={{this.settings.errors}} @property="slackUrl" data-test-error="slack-url" />
{{/unless}}
{{else}}
<p>Set up a new incoming webhook <a href="https://my.slack.com/apps/new/A0F7XDUAZ-incoming-webhooks" target="_blank" rel="noopener noreferrer">here</a>, and grab the URL.</p>
{{/if}}
</GhFormGroup>
</div>
</div>

View File

@ -40,7 +40,7 @@
{{#if (or uploader.errors uploader.isUploading)}}
{{#if uploader.errors}}
<span class="db flex items-center h8 pl2 pr2 red sans-serif f6 fw6">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}
@ -138,7 +138,7 @@
{{#if (or uploader.errors uploader.isUploading)}}
{{#if uploader.errors}}
<span class="flex items-center h8 pl2 pr2 red sans-serif f6 fw5">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}

View File

@ -20,7 +20,6 @@
{{on "dragover" this.dragOver}}
{{on "dragleave" this.dragLeave}}
{{on "drop" this.drop}}
as |card|
>
{{#if @payload.src}}
<div class="kg-upload-container {{if (and (not @isEditing) (or (not @payload.fileTitle) (not @payload.fileCaption))) "medium"}} {{if (and (not @isEditing) (and (not @payload.fileTitle) (not @payload.fileCaption))) "small"}}">
@ -70,7 +69,7 @@
{{#if (or uploader.errors uploader.isUploading)}}
{{#if uploader.errors}}
<span class="db absolute top-0 right-0 left-0 flex items-center h8 pl2 pr2 bg-red white sans-serif f7">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}

View File

@ -50,7 +50,7 @@
<div class="relative miw-100 flex items-center {{if this.previewSrc "absolute absolute--fill bg-white-50" "kg-media-placeholder ba b--whitegrey"}}">
{{#if uploader.errors}}
<span class="db absolute top-0 right-0 left-0 flex items-center h8 pl2 pr2 bg-red white sans-serif f7">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}

View File

@ -57,7 +57,7 @@
<div class="relative miw-100 h-100 flex items-center {{if this.previewSrc "absolute absolute--fill bg-white-50" "kg-media-placeholder ba b--whitegrey"}}">
{{#if uploader.errors}}
<span class="db absolute top-0 right-0 left-0 pl2 pr2 bg-red white sans-serif f7">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}

View File

@ -56,7 +56,7 @@
<div class="relative miw-100 flex items-center justify-center {{unless @payload.src "kg-media-placeholder ba b--whitegrey bg-whitegrey-l2" "absolute absolute--fill bg-white-50"}}">
{{#if uploader.errors}}
<span class="kg-upload-error">
{{uploader.errors.firstObject.message}}
{{get uploader.errors "0.message"}}
</span>
{{/if}}

View File

@ -114,7 +114,7 @@
"ember-sinon": "5.0.0",
"ember-source": "3.24.0",
"ember-svg-jar": "2.4.2",
"ember-template-lint": "4.18.2",
"ember-template-lint": "5.3.0",
"ember-test-selectors": "6.0.0",
"ember-tooltips": "3.6.0",
"ember-truth-helpers": "3.1.1",

View File

@ -26,7 +26,7 @@ describe('Integration: Component: gh-alerts', function () {
it('renders', async function () {
let notifications = this.owner.lookup('service:notifications');
await render(hbs`{{gh-alerts}}`);
await render(hbs`<GhAlerts />`);
expect(findAll('.gh-alerts').length).to.equal(1);
expect(find('.gh-alerts').children.length).to.equal(2);
@ -42,7 +42,7 @@ describe('Integration: Component: gh-alerts', function () {
// test double for notify action
this.set('notify', count => expect(count).to.equal(expectedCount));
await render(hbs`{{gh-alerts notify=(action notify)}}`);
await render(hbs`<GhAlerts @notify={{this.notify}} />`);
expectedCount = 3;
notifications.alerts.pushObject({message: 'Third', type: 'success'});

View File

@ -12,9 +12,12 @@ describe('Integration: Component: gh-cm-editor', function () {
setupRenderingTest();
it('handles change event', async function () {
this.set('onUpdate', (value) => {
this.set('text', value);
});
this.set('text', '');
await render(hbs`{{gh-cm-editor text class="gh-input" update=(action (mut text))}}`);
await render(hbs`<GhCmEditor @value={{this.text}} @classNames="gh-input" @update={{this.onUpdate}} />`);
// access CodeMirror directly as it doesn't pick up changes to the textarea
let cm = find('.gh-input .CodeMirror').CodeMirror;
cm.setValue('Testing');
@ -36,9 +39,12 @@ describe('Integration: Component: gh-cm-editor', function () {
.to.be.true;
};
this.set('onUpdate', (value) => {
this.set('text', value);
});
this.set('onFocus', onFocus);
this.set('text', '');
await render(hbs`{{gh-cm-editor text class="gh-input" update=(action (mut text)) autofocus=true focus-in=(action onFocus)}}`);
await render(hbs`<GhCmEditor @value={{this.text}} @classNames="gh-input" @update={{this.onUpdate}} @autofocus={{true}} @focus-in={{this.onFocus}} />`);
});
});

View File

@ -53,20 +53,20 @@ describe('Integration: Component: gh-file-uploader', function () {
});
it('renders', async function () {
await render(hbs`{{gh-file-uploader}}`);
await render(hbs`<GhFileUploader />`);
expect(find('label').textContent.trim(), 'default label')
.to.equal('Select or drag-and-drop a file');
});
it('allows file input "accept" attribute to be changed', async function () {
await render(hbs`{{gh-file-uploader}}`);
await render(hbs`<GhFileUploader />`);
expect(
find('input[type="file"]').getAttribute('accept'),
'default "accept" attribute'
).to.equal('text/csv');
await render(hbs`{{gh-file-uploader accept="application/zip"}}`);
await render(hbs`<GhFileUploader @accept="application/zip" />`);
expect(
find('input[type="file"]').getAttribute('accept'),
'specified "accept" attribute'
@ -75,7 +75,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('renders form with supplied label text', async function () {
this.set('labelText', 'My label');
await render(hbs`{{gh-file-uploader labelText=labelText}}`);
await render(hbs`<GhFileUploader @labelText={{this.labelText}} />`);
expect(find('label').textContent.trim(), 'label')
.to.equal('My label');
@ -84,7 +84,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('generates request to supplied endpoint', async function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(server.handledRequests.length).to.equal(1);
@ -97,7 +97,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadSuccess=(action uploadSuccess)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadSuccess={{this.uploadSuccess}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(uploadSuccess.calledOnce).to.be.true;
@ -110,7 +110,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubFailedUpload(server, 500);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadSuccess=(action uploadSuccess)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadSuccess={{this.uploadSuccess}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
await settled();
@ -123,7 +123,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl fileSelected=(action fileSelected)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @fileSelected={{this.fileSelected}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(fileSelected.calledOnce).to.be.true;
@ -136,7 +136,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadStarted=(action uploadStarted)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadStarted={{this.uploadStarted}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(uploadStarted.calledOnce).to.be.true;
@ -148,7 +148,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadFinished=(action uploadFinished)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadFinished={{this.uploadFinished}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(uploadFinished.calledOnce).to.be.true;
@ -160,7 +160,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubFailedUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadFinished=(action uploadFinished)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadFinished={{this.uploadFinished}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(uploadFinished.calledOnce).to.be.true;
@ -168,7 +168,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('displays invalid file type error', async function () {
stubFailedUpload(server, 415, 'UnsupportedMediaTypeError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -179,7 +179,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('displays file too large for server error', async function () {
stubFailedUpload(server, 413, 'RequestEntityTooLargeError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -190,7 +190,7 @@ describe('Integration: Component: gh-file-uploader', function () {
server.post(`${ghostPaths().apiRoot}/images/`, function () {
return [413, {}, ''];
});
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -199,7 +199,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('displays other server-side error with message', async function () {
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -210,7 +210,7 @@ describe('Integration: Component: gh-file-uploader', function () {
server.post(`${ghostPaths().apiRoot}/images/`, function () {
return [500, {'Content-Type': 'application/json'}, ''];
});
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -224,7 +224,7 @@ describe('Integration: Component: gh-file-uploader', function () {
stubFailedUpload(server, 400, 'VersionMismatchError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(showAPIError.calledOnce).to.be.true;
@ -236,7 +236,7 @@ describe('Integration: Component: gh-file-uploader', function () {
notifications.set('showAPIError', showAPIError);
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
expect(showAPIError.called).to.be.false;
@ -244,7 +244,7 @@ describe('Integration: Component: gh-file-uploader', function () {
it('can be reset after a failed upload', async function () {
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-file-uploader url=uploadUrl}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
await click('[data-test-upload-try-again-button]');
@ -252,7 +252,7 @@ describe('Integration: Component: gh-file-uploader', function () {
});
it('handles drag over/leave', async function () {
await render(hbs`{{gh-file-uploader}}`);
await render(hbs`<GhFileUploader />`);
run(() => {
// eslint-disable-next-line new-cap
@ -285,7 +285,7 @@ describe('Integration: Component: gh-file-uploader', function () {
this.set('uploadSuccess', uploadSuccess);
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader url=uploadUrl uploadSuccess=(action uploadSuccess)}}`);
await render(hbs`<GhFileUploader @url={{this.uploadUrl}} @uploadSuccess={{this.uploadSuccess}} />`);
run(() => {
$(find('.gh-image-uploader')).trigger(drop);
@ -306,10 +306,10 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader
url=uploadUrl
uploadSuccess=(action uploadSuccess)
uploadFailed=(action uploadFailed)}}`);
await render(hbs`<GhFileUploader
@url={{this.uploadUrl}}
@uploadSuccess={{this.uploadSuccess}}
@uploadFailed={{this.uploadFailed}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.txt'});
@ -328,10 +328,10 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader
url=uploadUrl
uploadSuccess=(action uploadSuccess)
validate=(action validate)}}`);
await render(hbs`<GhFileUploader
@url={{this.uploadUrl}}
@uploadSuccess={{this.uploadSuccess}}
@validate={{this.validate}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});
@ -352,11 +352,11 @@ describe('Integration: Component: gh-file-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-file-uploader
url=uploadUrl
uploadSuccess=(action uploadSuccess)
uploadFailed=(action uploadFailed)
validate=(action validate)}}`);
await render(hbs`<GhFileUploader
@url={{this.uploadUrl}}
@uploadSuccess={{this.uploadSuccess}}
@uploadFailed={{this.uploadFailed}}
@validate={{this.validate}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.csv'});

View File

@ -64,19 +64,19 @@ describe('Integration: Component: gh-image-uploader', function () {
});
it('renders form with supplied alt text', async function () {
await render(hbs`{{gh-image-uploader image=image altText="text test"}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @altText="text test" />`);
expect(find('[data-test-file-input-description]')).to.have.trimmed.text('Upload image of "text test"');
});
it('renders form with supplied text', async function () {
await render(hbs`{{gh-image-uploader image=image text="text test"}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @text="text test" />`);
expect(find('[data-test-file-input-description]')).to.have.trimmed.text('text test');
});
it('generates request to correct endpoint', async function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(server.handledRequests.length).to.equal(1);
@ -90,7 +90,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(update.calledOnce).to.be.true;
@ -103,7 +103,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubFailedUpload(server, 500);
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(update.calledOnce).to.be.false;
@ -115,7 +115,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image fileSelected=(action fileSelected) update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @fileSelected={{this.fileSelected}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(fileSelected.calledOnce).to.be.true;
@ -128,7 +128,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image uploadStarted=(action uploadStarted) update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @uploadStarted={{this.uploadStarted}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(uploadStarted.calledOnce).to.be.true;
@ -140,7 +140,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image uploadFinished=(action uploadFinished) update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @uploadFinished={{this.uploadFinished}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(uploadFinished.calledOnce).to.be.true;
@ -152,7 +152,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubFailedUpload(server);
await render(hbs`{{gh-image-uploader image=image uploadFinished=(action uploadFinished) update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @uploadFinished={{this.uploadFinished}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(uploadFinished.calledOnce).to.be.true;
@ -160,7 +160,7 @@ describe('Integration: Component: gh-image-uploader', function () {
it('displays invalid file type error', async function () {
stubFailedUpload(server, 415, 'UnsupportedMediaTypeError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -171,7 +171,7 @@ describe('Integration: Component: gh-image-uploader', function () {
it('displays file too large for server error', async function () {
stubFailedUpload(server, 413, 'RequestEntityTooLargeError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -182,7 +182,7 @@ describe('Integration: Component: gh-image-uploader', function () {
server.post(`${ghostPaths().apiRoot}/images/upload/`, function () {
return [413, {}, ''];
});
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -191,7 +191,7 @@ describe('Integration: Component: gh-image-uploader', function () {
it('displays other server-side error with message', async function () {
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -202,7 +202,7 @@ describe('Integration: Component: gh-image-uploader', function () {
server.post(`${ghostPaths().apiRoot}/images/upload/`, function () {
return [500, {'Content-Type': 'application/json'}, ''];
});
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(findAll('.failed').length, 'error message is displayed').to.equal(1);
@ -216,7 +216,7 @@ describe('Integration: Component: gh-image-uploader', function () {
stubFailedUpload(server, 400, 'VersionMismatchError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(showAPIError.calledOnce).to.be.true;
@ -228,7 +228,7 @@ describe('Integration: Component: gh-image-uploader', function () {
notifications.set('showAPIError', showAPIError);
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});
expect(showAPIError.called).to.be.false;
@ -236,7 +236,7 @@ describe('Integration: Component: gh-image-uploader', function () {
it('can be reset after a failed upload', async function () {
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
await fileUpload('input[type="file"]', ['test'], {type: 'test.png'});
await click('.gh-btn-green');
@ -246,7 +246,7 @@ describe('Integration: Component: gh-image-uploader', function () {
it('handles drag over/leave', async function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader image=image update=(action update)}}`);
await render(hbs`<GhImageUploader @image={{this.image}} @update={{this.update}} />`);
run(() => {
// eslint-disable-next-line new-cap
@ -278,7 +278,7 @@ describe('Integration: Component: gh-image-uploader', function () {
this.set('uploadSuccess', uploadSuccess);
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader uploadSuccess=(action uploadSuccess)}}`);
await render(hbs`<GhImageUploader @uploadSuccess={{this.uploadSuccess}} />`);
run(() => {
$(find('.gh-image-uploader')).trigger(drop);
@ -298,9 +298,9 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader
uploadSuccess=(action uploadSuccess)
uploadFailed=(action uploadFailed)}}`);
await render(hbs`<GhImageUploader
@uploadSuccess={{this.uploadSuccess}}
@uploadFailed={{this.uploadFailed}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.json'});
@ -319,9 +319,9 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader
uploadSuccess=(action uploadSuccess)
validate=(action validate)}}`);
await render(hbs`<GhImageUploader
@uploadSuccess={{this.uploadSuccess}}
@validate={{this.validate}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.txt'});
@ -340,10 +340,10 @@ describe('Integration: Component: gh-image-uploader', function () {
stubSuccessfulUpload(server);
await render(hbs`{{gh-image-uploader
uploadSuccess=(action uploadSuccess)
uploadFailed=(action uploadFailed)
validate=(action validate)}}`);
await render(hbs`<GhImageUploader
@uploadSuccess={{this.uploadSuccess}}
@uploadFailed={{this.uploadFailed}}
@validate={{this.validate}} />`);
await fileUpload('input[type="file"]', ['test'], {name: 'test.png'});

View File

@ -13,14 +13,14 @@ describe('Integration: Component: gh-image-uploader-with-preview', function () {
this.set('remove', remove);
this.set('image', 'http://example.com/test.png');
await render(hbs`{{gh-image-uploader-with-preview image=image remove=(action remove)}}`);
await render(hbs`<GhImageUploaderWithPreview @image={{this.image}} @remove={{this.remove}} />`);
expect(findAll('.gh-image-uploader.-with-image').length).to.equal(1);
expect(find('img').getAttribute('src')).to.equal('http://example.com/test.png');
});
it('renders upload form when no image provided', async function () {
await render(hbs`{{gh-image-uploader-with-preview image=image}}`);
await render(hbs`<GhImageUploaderWithPreview @image={{this.image}} />`);
expect(findAll('input[type="file"]').length).to.equal(1);
});
@ -30,7 +30,7 @@ describe('Integration: Component: gh-image-uploader-with-preview', function () {
this.set('remove', remove);
this.set('image', 'http://example.com/test.png');
await render(hbs`{{gh-image-uploader-with-preview image=image remove=(action remove)}}`);
await render(hbs`<GhImageUploaderWithPreview @image={{this.image}} @remove={{this.remove}} />`);
await click('.image-delete');
expect(remove.calledOnce).to.be.true;

View File

@ -24,7 +24,7 @@ describe('Integration: Component: gh-notifications', function () {
});
it('renders', async function () {
await render(hbs`{{gh-notifications}}`);
await render(hbs`<GhNotifications />`);
expect(find('.gh-notifications')).to.exist;
expect(find('.gh-notifications').children.length).to.equal(2);

View File

@ -51,7 +51,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
it('shows selected tags on render', async function () {
await assignPostWithTags(this, 'one', 'three');
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
let selected = findAll('.tag-token');
expect(selected.length).to.equal(2);
@ -65,7 +65,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
this.set('post', this.store.findRecord('post', 1));
await settled();
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await settled();
// unsure why settled() is sometimes not catching the update
@ -83,7 +83,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
this.set('post', this.store.findRecord('post', 1));
await settled();
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await typeInSearch('2');
await settled();
@ -100,7 +100,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
this.set('post', this.store.findRecord('post', 1));
await settled();
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await typeInSearch('#Tag 2');
await settled();
@ -114,7 +114,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
it('highlights internal tags', async function () {
await assignPostWithTags(this, 'two', 'three');
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
let selected = findAll('.tag-token');
expect(selected.length).to.equal(2);
@ -125,7 +125,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
describe('updateTags', function () {
it('modifies post.tags', async function () {
await assignPostWithTags(this, 'two', 'three');
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await selectChoose('.ember-power-select-trigger', 'Tag 1');
expect(
@ -138,7 +138,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
// https://github.com/TryGhost/Ghost/issues/10308
it.skip('destroys new tag records when not selected', async function () {
await assignPostWithTags(this, 'two', 'three');
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await typeInSearch('New');
await settled();
@ -158,7 +158,7 @@ describe('Integration: Component: gh-psm-tags-input', function () {
describe('createTag', function () {
it('creates new records', async function () {
await assignPostWithTags(this, 'two', 'three');
await render(hbs`{{gh-psm-tags-input post=post}}`);
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await typeInSearch('New One');
await settled();

View File

@ -64,7 +64,7 @@ describe('Integration: Component: gh-psm-template-select', function () {
}
});
await render(hbs`{{gh-psm-template-select post=post}}`);
await render(hbs`<GhPsmTemplateSelect @post={{this.post}} />`);
expect(find('select').disabled, 'select is disabled').to.be.true;
expect(find('p')).to.contain.text('post-one.hbs');
@ -78,7 +78,7 @@ describe('Integration: Component: gh-psm-template-select', function () {
}
});
await render(hbs`{{gh-psm-template-select post=post}}`);
await render(hbs`<GhPsmTemplateSelect @post={{this.post}} />`);
expect(find('select').disabled, 'select is disabled').to.be.true;
expect(find('p')).to.contain.text('page-about.hbs');

View File

@ -13,7 +13,7 @@ describe('Integration: Component: gh-psm-visibility-input', function () {
visibility: 'members'
});
await render(hbs`{{gh-psm-visibility-input post=post}}`);
await render(hbs`<GhPsmVisibilityInput @post={{this.post}} />`);
expect(this.element, 'top-level elements').to.exist;
expect(findAll('option'), 'number of options').to.have.length(4);
@ -28,7 +28,7 @@ describe('Integration: Component: gh-psm-visibility-input', function () {
set: setVisibility
});
await render(hbs`{{gh-psm-visibility-input post=post}}`);
await render(hbs`<GhPsmVisibilityInput @post={{this.post}} />`);
expect(this.element, 'top-level elements').to.exist;
expect(findAll('option'), 'number of options').to.have.length(4);

View File

@ -20,13 +20,13 @@ describe('Integration: Component: gh-search-input', function () {
it('renders', async function () {
// renders the component on the page
await render(hbs`{{gh-search-input}}`);
await render(hbs`<GhSearchInput />`);
expect(find('.ember-power-select-search input')).to.exist;
});
it('opens the dropdown on text entry', async function () {
await render(hbs`{{gh-search-input}}`);
await render(hbs`<GhSearchInput />`);
await fillIn('input[type="search"]', 'test');
expect(findAll('.ember-basic-dropdown-content').length).to.equal(1);

View File

@ -18,9 +18,10 @@ describe('Integration: Component: gh-timezone-select', function () {
});
it('renders', async function () {
await render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
timezone=timezone}}`);
await render(hbs`<GhTimezoneSelect
@availableTimezones={{this.availableTimezones}}
@timezone={{this.timezone}}
/>`);
expect(this.element, 'top-level elements').to.exist;
expect(findAll('option'), 'number of options').to.have.length(3);
@ -30,9 +31,10 @@ describe('Integration: Component: gh-timezone-select', function () {
it('handles an unknown timezone', async function () {
this.set('timezone', 'Europe/London');
await render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
timezone=timezone}}`);
await render(hbs`<GhTimezoneSelect
@availableTimezones={{this.availableTimezones}}
@timezone={{this.timezone}}
/>`);
// we have an additional blank option at the top
expect(findAll('option'), 'number of options').to.have.length(4);
@ -46,10 +48,11 @@ describe('Integration: Component: gh-timezone-select', function () {
let update = sinon.spy();
this.set('update', update);
await render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
timezone=timezone
update=(action update)}}`);
await render(hbs`<GhTimezoneSelect
@availableTimezones={{this.availableTimezones}}
@timezone={{this.timezone}}
@update={{this.update}}
/>`);
await fillIn('select', 'Pacific/Pago_Pago');
await blur('select');

View File

@ -9,7 +9,16 @@ describe('Integration: Component: gh-trim-focus-input', function () {
it('trims value on focusOut', async function () {
this.set('text', 'some random stuff ');
await render(hbs`{{gh-trim-focus-input value=(readonly text) input=(action (mut text) value="target.value")}}`);
this.set('onInput', (event) => {
this.set('text', event.target.value);
});
await render(hbs`
{{!-- template-lint-disable no-passed-in-event-handlers --}}
<GhTrimFocusInput
@value={{readonly this.text}}
@input={{this.onInput}}
/>
`);
await blur('input');
@ -18,16 +27,22 @@ describe('Integration: Component: gh-trim-focus-input', function () {
it('trims value on focusOut before calling custom focus-out', async function () {
this.set('text', 'some random stuff ');
this.set('onInput', (event) => {
this.set('text', event.target.value);
});
this.set('customFocusOut', function (value) {
expect(find('.gh-input').value, 'input value').to.equal('some random stuff');
expect(value, 'value').to.equal('some random stuff');
});
await render(hbs`{{gh-trim-focus-input
value=(readonly text)
input=(action (mut text) value="target.value")
focus-out=(action customFocusOut)
}}`);
await render(hbs`
{{!-- template-lint-disable no-passed-in-event-handlers --}}
<GhTrimFocusInput
@value={{readonly this.text}}
@input={{this.onInput}}
@focus-out={{this.customFocusOut}}
/>
`);
await blur('input');
@ -36,25 +51,25 @@ describe('Integration: Component: gh-trim-focus-input', function () {
it('does not have the autofocus attribute if not set to focus', async function () {
this.set('text', 'some text');
await render(hbs`{{gh-trim-focus-input value=(readonly text) shouldFocus=false}}`);
await render(hbs`<GhTrimFocusInput @value={{readonly this.text}} @shouldFocus={{false}} />`);
expect(find('input').autofocus).to.not.be.ok;
});
it('has the autofocus attribute if set to focus', async function () {
this.set('text', 'some text');
await render(hbs`{{gh-trim-focus-input value=(readonly text) shouldFocus=true}}`);
await render(hbs`<GhTrimFocusInput @value={{readonly this.text}} @shouldFocus={{true}} />`);
expect(find('input').autofocus).to.be.ok;
});
it('handles undefined values', async function () {
this.set('text', undefined);
await render(hbs`{{gh-trim-focus-input value=(readonly text) shouldFocus=true}}`);
await render(hbs`<GhTrimFocusInput @value={{readonly this.text}} @shouldFocus={{true}} />`);
expect(find('input').autofocus).to.be.ok;
});
it('handles non-string values', async function () {
this.set('text', 10);
await render(hbs`{{gh-trim-focus-input value=(readonly text) shouldFocus=true}}`);
await render(hbs`<GhTrimFocusInput @value={{readonly this.text}} @shouldFocus={{true}} />`);
expect(find('input').value).to.equal('10');
});
});

View File

@ -69,7 +69,7 @@ describe('Integration: Component: gh-unsplash-photo', function () {
});
it('sets background-color style', async function () {
await render(hbs`{{gh-unsplash-photo photo=photo}}`);
await render(hbs`<GhUnsplashPhoto @photo={{this.photo}} />`);
expect(
find('[data-test-unsplash-photo-container]').attributes.style.value
@ -77,7 +77,7 @@ describe('Integration: Component: gh-unsplash-photo', function () {
});
it('sets padding-bottom style', async function () {
await render(hbs`{{gh-unsplash-photo photo=photo}}`);
await render(hbs`<GhUnsplashPhoto @photo={{this.photo}} />`);
// don't check full padding-bottom value as it will likely vary across
// browsers
@ -87,7 +87,7 @@ describe('Integration: Component: gh-unsplash-photo', function () {
});
it('uses correct image size url', async function () {
await render(hbs`{{gh-unsplash-photo photo=photo}}`);
await render(hbs`<GhUnsplashPhoto @photo={{this.photo}} />`);
expect(
find('[data-test-unsplash-photo-image]').attributes.src.value
@ -95,7 +95,7 @@ describe('Integration: Component: gh-unsplash-photo', function () {
});
it('calculates image width/height', async function () {
await render(hbs`{{gh-unsplash-photo photo=photo}}`);
await render(hbs`<GhUnsplashPhoto @photo={{this.photo}} />`);
expect(
find('[data-test-unsplash-photo-image]').attributes.width.value

View File

@ -17,7 +17,7 @@ describe('Integration: Component: gh-unsplash', function () {
// {{/gh-unsplash}}
// `);
await render(hbs`{{gh-unsplash}}`);
await render(hbs`<GhUnsplash />`);
expect(this.element).to.exist;
});

View File

@ -44,7 +44,7 @@ describe('Integration: Component: gh-uploader', function () {
});
it('triggers uploads when `files` is set', async function () {
await render(hbs`{{#gh-uploader files=files}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}}></GhUploader>`);
this.set('files', [createFile()]);
await settled();
@ -59,7 +59,7 @@ describe('Integration: Component: gh-uploader', function () {
});
it('triggers multiple uploads', async function () {
await render(hbs`{{#gh-uploader files=files}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}}></GhUploader>`);
this.set('files', [createFile(), createFile()]);
await settled();
@ -70,7 +70,7 @@ describe('Integration: Component: gh-uploader', function () {
it('triggers onStart when upload starts', async function () {
this.set('uploadStarted', sinon.spy());
await render(hbs`{{#gh-uploader files=files onStart=(action uploadStarted)}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @onStart={{this.uploadStarted}}></GhUploader>`);
this.set('files', [createFile(), createFile()]);
await settled();
@ -80,7 +80,7 @@ describe('Integration: Component: gh-uploader', function () {
it('triggers onUploadSuccess when a file uploads', async function () {
this.set('fileUploaded', sinon.spy());
await render(hbs`{{#gh-uploader files=files onUploadSuccess=(action fileUploaded)}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @onUploadSuccess={{this.fileUploaded}}></GhUploader>`);
this.set('files', [createFile(['test'], {name: 'file1.png'}), createFile()]);
await settled();
@ -96,7 +96,7 @@ describe('Integration: Component: gh-uploader', function () {
it('triggers onComplete when all files uploaded', async function () {
this.set('uploadsFinished', sinon.spy());
await render(hbs`{{#gh-uploader files=files onComplete=(action uploadsFinished)}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @onComplete={{this.uploadsFinished}}></GhUploader>`);
this.set('files', [
createFile(['test'], {name: 'file1.png'}),
createFile(['test'], {name: 'file2.png'})
@ -117,7 +117,7 @@ describe('Integration: Component: gh-uploader', function () {
it('onComplete only passes results for last upload', async function () {
this.set('uploadsFinished', sinon.spy());
await render(hbs`{{#gh-uploader files=files onComplete=(action uploadsFinished)}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @onComplete={{this.uploadsFinished}}></GhUploader>`);
this.set('files', [
createFile(['test'], {name: 'file1.png'})
]);
@ -145,7 +145,7 @@ describe('Integration: Component: gh-uploader', function () {
this.set('uploadsFinished', sinon.spy());
await render(hbs`{{#gh-uploader files=files onComplete=(action uploadsFinished)}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @onComplete={{this.uploadsFinished}}></GhUploader>`);
this.set('files', [
createFile(['test'], {name: 'file1.png'}), // large - finishes last
createFile(['test'], {name: 'file2.png'}) // small - finishes first
@ -161,7 +161,7 @@ describe('Integration: Component: gh-uploader', function () {
let errorSpy = sinon.spy(console, 'error');
stubSuccessfulUpload(server, 100);
await render(hbs`{{#gh-uploader files=files}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}}></GhUploader>`);
this.set('files', [createFile()]);
// logs error because upload is in progress
@ -183,11 +183,11 @@ describe('Integration: Component: gh-uploader', function () {
stubSuccessfulUpload(server, 100);
await render(hbs`
{{#gh-uploader files=files as |uploader|}}
<GhUploader @files={{files}} as |uploader|>
{{#if uploader.isUploading}}
<div class="is-uploading-test"></div>
{{/if}}
{{/gh-uploader}}`);
</GhUploader>`);
this.set('files', [createFile(), createFile()]);
@ -201,9 +201,9 @@ describe('Integration: Component: gh-uploader', function () {
stubSuccessfulUpload(server, 100);
await render(hbs`
{{#gh-uploader files=files as |uploader|}}
<GhUploader @files={{files}} as |uploader|>
{{uploader.progressBar}}
{{/gh-uploader}}`);
</GhUploader>`);
this.set('files', [createFile(), createFile()]);
@ -221,11 +221,11 @@ describe('Integration: Component: gh-uploader', function () {
it('yields files property', async function () {
await render(hbs`
{{#gh-uploader files=files as |uploader|}}
<GhUploader @files={{files}} as |uploader|>
{{#each uploader.files as |file|}}
<div class="file">{{file.name}}</div>
{{/each}}
{{/gh-uploader}}`);
</GhUploader>`);
this.set('files', [
createFile(['test'], {name: 'file1.png'}),
@ -242,11 +242,11 @@ describe('Integration: Component: gh-uploader', function () {
this.set('complete', sinon.spy());
await render(hbs`
{{#gh-uploader files=files onCancel=(action cancelled) as |uploader|}}
<GhUploader @files={{files}} @onCancel={{this.cancelled}} as |uploader|>
{{#if uploader.isUploading}}
<button class="cancel-button" {{action uploader.cancel}}>Cancel</button>
<button class="cancel-button" type="button" {{on "click" uploader.cancel}}>Cancel</button>
{{/if}}
{{/gh-uploader}}`);
</GhUploader>`);
this.set('files', [createFile()]);
@ -262,7 +262,7 @@ describe('Integration: Component: gh-uploader', function () {
return [200, {'Content-Type': 'application/json'}, '{"images": [{"url": "/content/images/test.png"}]'];
});
await render(hbs`{{#gh-uploader files=files uploadUrl="/images/"}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @uploadUrl="/images/"></GhUploader>`);
this.set('files', [createFile()]);
await settled();
@ -271,7 +271,7 @@ describe('Integration: Component: gh-uploader', function () {
});
it('passes supplied paramName in request', async function () {
await render(hbs`{{#gh-uploader files=files paramName="testupload"}}{{/gh-uploader}}`);
await render(hbs`<GhUploader @files={{files}} @paramName="testupload"></GhUploader>`);
this.set('files', [createFile()]);
await settled();
@ -288,7 +288,7 @@ describe('Integration: Component: gh-uploader', function () {
this.set('onFailed', sinon.spy());
await render(hbs`
{{#gh-uploader files=files extensions="jpg,jpeg" onFailed=(action onFailed)}}{{/gh-uploader}}
<GhUploader @files={{files}} @extensions="jpg,jpeg" @onFailed={{this.onFailed}}></GhUploader>
`);
this.set('files', [createFile(['test'], {name: 'test.png'})]);
await settled();
@ -306,7 +306,7 @@ describe('Integration: Component: gh-uploader', function () {
this.set('onFailed', sinon.spy());
await render(hbs`
{{#gh-uploader files=files validate=(action validate) onFailed=(action onFailed)}}{{/gh-uploader}}
<GhUploader @files={{files}} @validate={{this.validate}} @onFailed={{this.onFailed}}></GhUploader>
`);
this.set('files', [createFile(['test'], {name: 'test.png'})]);
await settled();
@ -319,12 +319,12 @@ describe('Integration: Component: gh-uploader', function () {
it('yields errors when validation fails', async function () {
await render(hbs`
{{#gh-uploader files=files extensions="jpg,jpeg" as |uploader|}}
<GhUploader @files={{files}} @extensions="jpg,jpeg" as |uploader|>
{{#each uploader.errors as |error|}}
<div class="error-fileName">{{error.fileName}}</div>
<div class="error-message">{{error.message}}</div>
{{/each}}
{{/gh-uploader}}
</GhUploader>
`);
this.set('files', [createFile(['test'], {name: 'test.png'})]);
await settled();
@ -344,11 +344,8 @@ describe('Integration: Component: gh-uploader', function () {
this.set('uploadComplete', sinon.spy());
await render(hbs`
{{#gh-uploader
files=files
onFailed=(action uploadFailed)
onComplete=(action uploadComplete)}}
{{/gh-uploader}}
<GhUploader @files={{files}} @onFailed={{this.uploadFailed}} @onComplete={{this.uploadComplete}}>
</GhUploader>
`);
this.set('files', [
createFile(['test'], {name: 'file1.png'}),
@ -369,10 +366,8 @@ describe('Integration: Component: gh-uploader', function () {
this.set('uploadFail', sinon.spy());
await render(hbs`
{{#gh-uploader
files=files
onUploadFailure=(action uploadFail)}}
{{/gh-uploader}}
<GhUploader @files={{files}} @onUploadFailure={{this.uploadFail}}>
</GhUploader>
`);
this.set('files', [
createFile(['test'], {name: 'file1.png'}),
@ -393,12 +388,12 @@ describe('Integration: Component: gh-uploader', function () {
it('yields errors when uploads fail', async function () {
await render(hbs`
{{#gh-uploader files=files as |uploader|}}
<GhUploader @files={{files}} as |uploader|>
{{#each uploader.errors as |error|}}
<div class="error-fileName">{{error.fileName}}</div>
<div class="error-message">{{error.message}}</div>
{{/each}}
{{/gh-uploader}}
</GhUploader>
`);
this.set('files', [createFile(['test'], {name: 'test.png'})]);
await settled();

View File

@ -49,7 +49,7 @@ describe('Integration: Component: modal-import-members-test', function () {
});
it('renders', async function () {
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
expect(find('h1').textContent.trim(), 'default header')
.to.equal('Import members');
@ -60,7 +60,7 @@ describe('Integration: Component: modal-import-members-test', function () {
it('generates request to supplied endpoint', async function () {
stubSuccessfulUpload(server);
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
await waitFor('table', {timeout: 50});
@ -77,7 +77,7 @@ describe('Integration: Component: modal-import-members-test', function () {
it('displays server error', async function () {
stubFailedUpload(server, 415, 'UnsupportedMediaTypeError');
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -90,7 +90,7 @@ describe('Integration: Component: modal-import-members-test', function () {
it('displays file too large for server error', async function () {
stubFailedUpload(server, 413, 'RequestEntityTooLargeError');
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -105,7 +105,7 @@ describe('Integration: Component: modal-import-members-test', function () {
server.post(`${ghostPaths().apiRoot}/members/upload/`, function () {
return [413, {}, ''];
});
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -118,7 +118,7 @@ describe('Integration: Component: modal-import-members-test', function () {
it('displays other server-side error with message', async function () {
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -133,7 +133,7 @@ describe('Integration: Component: modal-import-members-test', function () {
server.post(`${ghostPaths().apiRoot}/members/upload/`, function () {
return [500, {'Content-Type': 'application/json'}, ''];
});
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -151,7 +151,7 @@ describe('Integration: Component: modal-import-members-test', function () {
stubFailedUpload(server, 400, 'VersionMismatchError');
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -167,7 +167,7 @@ describe('Integration: Component: modal-import-members-test', function () {
notifications.set('showAPIError', showAPIError);
stubFailedUpload(server, 400, 'UnknownError');
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});
// Wait for async CSV parsing to finish
@ -180,7 +180,7 @@ describe('Integration: Component: modal-import-members-test', function () {
it('validates extension by default', async function () {
stubFailedUpload(server, 415);
await render(hbs`{{modal-import-members}}`);
await render(hbs`<ModalImportMembers />`);
await fileUpload('input[type="file"]', ['name,email\r\nmembername,memberemail@example.com'], {name: 'test.csv'});

View File

@ -49,7 +49,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('has the correct title', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(find('.tag-settings-pane h4').textContent, 'existing tag title').to.equal('Tag settings');
@ -59,7 +59,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('renders main settings', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(findAll('.gh-image-uploader').length, 'displays image uploader').to.equal(1);
@ -72,7 +72,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('can switch between main/meta settings', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(find('.tag-settings-pane').classList.contains('settings-menu-pane-in'), 'main settings are displayed by default').to.be.true;
@ -95,7 +95,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
});
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
await fillIn('input[name="name"]', 'New name');
@ -129,7 +129,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
};
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
await testSetProperty('input[name="name"]', 'name', 'New name');
@ -159,7 +159,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
hasValidated.push('metaDescription');
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
let nameFormGroup = find('input[name="name"]').closest('.form-group');
@ -184,7 +184,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('displays char count for text fields', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
let descriptionFormGroup = find('textarea[name="description"]').closest('.form-group');
@ -196,7 +196,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('renders SEO title preview', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(find('.seo-preview-title').textContent, 'displays meta title if present').to.equal('Meta Title');
@ -210,7 +210,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('renders SEO URL preview', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(find('.seo-preview-link').textContent, 'adds url and tag prefix').to.equal('http://localhost:2368/tag/test/');
@ -221,7 +221,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('renders SEO description preview', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(find('.seo-preview-description').textContent, 'displays meta description if present').to.equal('Meta description');
@ -235,7 +235,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
it('resets if a new tag is received', async function () {
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
await click('.meta-data-button');
expect(find('.tag-meta-settings-pane').classList.contains('settings-menu-pane-in'), 'meta data pane is shown').to.be.true;
@ -252,7 +252,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
});
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProper}} /> showDeleteTagModal=(action openModal)}}
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} @showDeleteTagModal={{this.openModal}} />
`);
await click('.settings-menu-delete-button');
@ -264,7 +264,7 @@ describe.skip('Integration: Component: tags/tag-form', function () {
mediaQueries.set('maxWidth600', true);
await render(hbs`
<Tags::TagForm @tag={{this.tag}} @setProperty={{action setProperty}} />
<Tags::TagForm @tag={{this.tag}} @setProperty={{this.setProperty}} />
`);
expect(findAll('.tag-settings-pane .settings-menu-header .settings-menu-header-action').length, 'tags link is shown').to.equal(1);

View File

@ -29,8 +29,8 @@ describe('Integration: Helper: activity-feed-fetcher-test', function () {
await render(hbs`
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
<button class="previous" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
<button class="previous" type="button" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
<button class="next" type="button" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
<div class="shown-events">{{eventsFetcher.shownEvents}}</div>
<div class="total-events">{{eventsFetcher.totalEvents}}</div>
@ -71,8 +71,8 @@ describe('Integration: Helper: activity-feed-fetcher-test', function () {
await render(hbs`
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
<button class="previous" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
<button class="previous" type="button" {{on "click" eventsFetcher.loadPreviousPage}}>Previous page</button>
<button class="next" type="button" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
{{#each eventsFetcher.data as |event|}}
<div class="event-id">{{event.data.id}}</div>
@ -115,7 +115,7 @@ describe('Integration: Helper: activity-feed-fetcher-test', function () {
await render(hbs`
{{#let (activity-feed-fetcher pageSize="2") as |eventsFetcher|}}
<button class="next" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
<button class="next" type="button" {{on "click" eventsFetcher.loadNextPage}}>Next page</button>
<div class="error">{{eventsFetcher.isError}}</div>
<div class="error-message">{{eventsFetcher.errorMessage}}</div>

View File

@ -16,21 +16,23 @@ describe('Unit: Component: gh-url-preview', function () {
it('generates the correct preview URL with a prefix', async function () {
await render(hbs`
{{gh-url-preview
prefix="tag"
slug="test-slug"
tagName="p"
classNames="test-class"}}`);
<GhUrlPreview
@prefix="tag"
@slug="test-slug"
@tagName="p"
@classNames="test-class"
/>`);
expect(this.element).to.have.trimmed.text('my-ghost-blog.com/tag/test-slug/');
});
it('generates the correct preview URL without a prefix', async function () {
await render(hbs`
{{gh-url-preview
slug="test-slug"
tagName="p"
classNames="test-class"}}`);
<GhUrlPreview
@slug="test-slug"
@tagName="p"
@classNames="test-class"
/>`);
expect(this.element).to.have.trimmed.text('my-ghost-blog.com/test-slug/');
});

View File

@ -8789,6 +8789,11 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3"
integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@ -9006,7 +9011,7 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0, ci-info@^3.3.0, ci-info@^3.4.0:
ci-info@^3.2.0, ci-info@^3.3.0, ci-info@^3.7.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.1.tgz#708a6cdae38915d597afdf3b145f2f8e1ff55f3f"
integrity sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==
@ -11117,9 +11122,9 @@ ember-basic-dropdown@^3.0.11:
ember-truth-helpers "^2.1.0 || ^3.0.0"
ember-basic-dropdown@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/ember-basic-dropdown/-/ember-basic-dropdown-6.0.2.tgz#af47dbd544c605cf9cbc62225185616356aeef52"
integrity sha512-JgI/cy7eS/Y2WoQl7B2Mko/1aFTAlxr5d+KpQeH7rBKOFml7IQtLvhiDQrpU/FLkrQ9aLNEJtzwtDZV1xQxAKA==
version "6.0.1"
resolved "https://registry.yarnpkg.com/ember-basic-dropdown/-/ember-basic-dropdown-6.0.1.tgz#9844b8b263033c916e193fb15b91517a00192db0"
integrity sha512-8cmqHvho7fToAv2pauzLd3y9fUVtMu0+eBwsevjiuTdWUPLvkIvn745NbT5aempVmxfMq0oQLhjzK8VUd4gxaw==
dependencies:
"@ember/render-modifiers" "^2.0.4"
"@embroider/macros" "^1.2.0"
@ -11130,10 +11135,10 @@ ember-basic-dropdown@^6.0.0:
ember-cli-htmlbars "^6.0.1"
ember-cli-typescript "^4.2.1"
ember-element-helper "^0.6.0"
ember-get-config "^2.1.1"
ember-get-config "^1.0.2 || ^2.0.0"
ember-maybe-in-element "^2.0.3"
ember-modifier "^3.2.7"
ember-style-modifier "^0.8.0 || ^1.0.0"
ember-style-modifier "^0.8.0"
ember-truth-helpers "^2.1.0 || ^3.0.0"
ember-classic-decorator@3.0.1:
@ -11923,7 +11928,7 @@ ember-fetch@8.1.2:
ember-cli-babel "^7.26.6"
ember-cli-htmlbars "^5.7.1"
ember-get-config@^2.1.1:
"ember-get-config@^1.0.2 || ^2.0.0":
version "2.1.1"
resolved "https://registry.yarnpkg.com/ember-get-config/-/ember-get-config-2.1.1.tgz#bede76c25d95dbefab8d30064abf7aa00bc19235"
integrity sha512-uNmv1cPG/4qsac8oIf5txJ2FZ8p88LEpG4P3dNcjsJS98Y8hd0GPMFwVqpnzI78Lz7VYRGQWY4jnE4qm5R3j4g==
@ -12260,12 +12265,12 @@ ember-style-modifier@^0.7.0:
ember-cli-babel "^7.26.6"
ember-modifier "^3.0.0"
"ember-style-modifier@^0.8.0 || ^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/ember-style-modifier/-/ember-style-modifier-1.0.0.tgz#96e5d342a255d8c1cba1637779dbb1949322e139"
integrity sha512-ANkYpOeI3/tkRxVz750ymb8cQBqfBTKOUOz4RPRsNys8rlaBiaKEa95XLz1JWfCXCzjmqe8i2cIdnAMix+nb3A==
ember-style-modifier@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/ember-style-modifier/-/ember-style-modifier-0.8.0.tgz#ef46b3f288e63e3d850418ea8dc6f7b12edde721"
integrity sha512-I7M+oZ+poYYOP7n521rYv7kkYZbxotL8VbtHYxLQ3tasRZYQJ21qfu3vVjydSjwyE3w7EZRgKngBoMhKSAEZnw==
dependencies:
ember-cli-babel "^7.26.11"
ember-cli-babel "^7.26.6"
ember-modifier "^3.2.7"
ember-svg-jar@2.4.2:
@ -12303,24 +12308,25 @@ ember-template-imports@^3.4.0:
string.prototype.matchall "^4.0.6"
validate-peer-dependencies "^1.1.0"
ember-template-lint@4.18.2:
version "4.18.2"
resolved "https://registry.yarnpkg.com/ember-template-lint/-/ember-template-lint-4.18.2.tgz#18e5e5fc6ea7301e7a075e024008271d2a781e1e"
integrity sha512-yI8kQ8IQ2x5HVq0tQAISXABOHr0Is5sAg6rwceO6M8CYozq7HMxUPEj0VbdcbyIE70SWw/8d24M1rBI4km544Q==
ember-template-lint@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/ember-template-lint/-/ember-template-lint-5.3.0.tgz#da91f704d0055db8e69ff13b5f98488cc76a8322"
integrity sha512-P4GsqYDN3bvTgN8+v3LQsBQVfDnu/EJJzZH8LqAYZxFfRQmBeZMcMFjB6I8QS9NYkYKOXO4I4ApiJYtFHRXsUw==
dependencies:
"@lint-todo/utils" "^13.0.3"
aria-query "^5.0.2"
chalk "^4.1.2"
ci-info "^3.4.0"
chalk "^5.2.0"
ci-info "^3.7.0"
date-fns "^2.29.2"
ember-template-imports "^3.4.0"
ember-template-recast "^6.1.3"
eslint-formatter-kakoune "^1.0.0"
find-up "^6.3.0"
fuse.js "^6.5.3"
get-stdin "^9.0.0"
globby "^13.1.2"
is-glob "^4.0.3"
language-tags "^1.0.5"
language-tags "^1.0.6"
micromatch "^4.0.5"
resolve "^1.22.1"
v8-compile-cache "^2.3.0"
@ -12726,6 +12732,11 @@ eslint-config-react-app@^7.0.1:
eslint-plugin-react-hooks "^4.3.0"
eslint-plugin-testing-library "^5.0.1"
eslint-formatter-kakoune@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-formatter-kakoune/-/eslint-formatter-kakoune-1.0.0.tgz#a95cc4fe1fbc06b84e0f2397e83f5f0b68340125"
integrity sha512-Uk/TVLt6Nf6Xoz7C1iYuZjOSdJxe5aaauGRke8JhKeJwD66Y61/pY2FjtLP04Ooq9PwV34bzrkKkU2UZ5FtDRA==
eslint-import-resolver-node@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
@ -17614,7 +17625,7 @@ language-subtag-registry@^0.3.20:
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==
language-tags@^1.0.5:
language-tags@^1.0.5, language-tags@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.7.tgz#41cc248730f3f12a452c2e2efe32bc0bbce67967"
integrity sha512-bSytju1/657hFjgUzPAPqszxH62ouE8nQFoFaVlIQfne4wO/wXC9A4+m8jYve7YBBvi59eq0SUpcshvG8h5Usw==
@ -17784,7 +17795,7 @@ liquid-wormhole@3.0.0:
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.1.0"
ember-decorators "^6.1.1"
perf-primitives "github:rwwagner90/perf-primitives#a6a26f11497ca27be3763a88a5f20744e424756b"
perf-primitives rwwagner90/perf-primitives#a6a26f11497ca27be3763a88a5f20744e424756b
listr2@^5.0.5:
version "5.0.6"
@ -20722,7 +20733,6 @@ pend@~1.2.0:
"perf-primitives@github:rwwagner90/perf-primitives#a6a26f11497ca27be3763a88a5f20744e424756b":
version "0.0.6"
uid a6a26f11497ca27be3763a88a5f20744e424756b
resolved "https://codeload.github.com/rwwagner90/perf-primitives/tar.gz/a6a26f11497ca27be3763a88a5f20744e424756b"
dependencies:
ember-cli-babel "^7.26.6"