0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Added conversions count and separate analytics page (#15637)

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

- When audience feedback is enabled, we use a single 'conversions' count instead of having separate ones for signups and paid conversions.
- The analytics component is separated so we can change it without breaking the existing page.
This commit is contained in:
Simon Backx 2022-10-17 13:02:39 +02:00 committed by GitHub
parent b6d2d97af2
commit 22fe1c01de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 403 additions and 49 deletions

View file

@ -76,19 +76,10 @@
{{#if this.post.showAttributionAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "signup:[" this.post.id "]") }}>
<h3>{{format-number this.post.count.signups}}</h3>
<p>{{gh-pluralize this.post.count.signups "signup" without-count=true}}</p>
<h3>{{format-number this.post.count.conversions}}</h3>
<p>{{gh-pluralize this.post.count.conversions "conversions" without-count=true}}</p>
</LinkTo>
</div>
{{#if this.post.showPaidAttributionAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "conversion:[" this.post.id "]") }}>
<h3>{{format-number this.post.count.paid_conversions}}</h3>
<p><span class="hide-when-small">Paid </span>{{gh-pluralize this.post.count.paid_conversions "conversion" without-count=true}}</p>
</LinkTo>
</div>
{{/if}}
{{/if}}
{{#if this.post.showAudienceFeedback }}

View file

@ -0,0 +1,157 @@
<section class="gh-canvas" {{did-insert this.loadData}}>
<GhCanvasHeader class="gh-canvas-header gh-post-analytics-header">
<div class="flex flex-column flex-grow-1">
<div class="gh-canvas-breadcrumb">
<LinkTo @route="posts">
Posts
</LinkTo>
{{svg-jar "arrow-right-small"}}Analytics
</div>
<h2 class="gh-canvas-title gh-post-title">
{{this.post.title}}
</h2>
<div class="gh-post-analytics-meta">
<div class="gh-post-analytics-meta-text">
{{#if this.post.hasBeenEmailed }}
{{#if this.post.emailOnly}}
Sent
{{else}}
Published and sent
{{/if}}
{{else}}
Published
{{#if @post.didEmailFail}}
but failed to send
{{else}}
on your site
{{/if}}
{{/if}}
{{#let (moment-site-tz this.post.publishedAtUTC) as |publishedAt|}}
on
{{moment-format publishedAt "D MMM YYYY"}}
at
{{moment-format publishedAt "HH:mm"}}
{{/let}}
</div>
<LinkTo @route="editor.edit" @models={{array this.post.displayName this.post.id}} class="gh-post-list-cta edit" title="">
{{svg-jar "pen" title=""}}<span>Edit post</span>
</LinkTo>
</div>
</div>
</GhCanvasHeader>
<h4 class="gh-main-section-header small bn">
Engagement
</h4>
<div class="gh-post-analytics-box">
{{#if this.post.hasBeenEmailed}}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "emails.post_id:[" this.post.id "]") }}>
<h3>{{format-number this.post.email.emailCount}}</h3>
<p>Sent</p>
</LinkTo>
</div>
{{#if this.post.showEmailOpenAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "opened_emails.post_id:[" this.post.id "]") }}>
<h3>{{format-number this.post.email.openedCount}}</h3>
<p>Opened &mdash; <strong>{{this.post.email.openRate}}%</strong></p>
</LinkTo>
</div>
{{/if}}
{{#if this.post.showEmailClickAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "clicked_links.post_id:[" this.post.id "]") }}>
<h3>{{format-number this.post.count.clicks}}</h3>
<p>Clicked &mdash; <strong>{{this.post.clickRate}}%</strong></p>
</LinkTo>
</div>
{{/if}}
{{/if}}
{{#if this.post.showAttributionAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "signup:[" this.post.id "]") }}>
<h3>{{format-number this.post.count.signups}}</h3>
<p>{{gh-pluralize this.post.count.signups "signup" without-count=true}}</p>
</LinkTo>
</div>
{{#if this.post.showPaidAttributionAnalytics }}
<div class="gh-post-analytics-item">
<LinkTo @route="members" @query={{hash filterParam=(concat "conversion:[" this.post.id "]") }}>
<h3>{{format-number this.post.count.paid_conversions}}</h3>
<p><span class="hide-when-small">Paid </span>{{gh-pluralize this.post.count.paid_conversions "conversion" without-count=true}}</p>
</LinkTo>
</div>
{{/if}}
{{/if}}
</div>
{{#if this.isLoaded }}
{{#if this.showLinks }}
{{#if (is-empty this.links) }}
{{!-- Empty state --}}
{{else}}
<Posts::LinksTable @links={{this.links}} @updateLink={{this.updateLink}} />
{{/if}}
{{/if}}
{{#if this.showSources }}
{{#if (is-empty this.sources) }}
{{!-- Empty state --}}
{{else}}
<h4 class="gh-main-section-header small bn">
Growth from this post
</h4>
<div class="gh-post-analytics-box column">
<div class="gh-attribution-box">
<div class="gh-attribution-table-column">
<MemberAttribution::SourceAttributionTable
@sources={{this.sources}}
@sortColumn={{this.sortColumn}}
@setSortColumn={{this.setSortColumn}}
/>
</div>
</div>
</div>
{{/if}}
{{/if}}
<h4 class="gh-main-section-header small bn">
Get started with analytics
</h4>
<div class="gh-post-analytics-box resources">
<a href="https://ghost.org/help/post-analytics/" target="_blank" class="gh-post-analytics-resource" rel="noopener noreferrer">
<div class="thumbnail" style="background-image: url(assets/img/marketing/analytics-1.jpg);"></div>
<div class="flex flex-column justify-between">
<div>
<h3>Understanding analytics in Ghost</h3>
<p>Find out how to review the performance of your content and get the most out of post analytics in Ghost.</p>
</div>
<div class="gh-btn gh-btn-link">Read more &rarr;</div>
</div>
</a>
<a href="https://ghost.org/resources/content-distribution/" target="_blank" class="gh-post-analytics-resource" rel="noopener noreferrer">
<div class="thumbnail" style="background-image: url(assets/img/marketing/analytics-2.jpg);"></div>
<div class="flex flex-column justify-between">
<div>
<h3>How to get your content seen online</h3>
<p>Use these content distribution tactics to get more people to discover your work and increase engagement.</p>
</div>
<div class="gh-btn gh-btn-link">Read more &rarr;</div>
</div>
</a>
</div>
{{else}}
<div class="gh-post-analytics-loading">
<div class="gh-loading-spinner-outer">
<div class="gh-loading-spinner"></div>
</div>
</div>
{{/if}}
</section>

View file

@ -0,0 +1,196 @@
import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
/**
* @typedef {import('../../services/dashboard-stats').SourceAttributionCount} SourceAttributionCount
*/
const DISPLAY_OPTIONS = [{
name: 'Free signups',
value: 'signups'
}, {
name: 'Paid conversions',
value: 'paid'
}];
export default class Analytics extends Component {
@service ajax;
@service ghostPaths;
@service settings;
@service membersUtils;
@service utils;
@service feature;
@tracked sources = null;
@tracked links = null;
@tracked sortColumn = 'signups';
displayOptions = DISPLAY_OPTIONS;
get post() {
return this.args.post;
}
get allowedDisplayOptions() {
if (!this.hasPaidConversionData) {
return this.displayOptions.filter(d => d.value === 'signups');
}
if (!this.hasFreeSignups) {
return this.displayOptions.filter(d => d.value === 'paid');
}
return this.displayOptions;
}
get isDropdownDisabled() {
if (!this.hasPaidConversionData || !this.hasFreeSignups) {
return true;
}
return false;
}
get selectedDisplayOption() {
if (!this.hasPaidConversionData) {
return this.displayOptions.find(d => d.value === 'signups');
}
if (!this.hasFreeSignups) {
return this.displayOptions.find(d => d.value === 'paid');
}
return this.displayOptions.find(d => d.value === this.sortColumn) ?? this.displayOptions[0];
}
get selectedSortColumn() {
if (!this.hasPaidConversionData) {
return 'signups';
}
if (!this.hasFreeSignups) {
return 'paid';
}
return this.sortColumn;
}
get hasPaidConversionData() {
return this.sources.some(sourceData => sourceData.paidConversions > 0);
}
get hasFreeSignups() {
return this.sources.some(sourceData => sourceData.signups > 0);
}
@action
onDisplayChange(selected) {
this.sortColumn = selected.value;
}
@action
setSortColumn(column) {
this.sortColumn = column;
}
@action
updateLink(linkId, linkTo) {
this.links = this.links?.map((link) => {
if (link.link.link_id === linkId) {
return {
...link,
link: {
...link.link,
to: this.utils.cleanTrackedUrl(linkTo, false),
title: this.utils.cleanTrackedUrl(linkTo, true)
}
};
}
return link;
});
}
@action
loadData() {
if (this.showSources) {
this.fetchReferrersStats();
} else {
this.sources = [];
}
if (this.showLinks) {
this.fetchLinks();
} else {
this.links = [];
}
}
async fetchReferrersStats() {
if (this._fetchReferrersStats.isRunning) {
return this._fetchReferrersStats.last;
}
return this._fetchReferrersStats.perform();
}
async fetchLinks() {
if (this._fetchLinks.isRunning) {
return this._fetchLinks.last;
}
return this._fetchLinks.perform();
}
@task
*_fetchReferrersStats() {
let statsUrl = this.ghostPaths.url.api(`stats/referrers/posts/${this.post.id}`);
let result = yield this.ajax.request(statsUrl);
this.sources = result.stats.map((stat) => {
return {
source: stat.source ?? 'Direct',
signups: stat.signups,
paidConversions: stat.paid_conversions
};
});
}
@task
*_fetchLinks() {
const filter = `post_id:${this.post.id}`;
let statsUrl = this.ghostPaths.url.api(`links/`) + `?filter=${encodeURIComponent(filter)}`;
let result = yield this.ajax.request(statsUrl);
const links = result.links.map((link) => {
return {
...link,
link: {
...link.link,
to: this.utils.cleanTrackedUrl(link.link.to, false),
title: this.utils.cleanTrackedUrl(link.link.to, true)
}
};
});
// Remove duplicates by title ad merge
const linksByTitle = links.reduce((acc, link) => {
if (!acc[link.link.title]) {
acc[link.link.title] = link;
} else {
acc[link.link.title].clicks += link.clicks;
}
return acc;
}, {});
this.links = Object.values(linksByTitle);
}
get showLinks() {
return this.post.showEmailClickAnalytics;
}
get showSources() {
return this.feature.get('sourceAttribution') && this.post.showAttributionAnalytics;
}
get isLoaded() {
return this.links !== null && this.souces !== null;
}
}

View file

@ -1 +1,5 @@
<Posts::Analytics @post={{this.post}} />
{{#if (feature 'audienceFeedback') }}
<Posts::Analytics @post={{this.post}} />
{{else}}
<Posts::OldAnalytics @post={{this.post}} />
{{/if}}

View file

@ -26,7 +26,7 @@ function defaultRelations(frame) {
}
if (labs.isSet('audienceFeedback')) {
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback'];
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.conversions', 'count.clicks', 'count.sentiment', 'count.positive_feedback'];
} else {
frame.options.withRelated = ['tags', 'authors', 'authors.roles', 'email', 'tiers', 'newsletter', 'count.signups', 'count.paid_conversions', 'count.clicks'];
}

View file

@ -1346,6 +1346,26 @@ Post = ghostBookshelf.Model.extend({
.as('count__paid_conversions');
});
},
/**
* Combination of sigups and paid conversions, but unique per member
*/
conversions(modelOrCollection) {
modelOrCollection.query('columns', 'posts.*', (qb) => {
qb.count('*')
.from('k')
.with('k', (q) => {
q.select('member_id')
.from('members_subscription_created_events')
.whereRaw('posts.id = members_subscription_created_events.attribution_id')
.union(function () {
this.select('member_id')
.from('members_created_events')
.whereRaw('posts.id = members_created_events.attribution_id');
});
})
.as('count__conversions');
});
},
clicks(modelOrCollection) {
modelOrCollection.query('columns', 'posts.*', (qb) => {
qb.countDistinct('members_click_events.member_id')

View file

@ -21,10 +21,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -71,10 +70,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -123,7 +121,7 @@ exports[`Posts API Can browse 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": "10226",
"content-length": "10192",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@ -152,10 +150,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -206,10 +203,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -280,7 +276,7 @@ exports[`Posts API Can browse with formats 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": "13092",
"content-length": "13058",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@ -299,10 +295,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -352,7 +347,7 @@ exports[`Posts API Create Can create a post with lexical 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": "3909",
"content-length": "3892",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -372,10 +367,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -425,7 +419,7 @@ exports[`Posts API Create Can create a post with mobiledoc 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": "3725",
"content-length": "3708",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -546,10 +540,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -599,7 +592,7 @@ exports[`Posts API Update Can update a post with lexical 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": "3860",
"content-length": "3843",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -619,10 +612,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -672,7 +664,7 @@ exports[`Posts API Update Can update a post with lexical 4: [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": "3857",
"content-length": "3840",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
@ -692,10 +684,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -745,7 +736,7 @@ exports[`Posts API Update Can update a post with mobiledoc 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": "3670",
"content-length": "3653",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -765,10 +756,9 @@ Object {
"comment_id": Any<String>,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -818,7 +808,7 @@ exports[`Posts API Update Can update a post with mobiledoc 4: [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": "3667",
"content-length": "3650",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",

View file

@ -283,10 +283,9 @@ Object {
"comment_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -521,10 +520,9 @@ Object {
"comment_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -737,10 +735,9 @@ Object {
"comment_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,
@ -1019,10 +1016,9 @@ Object {
"comment_id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"count": Object {
"clicks": 0,
"paid_conversions": 0,
"conversions": 0,
"positive_feedback": 0,
"sentiment": 0,
"signups": 0,
},
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"custom_excerpt": null,