0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-18 02:21:47 -05:00

Removed emailClicks feature flag ()

fixes https://github.com/TryGhost/Team/issues/2028

Since link clicks became GA, some older components and templates are no longer used.
This commit is contained in:
Simon Backx 2022-10-07 14:27:57 +02:00 committed by GitHub
parent 2612b44c21
commit 7e3b41f643
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 302 additions and 707 deletions
ghost
admin
core
core
server
api/endpoints/utils/serializers
input
output/mappers
web/api/endpoints/admin
shared
test/e2e-api/admin/__snapshots__
members-api/lib/repositories

View file

@ -31,11 +31,11 @@
{{/if}}
{{#if event.url}}
<span class="gh-members-activity-event-join">{{event.join}}</span>
{{#if (feature "emailClicks")}}<span class="gh-members-activity-event-dash"></span>{{/if}}
<span class="gh-members-activity-event-dash"></span>
<a class="ghost-members-activity-object-link" href="{{event.url}}" target="_blank" rel="noopener noreferrer">{{event.object}}</a>
{{/if}}
{{#if event.email}}
{{#if (feature "emailClicks")}}<span class="gh-members-activity-event-dash"></span>{{/if}}
<span class="gh-members-activity-event-dash"></span>
<GhEmailPreviewLink @data={{event.email}} />
{{/if}}
</span>

View file

@ -26,11 +26,11 @@
{{/if}}
{{#if event.url}}
<span class="gh-members-activity-event-join">{{event.join}}</span>
{{#if (feature "emailClicks")}}<span class="gh-members-activity-event-dash"></span>{{/if}}
<span class="gh-members-activity-event-dash"></span>
<a class="ghost-members-activity-object-link" href="{{event.url}}" target="_blank" rel="noopener noreferrer">{{event.object}}</a>
{{/if}}
{{#if event.email}}
{{#if (feature "emailClicks")}}<span class="gh-members-activity-event-dash"></span>{{/if}}
<span class="gh-members-activity-event-dash"></span>
<GhEmailPreviewLink @data={{event.email}} />
{{/if}}
</span>

View file

@ -31,9 +31,9 @@ const FILTER_PROPERTIES = [
{label: 'Emails sent (all time)', name: 'email_count', group: 'Email'},
{label: 'Emails opened (all time)', name: 'email_opened_count', group: 'Email'},
{label: 'Open rate (all time)', name: 'email_open_rate', group: 'Email'},
{label: 'Received email', name: 'emails.post_id', group: 'Email', valueType: 'array', feature: 'emailClicks'},
{label: 'Opened email', name: 'opened_emails.post_id', group: 'Email', valueType: 'array', feature: 'emailClicks'},
{label: 'Clicked email', name: 'clicked_links.post_id', group: 'Email', valueType: 'array', feature: 'emailClicks'}
{label: 'Received email', name: 'emails.post_id', group: 'Email', valueType: 'array'},
{label: 'Opened email', name: 'opened_emails.post_id', group: 'Email', valueType: 'array'},
{label: 'Clicked email', name: 'clicked_links.post_id', group: 'Email', valueType: 'array'}
// {label: 'Emails sent (30 days)', name: 'x', group: 'Email'},
// {label: 'Emails opened (30 days)', name: 'x', group: 'Email'},

View file

@ -1,208 +0,0 @@
{{!-- template-lint-disable no-invalid-interactive --}}
<li class="gh-list-row gh-posts-list-item gh-posts-list-item-labs gh-post-list-plain-status"
{{on "mouseover" this.mouseOver}}
{{on "mouseleave" this.mouseLeave}}
...attributes
>
{{!-- Title column --}}
{{#if (and this.session.user.isContributor @post.isPublished)}}
<a href={{@post.url}} class="permalink gh-list-data gh-post-list-title" target="_blank" rel="noopener noreferrer">
<h3 class="gh-content-entry-title">
{{@post.title}} {{svg-jar "external" class="gh-post-list-external"}}
</h3>
{{#unless @hideAuthor }}
<p class="gh-content-entry-meta">
<span class="gh-content-entry-author">
By {{post-author-names @post}}
{{#if @post.primaryTag}}
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
{{/if}}
-
</span>
<span class="gh-content-entry-date">
{{#if this.isHovered}}
{{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}
{{else}}
{{gh-format-post-time @post.updatedAtUTC draft=true}}
{{/if}}
</span>
</p>
<p class="gh-content-entry-status">
<span class="published">
Published
{{#if @post.hasEmail}}
{{#if this.isHovered}}
and sent to {{gh-pluralize @post.email.emailCount "member"}}
{{else}}
and sent
{{/if}}
{{/if}}
</span>
</p>
{{/unless}}
</a>
{{else}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-title">
<h3 class="gh-content-entry-title">
{{@post.title}}
{{#if @post.lexical}}
<span class="gh-lexical-indicator">L</span>
{{/if}}
</h3>
{{#unless @hideAuthor }}
<p class="gh-content-entry-meta">
<span class="gh-content-entry-author">
By {{post-author-names @post}}
{{#if @post.primaryTag}}
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
{{/if}}
-
</span>
<span class="gh-content-entry-date" {{on "mouseover" (fn (mut this.isDateHovered) true)}} {{on "mouseleave" (fn (mut this.isDateHovered) false)}}>
{{gh-format-post-time @post.updatedAtUTC draft=true}}
{{#if this.isDateHovered}}
<span {{css-transition "anim-fade-in-scale"}}>on {{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}</span>
{{/if}}
</span>
{{!-- {{#if @post.lexical}}
<span class="gh-content-entry-date"> Lexical</span>
{{/if}} --}}
</p>
<p class="gh-content-entry-status">
{{#if @post.isScheduled}}
<span class="scheduled" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
<span class="status-dot"></span>
Scheduled
{{#if this.isStateHovered}}
<span class="schedule-details" {{css-transition "anim-fade-in-scale"}}>to be published {{if @post.newsletter "and sent "}}{{this.scheduledText}} to {{humanize-recipient-filter @post.emailSegment}}</span>
{{/if}}
</span>
{{/if}}
{{#if @post.isDraft}}
<span class="draft">
<span class="status-dot"></span>
Draft
</span>
{{/if}}
{{#if @post.isPublished}}
<span class="published {{this.errorClass}}" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
Published
{{#if @post.didEmailFail}}
but failed to send newsletter
{{else if @post.hasBeenEmailed}}
and sent
{{#if this.isHovered}}
<span {{css-transition "anim-fade-in-scale"}}>to {{gh-pluralize @post.email.emailCount "member"}}</span>
{{/if}}
{{/if}}
</span>
{{/if}}
{{#if @post.isSent}}
<span class="sent {{this.errorClass}}" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
{{#if @post.didEmailFail}}
Failed to send newsletter
{{else}}
Sent
{{#if this.isHovered}}
<span {{css-transition "anim-fade-in-scale"}}>to {{gh-pluralize @post.email.emailCount "member"}}</span>
{{/if}}
{{/if}}
</span>
{{/if}}
</p>
{{/unless}}
</LinkTo>
{{/if}}
{{!-- Opened / Signups column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-opens">
{{#if (and @post.showEmailOpenAnalytics @post.showEmailClickAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "opened_emails.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.email.openedCount}}
{{else}}
{{@post.email.openRate}}<sup>%</sup>
{{/if}}
</span>
<span class="gh-content-email-stats">
opened
</span>
</LinkTo>
{{else if (and @post.isPage @post.showAttributionAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "signup:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{@post.count.signups}}
</span>
<span class="gh-content-email-stats">
signups
</span>
</LinkTo>
{{/if}}
</LinkTo>
{{!-- Clicked / Conversions column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-clicks">
{{#unless @post.showEmailClickAnalytics}}
{{#if @post.showEmailOpenAnalytics }}
<LinkTo @route="members" @query={{hash filterParam=(concat "opened_emails.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.email.openedCount}}
{{else}}
{{@post.email.openRate}}<sup>%</sup>
{{/if}}
</span>
<span class="gh-content-email-stats">
opened
</span>
</LinkTo>
{{/if}}
{{/unless}}
{{#if @post.showEmailClickAnalytics }}
<LinkTo @route="members" @query={{hash filterParam=(concat "clicked_links.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isClickStatHovered) true)}} {{on "mouseleave" (fn (mut this.isClickStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.count.clicks}}
{{else}}
{{@post.clickRate}}<sup>%</sup>
{{/if}}
</span>
<span class="gh-content-email-stats">
clicked
</span>
</LinkTo>
{{else if (and @post.isPage @post.showPaidAttributionAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "conversion:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isClickStatHovered) true)}} {{on "mouseleave" (fn (mut this.isClickStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{@post.count.paid_conversions}}
</span>
<span class="gh-content-email-stats">
conversions
</span>
</LinkTo>
{{/if}}
</LinkTo>
{{!-- Button column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-button">
<div class="gh-list-data-inner">
{{#if @post.hasAnalyticsPage }}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="gh-post-list-cta stats {{if this.isHovered "is-hovered"}}" title="">
{{svg-jar "stats" title=""}}
</LinkTo>
{{else}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="gh-post-list-cta edit {{if this.isHovered "is-hovered"}}" title="">
{{svg-jar "pen" title=""}}
</LinkTo>
{{/if}}
</div>
</LinkTo>
</li>

View file

@ -1,60 +0,0 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {formatPostTime} from 'ghost-admin/helpers/gh-format-post-time';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';
export default class PostsListItemClicks extends Component {
@service feature;
@service session;
@service settings;
@tracked isHovered = false;
get post() {
return this.args.post;
}
get errorClass() {
if (this.post.didEmailFail) {
return 'error';
}
return '';
}
get scheduledText() {
let text = [];
let formattedTime = formatPostTime(
this.post.publishedAtUTC,
{timezone: this.settings.get('timezone'), scheduled: true}
);
text.push(formattedTime);
return text.join(' ');
}
get routeForLink() {
if (this.post.hasAnalyticsPage) {
return 'posts.analytics';
}
return 'editor.edit';
}
get modelsForLink() {
if (this.post.hasAnalyticsPage) {
return [this.post];
}
return [this.post.displayName, this.post.id];
}
@action
mouseOver() {
this.isHovered = true;
}
@action
mouseLeave() {
this.isHovered = false;
}
}

View file

@ -1,5 +1,5 @@
{{!-- template-lint-disable no-invalid-interactive --}}
<li class="gh-list-row gh-posts-list-item {{if this.feature.memberAttribution "gh-post-list-plain-status"}}"
<li class="gh-list-row gh-posts-list-item gh-posts-list-item-labs gh-post-list-plain-status"
{{on "mouseover" this.mouseOver}}
{{on "mouseleave" this.mouseLeave}}
...attributes
@ -12,22 +12,40 @@
{{@post.title}} {{svg-jar "external" class="gh-post-list-external"}}
</h3>
{{#unless @hideAuthor }}
<p>
<span class="gh-content-entry-meta">
By <span class="midgrey-l2 fw5">{{post-author-names @post}}</span>
<p class="gh-content-entry-meta">
<span class="gh-content-entry-author">
By {{post-author-names @post}}
{{#if @post.primaryTag}}
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
{{/if}}
• <span data-tooltip="{{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}">{{gh-format-post-time @post.updatedAtUTC draft=true}}</span>
-
</span>
<span class="gh-content-entry-date">
{{#if this.isHovered}}
{{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}
{{else}}
{{gh-format-post-time @post.updatedAtUTC draft=true}}
{{/if}}
</span>
</p>
<p class="gh-content-entry-status">
<span class="published">
Published
{{#if @post.hasEmail}}
{{#if this.isHovered}}
and sent to {{gh-pluralize @post.email.emailCount "member"}}
{{else}}
and sent
{{/if}}
{{/if}}
</span>
</p>
{{/unless}}
</a>
{{else}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-title">
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-title">
<h3 class="gh-content-entry-title">
{{@post.title}}
{{#if @post.lexical}}
@ -35,194 +53,156 @@
{{/if}}
</h3>
{{#unless @hideAuthor }}
<p>
<span class="gh-content-entry-meta">
By <span class="midgrey-l2 fw5">{{post-author-names @post}}</span>
<p class="gh-content-entry-meta">
<span class="gh-content-entry-author">
By {{post-author-names @post}}
{{#if @post.primaryTag}}
in <span class="midgrey-l2 fw5">{{@post.primaryTag.name}}</span>
{{/if}}
• <span data-tooltip="{{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}">{{gh-format-post-time @post.updatedAtUTC draft=true}}</span>
-
</span>
<span class="gh-content-entry-date" {{on "mouseover" (fn (mut this.isDateHovered) true)}} {{on "mouseleave" (fn (mut this.isDateHovered) false)}}>
{{gh-format-post-time @post.updatedAtUTC draft=true}}
{{#if this.isDateHovered}}
<span {{css-transition "anim-fade-in-scale"}}>on {{gh-format-post-time @post.updatedAtUTC format="D MMM YYYY"}}</span>
{{/if}}
</span>
{{!-- {{#if @post.lexical}}
<span class="gh-content-entry-date"> Lexical</span>
{{/if}} --}}
</p>
<p class="gh-content-entry-status">
{{#if @post.isScheduled}}
<span class="scheduled" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
<span class="status-dot"></span>
Scheduled
{{#if this.isStateHovered}}
<span class="schedule-details" {{css-transition "anim-fade-in-scale"}}>to be published {{if @post.newsletter "and sent "}}{{this.scheduledText}} to {{humanize-recipient-filter @post.emailSegment}}</span>
{{/if}}
</span>
{{/if}}
{{#if @post.isDraft}}
<span class="draft">
<span class="status-dot"></span>
Draft
</span>
{{/if}}
{{#if @post.isPublished}}
<span class="published {{this.errorClass}}" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
Published
{{#if @post.didEmailFail}}
but failed to send newsletter
{{else if @post.hasBeenEmailed}}
and sent
{{#if this.isHovered}}
<span {{css-transition "anim-fade-in-scale"}}>to {{gh-pluralize @post.email.emailCount "member"}}</span>
{{/if}}
{{/if}}
</span>
{{/if}}
{{#if @post.isSent}}
<span class="sent {{this.errorClass}}" {{on "mouseover" (fn (mut this.isStateHovered) true)}} {{on "mouseleave" (fn (mut this.isStateHovered) false)}}>
{{#if @post.didEmailFail}}
Failed to send newsletter
{{else}}
Sent
{{#if this.isHovered}}
<span {{css-transition "anim-fade-in-scale"}}>to {{gh-pluralize @post.email.emailCount "member"}}</span>
{{/if}}
{{/if}}
</span>
{{/if}}
</p>
{{/unless}}
</LinkTo>
{{/if}}
{{!-- Statuses for when the feature flag for Member Attribution is on only --}}
{{#if this.feature.memberAttribution}}
{{#unless @hideStatusColumn }}
{{#if (and this.session.user.isContributor @post.isPublished)}}
<a href={{@post.url}} class="permalink gh-list-data gh-post-list-status" target="_blank" rel="noopener noreferrer">
<div class="flex items-center">
<span class="gh-content-status-published nowrap">
{{svg-jar "check" class="gh-post-status-icon"}}
Published
{{#if @post.hasEmail}}
&amp; Sent
{{/if}}
</span>
</div>
</a>
{{else}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-status">
<div class="flex items-center">
{{#if @post.isScheduled}}
<span class="gh-content-status-scheduled gh-badge nowrap" title="Scheduled" data-tooltip="To be published {{if @post.newsletter "& sent at "}}{{capitalize this.scheduledText}} to {{@post.emailSegment}} members">
{{svg-jar "clock" class="gh-post-status-icon"}}
Scheduled
</span>
{{/if}}
{{#if @post.isDraft}}
<span class="gh-content-status-draft gh-badge gh-badge-pink nowrap">
{{svg-jar "pen" class="gh-post-status-icon"}}
Draft
</span>
{{/if}}
{{#if @post.isPublished}}
<span class="gh-content-status-published nowrap">
{{svg-jar "check" class="gh-post-status-icon"}}
Published
{{#if @post.hasEmail}}
&amp; Sent
{{/if}}
</span>
{{/if}}
{{#if @post.isSent}}
<span class="gh-content-status-emailed nowrap">
{{svg-jar "email-stroke" class="gh-post-status-icon"}}
Sent
</span>
{{/if}}
</div>
</LinkTo>
{{/if}}
{{/unless}}
{{/if}}
{{#if (and this.feature.memberAttribution (not this.session.user.isContributor)) }}
{{#if @post.count.signups}}
<LinkTo @route="members" @query={{hash filterParam=(concat "signup:[" @post.id "]") }} class="permalink gh-list-data gh-post-list-signups active">
<span class="midlightgrey {{if (not (eq @post.count.signups 0)) 'darkgrey'}} fw5 gh-content-attribution-stats">{{@post.count.signups}}</span>
<span class="midgrey-l2 fw4 gh-content-attribution-stats-mobile">{{gh-pluralize @post.count.signups "signup"}}</span>
</LinkTo>
{{else}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-signups">
<span class="midlightgrey {{if (not (eq @post.count.signups 0)) 'darkgrey'}} fw5 gh-content-attribution-stats">{{@post.count.signups}}</span>
<span class="midgrey-l2 fw4 gh-content-attribution-stats-mobile">{{gh-pluralize @post.count.signups "signup"}}</span>
</LinkTo>
{{/if}}
{{/if}}
{{#if (and this.feature.memberAttribution (not this.session.user.isContributor)) }}
{{#if @post.count.paid_conversions}}
<LinkTo @route="members" @query={{hash filterParam=(concat "conversion:[" @post.id "]") }} class="permalink gh-list-data gh-post-list-conversions active">
<span class="midlightgrey {{if (not (eq @post.count.paid_conversions 0)) 'darkgrey'}} fw5 gh-content-attribution-stats">{{@post.count.paid_conversions}}</span>
<span class="midgrey-l2 fw4 gh-content-attribution-stats-mobile">{{gh-pluralize @post.count.paid_conversions "conversion"}}</span>
</LinkTo>
{{else}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-conversions">
<span class="midlightgrey {{if (not (eq @post.count.paid_conversions 0)) 'darkgrey'}} fw5 gh-content-attribution-stats">{{@post.count.paid_conversions}}</span>
<span class="midgrey-l2 fw4 gh-content-attribution-stats-mobile">{{gh-pluralize @post.count.paid_conversions "conversion"}}</span>
</LinkTo>
{{/if}}
{{/if}}
{{!-- Sends/Opens columns --}}
{{#if (and (not-eq this.settings.membersSignupAccess "none") (not-eq this.settings.editorDefaultEmailRecipients "disabled") (not this.session.user.isContributor))}}
{{#if (and this.feature.emailAnalytics (eq @post.displayName "post"))}}
{{!-- Sends column --}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-recipients">
<div class="flex fw4">
{{#if (eq @post.email.status "submitted")}}
<span class="flex" data-tooltip={{humanize-recipient-filter @post.email.recipientFilter}}>
<span class="darkgrey fw5 gh-content-email-stats">{{format-number @post.email.emailCount}}</span>
<span class="midgrey-l2 fw4 gh-content-email-stats-mobile">{{gh-pluralize @post.email.emailCount "send"}}</span>
</span>
{{!-- Opened / Signups column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-opens">
{{#if (and @post.showEmailOpenAnalytics @post.showEmailClickAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "opened_emails.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.email.openedCount}}
{{else}}
<span class="gh-list-nodata">&mdash;</span>
{{@post.email.openRate}}<sup>%</sup>
{{/if}}
</div>
</span>
<span class="gh-content-email-stats">
opened
</span>
</LinkTo>
{{!-- Opens column --}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-opens">
{{#if (and @post.email.trackOpens (eq @post.email.status "submitted"))}}
<div class="flex">
{{#if this.feature.memberAttribution}}
<span class="gh-list-rate-bar">
<span class="gh-list-rate-number" data-tooltip="Opens: {{format-number @post.email.openedCount}}">{{@post.email.openRate}}%&nbsp;</span>
<span class="gh-list-rate-amount"><span style={{html-safe (concat "width: " @post.email.openRate "%;")}}/></span>
</span>
{{else}}
<span class="darkgrey fw5 gh-content-email-stats">
{{#if this.isHovered}}
{{format-number @post.email.openedCount}}
{{else}}
{{@post.email.openRate}}%&nbsp;
{{/if}}
</span>
{{/if}}
<span class="midgrey-l2 fw4 gh-content-email-stats-mobile">{{@post.email.openRate}}% opens</span>
</div>
{{else}}
<span class="gh-list-nodata">&mdash;</span>
{{/if}}
{{else if (and @post.isPage @post.showAttributionAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "signup:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{@post.count.signups}}
</span>
<span class="gh-content-email-stats">
signups
</span>
</LinkTo>
{{/if}}
{{/if}}
{{!-- Statuses for without the Member Attribution feature flag --}}
{{#unless this.feature.memberAttribution}}
{{#unless @hideStatusColumn }}
{{#if (and this.session.user.isContributor @post.isPublished)}}
<a href={{@post.url}} class="permalink gh-list-data gh-post-list-status" target="_blank" rel="noopener noreferrer">
<div class="flex items-center">
<span class="gh-content-status-published nowrap">
Published
{{#if @post.hasEmail}}
{{svg-jar "email-stroke" class="gh-post-status-email"}}
{{/if}}
</span>
</div>
</a>
{{else}}
<LinkTo @route="editor.edit" @models={{array @post.displayName @post.id}} class="permalink gh-list-data gh-post-list-status">
<div class="flex items-center">
{{#if @post.isScheduled}}
<span class="gh-content-status-scheduled gh-badge nowrap" title="Scheduled" data-tooltip="To be published {{if @post.newsletter "& sent at "}}{{capitalize this.scheduledText}} to {{@post.emailSegment}} members">
Scheduled
</span>
</LinkTo>
{{!-- Clicked / Conversions column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-clicks">
{{#unless @post.showEmailClickAnalytics}}
{{#if @post.showEmailOpenAnalytics }}
<LinkTo @route="members" @query={{hash filterParam=(concat "opened_emails.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isOpenStatHovered) true)}} {{on "mouseleave" (fn (mut this.isOpenStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.email.openedCount}}
{{else}}
{{@post.email.openRate}}<sup>%</sup>
{{/if}}
{{#if @post.isDraft}}
<span class="gh-content-status-draft gh-badge gh-badge-pink nowrap">
Draft
</span>
{{/if}}
{{#if @post.isPublished}}
<span class="gh-content-status-published nowrap">
Published
{{#if @post.hasEmail}}
{{svg-jar "email-stroke" class="gh-post-status-email"}}
{{/if}}
</span>
{{/if}}
{{#if @post.isSent}}
<span class="gh-content-status-emailed nowrap">
{{svg-jar "email-stroke" class="gh-post-status-icon"}}
</span>
{{/if}}
</div>
</span>
<span class="gh-content-email-stats">
opened
</span>
</LinkTo>
{{/if}}
{{/unless}}
{{/unless}}
{{#if @post.showEmailClickAnalytics }}
<LinkTo @route="members" @query={{hash filterParam=(concat "clicked_links.post_id:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isClickStatHovered) true)}} {{on "mouseleave" (fn (mut this.isClickStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{#if this.isHovered}}
{{format-number @post.count.clicks}}
{{else}}
{{@post.clickRate}}<sup>%</sup>
{{/if}}
</span>
<span class="gh-content-email-stats">
clicked
</span>
</LinkTo>
{{else if (and @post.isPage @post.showPaidAttributionAnalytics) }}
<LinkTo @route="members" @query={{hash filterParam=(concat "conversion:[" @post.id "]") }} class="flex flex-column gh-post-row-event" {{on "mouseover" (fn (mut this.isClickStatHovered) true)}} {{on "mouseleave" (fn (mut this.isClickStatHovered) false)}}>
<span class="gh-content-email-stats-value">
{{@post.count.paid_conversions}}
</span>
<span class="gh-content-email-stats">
conversions
</span>
</LinkTo>
{{/if}}
</LinkTo>
{{!-- Button column --}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="permalink gh-list-data gh-post-list-button">
<div class="gh-list-data-inner">
{{#if @post.hasAnalyticsPage }}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="gh-post-list-cta stats {{if this.isHovered "is-hovered"}}" title="">
{{svg-jar "stats" title=""}}
</LinkTo>
{{else}}
<LinkTo @route={{this.routeForLink}} @models={{this.modelsForLink}} class="gh-post-list-cta edit {{if this.isHovered "is-hovered"}}" title="">
{{svg-jar "pen" title=""}}
</LinkTo>
{{/if}}
</div>
</LinkTo>
</li>

View file

@ -4,19 +4,29 @@ import {formatPostTime} from 'ghost-admin/helpers/gh-format-post-time';
import {inject as service} from '@ember/service';
import {tracked} from '@glimmer/tracking';
export default class PostsListItem extends Component {
export default class PostsListItemClicks extends Component {
@service feature;
@service session;
@service settings;
@tracked isHovered = false;
get post() {
return this.args.post;
}
get errorClass() {
if (this.post.didEmailFail) {
return 'error';
}
return '';
}
get scheduledText() {
let {post} = this.args;
let text = [];
let formattedTime = formatPostTime(
post.publishedAtUTC,
this.post.publishedAtUTC,
{timezone: this.settings.get('timezone'), scheduled: true}
);
text.push(formattedTime);
@ -24,6 +34,20 @@ export default class PostsListItem extends Component {
return text.join(' ');
}
get routeForLink() {
if (this.post.hasAnalyticsPage) {
return 'posts.analytics';
}
return 'editor.edit';
}
get modelsForLink() {
if (this.post.hasAnalyticsPage) {
return [this.post];
}
return [this.post.displayName, this.post.id];
}
@action
mouseOver() {
this.isHovered = true;

View file

@ -141,89 +141,61 @@
</div>
{{/unless}}
{{#if this.feature.emailClicks }}
<div class="gh-expandable-block">
<div class="gh-expandable-header">
<div>
<h4 class="gh-expandable-title">Newsletter analytics</h4>
<p class="gh-expandable-description">Track how many members are opening emails and clicking links</p>
</div>
<button type="button" class="gh-btn" {{on "click" (toggle-action "newsletterTrackingOpen" this)}} data-test-toggle-membersemail>
<span>{{if this.newsletterTrackingOpen "Close" "Expand"}}</span>
</button>
<div class="gh-expandable-block">
<div class="gh-expandable-header">
<div>
<h4 class="gh-expandable-title">Newsletter analytics</h4>
<p class="gh-expandable-description">Track how many members are opening emails and clicking links</p>
</div>
<div class="gh-expandable-content">
{{#liquid-if this.newsletterTrackingOpen}}
<div class="mb6">
<div class="gh-newsletter-tracking">
<div class="gh-newsletter-tracking-row">
<div>
<h4 class="gh-newsletter-tracking-title">Track newsletter opens</h4>
</div>
<div class="for-switch">
<label class="switch" data-test-label="email-track-opens">
<input
id="email-track-opens"
type="checkbox"
checked={{this.settings.emailTrackOpens}}
class="gh-input"
{{on "change" this.toggleEmailTrackOpens}}
data-test-checkbox="email-track-opens"
>
<span class="input-toggle-component mt1"></span>
</label>
</div>
<button type="button" class="gh-btn" {{on "click" (toggle-action "newsletterTrackingOpen" this)}} data-test-toggle-analytics>
<span>{{if this.newsletterTrackingOpen "Close" "Expand"}}</span>
</button>
</div>
<div class="gh-expandable-content">
{{#liquid-if this.newsletterTrackingOpen}}
<div class="mb6">
<div class="gh-newsletter-tracking">
<div class="gh-newsletter-tracking-row">
<div>
<h4 class="gh-newsletter-tracking-title">Track newsletter opens</h4>
</div>
<div class="gh-newsletter-tracking-row">
<div>
<h4 class="gh-newsletter-tracking-title">Track newsletter link clicks</h4>
</div>
<div class="for-switch">
<label class="switch" data-test-label="email-track-opens">
<input
id="email-track-clicks"
type="checkbox"
checked={{this.settings.emailTrackClicks}}
class="gh-input"
{{on "change" this.toggleEmailTrackClicks}}
data-test-checkbox="email-track-clicks"
>
<span class="input-toggle-component mt1"></span>
</label>
</div>
<div class="for-switch">
<label class="switch" data-test-label="email-track-opens">
<input
id="email-track-opens"
type="checkbox"
checked={{this.settings.emailTrackOpens}}
class="gh-input"
{{on "change" this.toggleEmailTrackOpens}}
data-test-checkbox="email-track-opens"
>
<span class="input-toggle-component mt1"></span>
</label>
</div>
</div>
<div class="gh-newsletter-tracking-row">
<div>
<h4 class="gh-newsletter-tracking-title">Track newsletter link clicks</h4>
</div>
<div class="for-switch">
<label class="switch" data-test-label="email-track-clicks">
<input
id="email-track-clicks"
type="checkbox"
checked={{this.settings.emailTrackClicks}}
class="gh-input"
{{on "change" this.toggleEmailTrackClicks}}
data-test-checkbox="email-track-clicks"
>
<span class="input-toggle-component mt1"></span>
</label>
</div>
</div>
</div>
{{/liquid-if}}
</div>
</div>
{{else}}
<div class="gh-expandable-block">
<div class="gh-expandable-header">
<div>
<h4 class="gh-expandable-title">Enable newsletter open-rate</h4>
<p class="gh-expandable-description">Track how many members are reading your emails</p>
</div>
<div class="for-switch">
<label class="switch" data-test-label="email-track-opens">
<input
id="email-track-opens"
type="checkbox"
checked={{this.settings.emailTrackOpens}}
class="gh-input"
{{on "change" this.toggleEmailTrackOpens}}
data-test-checkbox="email-track-opens"
>
<span class="input-toggle-component mt1"></span>
</label>
</div>
</div>
{{/liquid-if}}
</div>
{{/if}}
</div>
</div>
</section>
{{/if}}

View file

@ -83,14 +83,6 @@ export default class PostsRoute extends AuthenticatedRoute {
setupController(controller) {
super.setupController(...arguments);
if (this.modelName === 'post') {
if (this.feature.get('emailClicks')) {
this.templateName = 'posts-clicks';
} else {
this.templateName = 'posts';
}
}
if (!controller._hasLoadedTags) {
this.store.query('tag', {limit: 'all'}).then(() => {
controller._hasLoadedTags = true;

View file

@ -63,7 +63,6 @@ export default class FeatureService extends Service {
@feature('compExpiring') compExpiring;
@feature('memberAttribution') memberAttribution;
@feature('emailAlerts') emailAlerts;
@feature('emailClicks') emailClicks;
@feature('sourceAttribution') sourceAttribution;
@feature('lexicalEditor') lexicalEditor;

View file

@ -29,32 +29,11 @@
<section class="view-container content-list">
<div class="{{if this.feature.memberAttribution 'gh-list-sticky'}}">
<ol class="pages-list gh-list {{unless this.postsInfinityModel "no-posts"}} {{if this.feature.memberAttribution 'feature-memberAttribution'}}">
{{#unless this.feature.emailClicks}}
{{#if this.postsInfinityModel}}
<li class="gh-list-row header">
<div class="gh-list-header gh-posts-title-header">Title</div>
<div class="gh-list-header gh-posts-status-header">{{#unless this.feature.memberAttribution}}Status{{/unless}}</div>
{{#if this.feature.memberAttribution}}
<div class="gh-list-header gh-posts-signups-header">Signups</div>
<div class="gh-list-header gh-posts-conversions-header">Conversions</div>
{{/if}}
</li>
{{/if}}
{{/unless}}
{{#each this.postsInfinityModel as |page|}}
{{#if this.feature.emailClicks}}
<PostsList::ListItemClicks
@post={{page}}
data-test-page-id={{page.id}}
/>
{{/if}}
{{#unless this.feature.emailClicks}}
<PostsList::ListItem
@post={{page}}
data-test-page-id={{page.id}}
/>
{{/unless}}
<PostsList::ListItem
@post={{page}}
data-test-page-id={{page.id}}
/>
{{else}}
<li class="no-posts-box">
<div class="no-posts">

View file

@ -1,64 +0,0 @@
<section class="gh-canvas gh-canvas-sticky">
<GhCanvasHeader class="gh-canvas-header sticky break tablet post-header">
<GhCustomViewTitle @title={{if this.session.user.isContributor (concat this.config.blogTitle " posts") "Posts"}} @query={{reset-query-params "posts"}} />
<section class="view-actions">
<PostsList::ContentFilter
@currentUser={{this.session.user}}
@selectedType={{this.selectedType}}
@availableTypes={{this.availableTypes}}
@onTypeChange={{action "changeType"}}
@selectedVisibility={{this.selectedVisibility}}
@availableVisibilities={{this.availableVisibilities}}
@onVisibilityChange={{action "changeVisibility"}}
@selectedAuthor={{this.selectedAuthor}}
@availableAuthors={{this.availableAuthors}}
@onAuthorChange={{action "changeAuthor"}}
@selectedTag={{this.selectedTag}}
@availableTags={{this.availableTags}}
@onTagChange={{action "changeTag"}}
@selectedOrder={{this.selectedOrder}}
@availableOrders={{this.availableOrders}}
@onOrderChange={{action "changeOrder"}}
/>
<LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-primary view-actions-top-row" data-test-new-post-button={{true}}><span>New post</span></LinkTo>
</section>
</GhCanvasHeader>
<section class="view-container content-list">
<ol class="posts-list gh-list {{unless this.postsInfinityModel "no-posts"}} feature-memberAttribution">
{{#each this.postsInfinityModel as |post|}}
<PostsList::ListItemClicks
@post={{post}}
data-test-post-id={{post.id}}
/>
{{else}}
<li class="no-posts-box">
<div class="no-posts">
{{#if this.showingAll}}
{{svg-jar "posts-placeholder" class="gh-posts-placeholder"}}
<h4>Start creating content.</h4>
<LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-green">
<span>Write a new post</span>
</LinkTo>
{{else}}
<h4>No posts match the current filter</h4>
<LinkTo @route="posts" @query={{hash type=null author=null tag=null}} class="gh-btn">
<span>Show all posts</span>
</LinkTo>
{{/if}}
</div>
</li>
{{/each}}
</ol>
<GhInfinityLoader
@infinityModel={{this.postsInfinityModel}}
@scrollable=".gh-main"
@triggerOffset={{1000}} />
</section>
{{outlet}}
</section>

View file

@ -27,52 +27,32 @@
</GhCanvasHeader>
<section class="view-container content-list">
<div class="{{if this.feature.memberAttribution 'gh-list-sticky'}}">
<ol class="posts-list gh-list {{unless this.postsInfinityModel "no-posts"}} {{if this.feature.memberAttribution 'feature-memberAttribution'}}">
{{#if this.postsInfinityModel}}
<li class="gh-list-row header">
<div class="gh-list-header gh-posts-title-header">Title</div>
<ol class="posts-list gh-list {{unless this.postsInfinityModel "no-posts"}} feature-memberAttribution">
{{#if (and this.feature.memberAttribution (not this.session.user.isContributor)) }}
<div class="gh-list-header gh-posts-status-header"></div>
<div class="gh-list-header gh-posts-signups-header">Signups</div>
<div class="gh-list-header gh-posts-conversions-header">Paid</div>
{{/if}}
{{#if (and (not-eq this.settings.membersSignupAccess "none") (not-eq this.settings.editorDefaultEmailRecipients "disabled") (not this.session.user.isContributor) this.feature.emailAnalytics)}}
<div class="gh-list-header gh-posts-sends-header">Sends</div>
<div class="gh-list-header gh-posts-opens-header">Opens</div>
{{/if}}
{{#if (or (not this.feature.memberAttribution) this.session.user.isContributor) }}
<div class="gh-list-header gh-posts-status-header">Status</div>
{{/if}}
</li>
{{/if}}
{{#each this.postsInfinityModel as |post|}}
<PostsList::ListItem
@post={{post}}
data-test-post-id={{post.id}}
/>
{{else}}
<li class="no-posts-box">
<div class="no-posts">
{{#if this.showingAll}}
{{svg-jar "posts-placeholder" class="gh-posts-placeholder"}}
<h4>Start creating content.</h4>
<LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-green">
<span>Write a new post</span>
</LinkTo>
{{else}}
<h4>No posts match the current filter</h4>
<LinkTo @route="posts" @query={{hash type=null author=null tag=null}} class="gh-btn">
<span>Show all posts</span>
</LinkTo>
{{/if}}
</div>
</li>
{{/each}}
</ol>
</div>
{{#each this.postsInfinityModel as |post|}}
<PostsList::ListItem
@post={{post}}
data-test-post-id={{post.id}}
/>
{{else}}
<li class="no-posts-box">
<div class="no-posts">
{{#if this.showingAll}}
{{svg-jar "posts-placeholder" class="gh-posts-placeholder"}}
<h4>Start creating content.</h4>
<LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-green">
<span>Write a new post</span>
</LinkTo>
{{else}}
<h4>No posts match the current filter</h4>
<LinkTo @route="posts" @query={{hash type=null author=null tag=null}} class="gh-btn">
<span>Show all posts</span>
</LinkTo>
{{/if}}
</div>
</li>
{{/each}}
</ol>
<GhInfinityLoader
@infinityModel={{this.postsInfinityModel}}

View file

@ -35,7 +35,7 @@ describe('Acceptance: Error Handling', function () {
this.server.put('/posts/:id', versionMismatchResponse);
await visit('/posts');
await click('.posts-list li:nth-of-type(2) a'); // select second post
await click('.posts-list li:nth-of-type(1) a'); // select first draft post (otherwise no automatic saving on blur)
await fillIn('[data-test-editor-title-input]', 'Updated post');
await blur('[data-test-editor-title-input]');

View file

@ -126,6 +126,8 @@ describe('Acceptance: Settings - Newsletters', function () {
this.server.db.settings.update({key: 'email_track_opens'}, {value: 'true'});
await visit('/settings/newsletters');
await click('[data-test-toggle-analytics]');
expect(find('[data-test-checkbox="email-track-opens"]')).to.be.checked;
await click('[data-test-label="email-track-opens"]');
@ -136,6 +138,22 @@ describe('Acceptance: Settings - Newsletters', function () {
expect(this.server.db.settings.findBy({key: 'email_track_opens'}).value).to.equal(false);
});
it('can manage click tracking', async function () {
this.server.db.settings.update({key: 'email_track_clicks'}, {value: 'true'});
await visit('/settings/newsletters');
await click('[data-test-toggle-analytics]');
expect(find('[data-test-checkbox="email-track-clicks"]')).to.be.checked;
await click('[data-test-label="email-track-clicks"]');
expect(find('[data-test-checkbox="email-track-clicks"]')).to.not.be.checked;
await click('[data-test-button="save-members-settings"]');
expect(this.server.db.settings.findBy({key: 'email_track_clicks'}).value).to.equal(false);
});
describe('Creating newsletters', function () {
it('can create new newsletter', async function () {
await visit('/settings/newsletters');

View file

@ -6,7 +6,6 @@ const localUtils = require('../../index');
const mobiledoc = require('../../../../../lib/mobiledoc');
const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
const clean = require('./utils/clean');
const labs = require('../../../../../../shared/labs');
function removeSourceFormats(frame) {
if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
@ -25,11 +24,7 @@ function defaultRelations(frame) {
return false;
}
if (labs.isSet('emailClicks')) {
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
} else {
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions'];
}
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
}
function setDefaultOrder(frame) {

View file

@ -10,7 +10,6 @@ const extraAttrs = require('../utils/extra-attrs');
const gating = require('../utils/post-gating');
const url = require('../utils/url');
const labs = require('../../../../../../../shared/labs');
const utils = require('../../../index');
const postsMetaSchema = require('../../../../../../data/schema').tables.posts_meta;
@ -110,20 +109,14 @@ module.exports = async (model, frame, options = {}) => {
});
}
if (labs.isSet('emailClicks')) {
if (jsonModel.email && jsonModel.count) {
jsonModel.email.opened_count = Math.min(
Math.max(
jsonModel.email.opened_count || 0,
jsonModel.count.clicks || 0
),
jsonModel.email.email_count
);
}
}
if (!labs.isSet('memberAttribution') && !labs.isSet('emailClicks')) {
delete jsonModel.count;
if (jsonModel.email && jsonModel.count) {
jsonModel.email.opened_count = Math.min(
Math.max(
jsonModel.email.opened_count || 0,
jsonModel.count.clicks || 0
),
jsonModel.email.email_count
);
}
return jsonModel;

View file

@ -3,7 +3,6 @@ const api = require('../../../../api').endpoints;
const {http} = require('@tryghost/api-framework');
const apiMw = require('../../middleware');
const mw = require('./middleware');
const labs = require('../../../../../shared/labs');
const shared = require('../../../shared');
@ -310,7 +309,7 @@ module.exports = function apiRoutes() {
router.put('/newsletters/verifications/', mw.authAdminApi, http(api.newsletters.verifyPropertyUpdate));
router.put('/newsletters/:id', mw.authAdminApi, http(api.newsletters.edit));
router.get('/links', labs.enabledMiddleware('emailClicks'), mw.authAdminApi, http(api.links.browse));
router.get('/links', mw.authAdminApi, http(api.links.browse));
return router;
};

View file

@ -19,8 +19,7 @@ const GA_FEATURES = [
'freeTrial',
'compExpiring',
'searchHelper',
'emailAlerts',
'emailClicks'
'emailAlerts'
];
// NOTE: this allowlist is meant to be used to filter out any unexpected

View file

@ -627,7 +627,7 @@ exports[`Settings API Edit Can edit a setting 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "3471",
"content-length": "3450",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",

View file

@ -46,13 +46,10 @@ module.exports = class EventRepository {
{type: 'login_event', action: 'getLoginEvents'},
{type: 'payment_event', action: 'getPaymentEvents'},
{type: 'signup_event', action: 'getSignupEvents'},
{type: 'comment_event', action: 'getCommentEvents'}
{type: 'comment_event', action: 'getCommentEvents'},
{type: 'click_event', action: 'getClickEvents'}
];
if (this._labsService.isSet('emailClicks')) {
pageActions.push({type: 'click_event', action: 'getClickEvents'});
}
if (this._EmailRecipient) {
pageActions.push({type: 'email_delivered_event', action: 'getEmailDeliveredEvents'});
pageActions.push({type: 'email_opened_event', action: 'getEmailOpenedEvents'});