From 26cb011a3a5931d2361e55fabfe73e7442c537d9 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 16:01:23 -0500 Subject: [PATCH 01/56] Create report title component --- app/components/-report/title.js | 9 +++++++++ app/templates/components/-report/title.hbs | 2 ++ app/templates/portal/campaigns/manage/report/summary.hbs | 5 +---- 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 app/components/-report/title.js create mode 100644 app/templates/components/-report/title.hbs diff --git a/app/components/-report/title.js b/app/components/-report/title.js new file mode 100644 index 00000000..7c98ce60 --- /dev/null +++ b/app/components/-report/title.js @@ -0,0 +1,9 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: 'h3', + classNames: ['font-weight-bold', 'text-muted'], + + title: null, + subtitle: null, +}); diff --git a/app/templates/components/-report/title.hbs b/app/templates/components/-report/title.hbs new file mode 100644 index 00000000..748d8e90 --- /dev/null +++ b/app/templates/components/-report/title.hbs @@ -0,0 +1,2 @@ +{{title}} +{{#if title}}{{subtitle}}{{/if}} diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index aa9832ce..02f48423 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -1,10 +1,7 @@
-

- Campaign Summary Report - a real-time summary of your campaign's most important metrics -

+ {{-report/title title="Campaign Summary Report" subtitle="A real-time summary of your campaign's most important metrics"}}
From df5c968b1521cdc3fc0133ee861ef0c6e8db71cb Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 16:01:41 -0500 Subject: [PATCH 02/56] Add initial story report routing --- app/router.js | 1 + app/templates/manage/story/forms/edit.hbs | 6 ++++++ app/templates/portal/stories/manage/report.hbs | 13 +++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 app/templates/portal/stories/manage/report.hbs diff --git a/app/router.js b/app/router.js index 590aa817..29e69e11 100644 --- a/app/router.js +++ b/app/router.js @@ -113,6 +113,7 @@ Router.map(function() { this.route('materials', function() { }); + this.route('report'); }); }); }); diff --git a/app/templates/manage/story/forms/edit.hbs b/app/templates/manage/story/forms/edit.hbs index 8dde8176..924b78ff 100644 --- a/app/templates/manage/story/forms/edit.hbs +++ b/app/templates/manage/story/forms/edit.hbs @@ -74,6 +74,12 @@ {{#link-to "portal.stories.manage.materials" model.advertiser.hash model.hash target="_blank" rel="noopener noreferrer"}}Material Collection Link{{/link-to}}
+
+
+ {{entypo-icon "link"}} + {{#link-to "portal.stories.manage.report" model.advertiser.hash model.hash target="_blank" rel="noopener noreferrer"}}Report{{/link-to}} +
+
diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs new file mode 100644 index 00000000..103ce200 --- /dev/null +++ b/app/templates/portal/stories/manage/report.hbs @@ -0,0 +1,13 @@ +
+
+
+ +
+
+ {{-report/title title="Story Summary Report" subtitle="A real-time summary of your story's most important metrics"}} +
+
+ +
+
+
From 23b22c60de4f6098a9b9ef1337ae3a22c17e3aa0 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 16:10:27 -0500 Subject: [PATCH 03/56] Add story header to report --- app/components/-report/story/metrics.js | 5 +++ .../portal/stories/manage/report.hbs | 41 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 app/components/-report/story/metrics.js diff --git a/app/components/-report/story/metrics.js b/app/components/-report/story/metrics.js new file mode 100644 index 00000000..47986526 --- /dev/null +++ b/app/components/-report/story/metrics.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index 103ce200..ba667edd 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -2,12 +2,51 @@
-
+
{{-report/title title="Story Summary Report" subtitle="A real-time summary of your story's most important metrics"}}
+
+
+
+ +
+
+ {{#if model.primaryImage.src}} +
+ {{imgix-img + originalSrc=model.primaryImage.src + width=192 + height=108 + w="192" + h="108" + fit="crop" + crop="focalpoint" + fp-x=model.primaryImage.focalPoint.x + fp-y=model.primaryImage.focalPoint.y + }} +
+ {{/if}} +
+

{{model.title}}

+

{{model.teaser}}

+

{{story-status status=model.status}}

+
+
+
+ +
+
+
+ +
+
+ {{-report/story/metrics storyId=model.id}} +
+
+
From da432cb6c4539f49a4448c02251a452ae4d70d6c Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 16:33:28 -0500 Subject: [PATCH 04/56] Add loading support to data cards --- app/components/-report/data-card.js | 1 + app/templates/components/-report/data-card.hbs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/components/-report/data-card.js b/app/components/-report/data-card.js index e8d26931..e4ed580e 100644 --- a/app/components/-report/data-card.js +++ b/app/components/-report/data-card.js @@ -2,4 +2,5 @@ import Component from '@ember/component'; export default Component.extend({ classNames: ['card', 'border-0', 'z-depth-half'], + isLoading: false, }); diff --git a/app/templates/components/-report/data-card.hbs b/app/templates/components/-report/data-card.hbs index a0302197..a6724c4f 100644 --- a/app/templates/components/-report/data-card.hbs +++ b/app/templates/components/-report/data-card.hbs @@ -7,7 +7,13 @@
{{title}} - {{number-format value format}} + + {{#if isLoading}} + {{entypo-icon "hour-glass" class="d-inline-block spin"}} + {{else}} + {{number-format value format}} + {{/if}} + {{#if percentage}} ({{number-format percentage "0%"}}) {{/if}} From 868eac8ff943b60c0c6ea4d005e832905c849030 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 17:07:53 -0500 Subject: [PATCH 05/56] Add metric cards --- app/components/-report/story/metrics.js | 25 +++++++++- app/gql/queries/story/metrics.graphql | 12 +++++ .../components/-report/story/metrics.hbs | 46 +++++++++++++++++++ .../portal/stories/manage/report.hbs | 2 +- 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 app/gql/queries/story/metrics.graphql create mode 100644 app/templates/components/-report/story/metrics.hbs diff --git a/app/components/-report/story/metrics.js b/app/components/-report/story/metrics.js index 47986526..c5d3641c 100644 --- a/app/components/-report/story/metrics.js +++ b/app/components/-report/story/metrics.js @@ -1,5 +1,28 @@ import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; -export default Component.extend({ +import query from 'fortnight/gql/queries/story/metrics'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { tagName: '', + + init() { + this._super(...arguments); + this.query(); + }, + + async query() { + this.startAction(); + const variables = { input: { id: this.get('storyId') } }; + try { + const { metrics } = await this.get('apollo').query({ query, variables }, 'story'); + this.set('metrics', metrics); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + }); diff --git a/app/gql/queries/story/metrics.graphql b/app/gql/queries/story/metrics.graphql new file mode 100644 index 00000000..c39d0d25 --- /dev/null +++ b/app/gql/queries/story/metrics.graphql @@ -0,0 +1,12 @@ +query StoryMetrics($input: ModelIdInput!) { + story(input: $input) { + id + metrics { + users + pageviews + shares + avgTimeOnPage + timeOnPage + } + } +} diff --git a/app/templates/components/-report/story/metrics.hbs b/app/templates/components/-report/story/metrics.hbs new file mode 100644 index 00000000..a5963fc6 --- /dev/null +++ b/app/templates/components/-report/story/metrics.hbs @@ -0,0 +1,46 @@ +
+
+ {{-report/data-card + icon="users" + title="Unique Users" + format="0.[00]a" + value=metrics.users + color="text-primary" + subtitle="Total people who visited" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="eye" + title="Page Views" + format="0.[00]a" + value=metrics.pageviews + color="text-info" + subtitle="Total times viewed" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="share" + title="Shares" + format="0.[00]a" + value=metrics.shares + color="text-warning" + subtitle="Social share interactions" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="area-graph" + title="Time Spent" + format="0:00:00" + value=metrics.avgTimeOnPage + color="text-success" + subtitle="Average time per person" + isLoading=isActionRunning + }} +
+
diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index ba667edd..b93acc1a 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -8,7 +8,7 @@
-
+
From 831632fa90787134da4ae88ca21d417bfc9153cd Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 17:11:59 -0500 Subject: [PATCH 06/56] Reorg metric row/cols --- app/components/-report/story/metrics.js | 2 +- .../components/-report/story/metrics.hbs | 90 +++++++++---------- .../portal/stories/manage/report.hbs | 6 +- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/app/components/-report/story/metrics.js b/app/components/-report/story/metrics.js index c5d3641c..041d6eb5 100644 --- a/app/components/-report/story/metrics.js +++ b/app/components/-report/story/metrics.js @@ -5,7 +5,7 @@ import ActionMixin from 'fortnight/mixins/action-mixin'; import query from 'fortnight/gql/queries/story/metrics'; export default Component.extend(ActionMixin, ObjectQueryManager, { - tagName: '', + classNames: ['row'], init() { this._super(...arguments); diff --git a/app/templates/components/-report/story/metrics.hbs b/app/templates/components/-report/story/metrics.hbs index a5963fc6..9cf6999d 100644 --- a/app/templates/components/-report/story/metrics.hbs +++ b/app/templates/components/-report/story/metrics.hbs @@ -1,46 +1,46 @@ -
-
- {{-report/data-card - icon="users" - title="Unique Users" - format="0.[00]a" - value=metrics.users - color="text-primary" - subtitle="Total people who visited" - isLoading=isActionRunning - }} -
-
- {{-report/data-card - icon="eye" - title="Page Views" - format="0.[00]a" - value=metrics.pageviews - color="text-info" - subtitle="Total times viewed" - isLoading=isActionRunning - }} -
-
- {{-report/data-card - icon="share" - title="Shares" - format="0.[00]a" - value=metrics.shares - color="text-warning" - subtitle="Social share interactions" - isLoading=isActionRunning - }} -
-
- {{-report/data-card - icon="area-graph" - title="Time Spent" - format="0:00:00" - value=metrics.avgTimeOnPage - color="text-success" - subtitle="Average time per person" - isLoading=isActionRunning - }} -
+ +
+ {{-report/data-card + icon="users" + title="Unique Users" + format="0.[00]a" + value=metrics.users + color="text-primary" + subtitle="Total people who visited" + isLoading=isActionRunning + }}
+
+ {{-report/data-card + icon="eye" + title="Page Views" + format="0.[00]a" + value=metrics.pageviews + color="text-info" + subtitle="Total times viewed" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="share" + title="Shares" + format="0.[00]a" + value=metrics.shares + color="text-warning" + subtitle="Social share interactions" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="area-graph" + title="Time Spent" + format="0:00:00" + value=metrics.avgTimeOnPage + color="text-success" + subtitle="Average time per person" + isLoading=isActionRunning + }} +
+ diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index b93acc1a..adff2575 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -41,11 +41,7 @@
-
-
- {{-report/story/metrics storyId=model.id}} -
-
+ {{-report/story/metrics storyId=model.id}}
From f7d2b2066f356dd8e2f6c5c0bd26c720514f8a3b Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 17:51:08 -0500 Subject: [PATCH 07/56] Rework data chart to support loading --- app/components/-report/data-chart.js | 6 ++++++ app/templates/components/-report/data-chart.hbs | 15 +++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 app/components/-report/data-chart.js diff --git a/app/components/-report/data-chart.js b/app/components/-report/data-chart.js new file mode 100644 index 00000000..e4ed580e --- /dev/null +++ b/app/components/-report/data-chart.js @@ -0,0 +1,6 @@ +import Component from '@ember/component'; + +export default Component.extend({ + classNames: ['card', 'border-0', 'z-depth-half'], + isLoading: false, +}); diff --git a/app/templates/components/-report/data-chart.hbs b/app/templates/components/-report/data-chart.hbs index 7ea88bbf..c7336313 100644 --- a/app/templates/components/-report/data-chart.hbs +++ b/app/templates/components/-report/data-chart.hbs @@ -1,8 +1,11 @@ -
-
- {{ title }} -
-
+
+ {{ title }} +
+
+ {{#if isLoading}} + Loading data... + {{progress-bar show=true}} + {{else}} {{high-charts series=series options=options}} -
+ {{/if}}
From 9e3ed0717adde7f7b7d04324afef97dce041c908 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 17:51:17 -0500 Subject: [PATCH 08/56] Initial metrics by day report --- .../-report/story/metrics-by-day.js | 86 +++++++++++++++++++ app/gql/queries/story/reports/by-day.graphql | 16 ++++ .../-report/story/metrics-by-day.hbs | 6 ++ .../portal/stories/manage/report.hbs | 4 + 4 files changed, 112 insertions(+) create mode 100644 app/components/-report/story/metrics-by-day.js create mode 100644 app/gql/queries/story/reports/by-day.graphql create mode 100644 app/templates/components/-report/story/metrics-by-day.hbs diff --git a/app/components/-report/story/metrics-by-day.js b/app/components/-report/story/metrics-by-day.js new file mode 100644 index 00000000..7d06e682 --- /dev/null +++ b/app/components/-report/story/metrics-by-day.js @@ -0,0 +1,86 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; +import { computed } from '@ember/object'; +import moment from 'moment'; + +import query from 'fortnight/gql/queries/story/reports/by-day'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { + tagName: '', + + startDate: computed('endDate', function() { + return moment(this.get('endDate')).subtract(14, 'days'); + }), + + endDate: computed(function() { + return moment(); + }), + + series: computed('rows.[]', function() { + const rows = this.get('rows') || []; + return { + name: 'Pageviews', + data: rows.map(row => row.metrics.pageviews), + }; + }), + + options: computed('series', 'rows.[]', function() { + const rows = this.get('rows') || []; + return { + chart: { type: 'areaspline' }, + title: { text: false }, + xAxis: { + categories: rows.map(row => row.date), + type: 'datetime', + }, + yAxis: { + title: { text: 'Pageviews' }, + }, + tooltip: { valueSuffix: ' pageviews' }, + plotOptions: { + areaspline: { fillOpacity: 0.5 }, + }, + }; + + // const data = this.get('timeSeries'); + // console.info(data); + // const options = { + // title: { + // text: false, + // }, + // yAxis: { + // title: { + // text: false, + // } + // }, + // xAxis: { + // type: 'datetime', + // } + // } + // return { data, options }; + }), + + init() { + this._super(...arguments); + this.query(); + }, + + async query() { + this.startAction(); + const variables = { + input: { id: this.get('storyId') }, + startDate: this.get('startDate').valueOf(), + endDate: this.get('endDate').valueOf(), + }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'story'); + this.set('rows', reports.byDay); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + +}); diff --git a/app/gql/queries/story/reports/by-day.graphql b/app/gql/queries/story/reports/by-day.graphql new file mode 100644 index 00000000..9f5c33bf --- /dev/null +++ b/app/gql/queries/story/reports/by-day.graphql @@ -0,0 +1,16 @@ +query StoryReportByDay($input: ModelIdInput!, $startDate: Date!, $endDate: Date!) { + story(input: $input) { + id + reports { + byDay(startDate: $startDate, endDate: $endDate) { + date + metrics { + users + pageviews + shares + } + } + } + + } +} diff --git a/app/templates/components/-report/story/metrics-by-day.hbs b/app/templates/components/-report/story/metrics-by-day.hbs new file mode 100644 index 00000000..05edc677 --- /dev/null +++ b/app/templates/components/-report/story/metrics-by-day.hbs @@ -0,0 +1,6 @@ +{{-report/data-chart + title="Views for the last 14 days" + isLoading=isActionRunning + series=series + options=options +}} diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index adff2575..087daad2 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -41,8 +41,12 @@
+

Total Metrics

{{-report/story/metrics storyId=model.id}} +

Metrics Over Time

+ {{-report/story/metrics-by-day storyId=model.id}} + From 948b48fa17ccc173e44a96ddfae7b813f28bc72c Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 19:50:16 -0500 Subject: [PATCH 09/56] Get metrics by day chart working --- app/components/-report/story/metrics-by-day.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/components/-report/story/metrics-by-day.js b/app/components/-report/story/metrics-by-day.js index 7d06e682..b85cabd9 100644 --- a/app/components/-report/story/metrics-by-day.js +++ b/app/components/-report/story/metrics-by-day.js @@ -19,10 +19,10 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { series: computed('rows.[]', function() { const rows = this.get('rows') || []; - return { - name: 'Pageviews', + return [{ + name: null, data: rows.map(row => row.metrics.pageviews), - }; + }]; }), options: computed('series', 'rows.[]', function() { @@ -32,7 +32,6 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { title: { text: false }, xAxis: { categories: rows.map(row => row.date), - type: 'datetime', }, yAxis: { title: { text: 'Pageviews' }, From 3e8bcde8a3cae36ccf6f3f7b75f04d9b0d3cd2a2 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 20:54:41 -0500 Subject: [PATCH 10/56] Rework by-day chart --- .../-report/story/metrics-by-day.js | 37 +++++++------------ app/gql/queries/story/reports/by-day.graphql | 3 +- .../components/-report/data-chart.hbs | 6 +-- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/app/components/-report/story/metrics-by-day.js b/app/components/-report/story/metrics-by-day.js index b85cabd9..d97d9dbc 100644 --- a/app/components/-report/story/metrics-by-day.js +++ b/app/components/-report/story/metrics-by-day.js @@ -17,47 +17,38 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { return moment(); }), - series: computed('rows.[]', function() { + data: computed('rows.[]', function() { const rows = this.get('rows') || []; + return rows.map(row => row.metrics.pageviews); + }), + + series: computed('data.length', function() { + const data = this.get('data'); return [{ - name: null, - data: rows.map(row => row.metrics.pageviews), + name: 'Pageviews', + data, }]; }), - options: computed('series', 'rows.[]', function() { + options: computed('series', 'data.length', function() { const rows = this.get('rows') || []; + const { length } = this.get('data'); return { chart: { type: 'areaspline' }, + legend: { enabled: false }, title: { text: false }, xAxis: { - categories: rows.map(row => row.date), + categories: rows.map(row => row.shortDate), + min: 0.5, + max: length - 1.5, }, yAxis: { title: { text: 'Pageviews' }, }, - tooltip: { valueSuffix: ' pageviews' }, plotOptions: { areaspline: { fillOpacity: 0.5 }, }, }; - - // const data = this.get('timeSeries'); - // console.info(data); - // const options = { - // title: { - // text: false, - // }, - // yAxis: { - // title: { - // text: false, - // } - // }, - // xAxis: { - // type: 'datetime', - // } - // } - // return { data, options }; }), init() { diff --git a/app/gql/queries/story/reports/by-day.graphql b/app/gql/queries/story/reports/by-day.graphql index 9f5c33bf..cacbafae 100644 --- a/app/gql/queries/story/reports/by-day.graphql +++ b/app/gql/queries/story/reports/by-day.graphql @@ -3,7 +3,8 @@ query StoryReportByDay($input: ModelIdInput!, $startDate: Date!, $endDate: Date! id reports { byDay(startDate: $startDate, endDate: $endDate) { - date + shortDate: date(format: "MMM D") + longDate: date(format: "dddd, MMMM Do, YYYY") metrics { users pageviews diff --git a/app/templates/components/-report/data-chart.hbs b/app/templates/components/-report/data-chart.hbs index c7336313..3ae06c22 100644 --- a/app/templates/components/-report/data-chart.hbs +++ b/app/templates/components/-report/data-chart.hbs @@ -1,7 +1,7 @@ -
- {{ title }} -
+ {{#if title}} +
{{title}}
+ {{/if}} {{#if isLoading}} Loading data... {{progress-bar show=true}} From ef86d80a21fed40b6b4645d303fd27528e905165 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 21:09:53 -0500 Subject: [PATCH 11/56] Format tooltip to use long date format --- app/components/-report/story/metrics-by-day.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/components/-report/story/metrics-by-day.js b/app/components/-report/story/metrics-by-day.js index d97d9dbc..ac6d1105 100644 --- a/app/components/-report/story/metrics-by-day.js +++ b/app/components/-report/story/metrics-by-day.js @@ -42,6 +42,15 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { min: 0.5, max: length - 1.5, }, + tooltip: { + formatter: function() { + const { index, color } = this.point; + const { longDate } = rows[index]; + return `${longDate}
+ \u25CF ${this.series.name}: ${this.y} + `; + }, + }, yAxis: { title: { text: 'Pageviews' }, }, From db5a3162a1d9517bf9b2b2c1cce125761f4f3e89 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 15 Aug 2018 21:11:46 -0500 Subject: [PATCH 12/56] Update timespent icon to use clock --- app/templates/components/-report/story/metrics.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/components/-report/story/metrics.hbs b/app/templates/components/-report/story/metrics.hbs index 9cf6999d..2c402281 100644 --- a/app/templates/components/-report/story/metrics.hbs +++ b/app/templates/components/-report/story/metrics.hbs @@ -34,7 +34,7 @@
{{-report/data-card - icon="area-graph" + icon="clock" title="Time Spent" format="0:00:00" value=metrics.avgTimeOnPage From f9224b7066de87ec5b92c0553f0d8c59e4de51c5 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Thu, 16 Aug 2018 08:29:01 -0500 Subject: [PATCH 13/56] Add story acquisition report --- app/components/-report/story/acquisition.js | 64 +++++++++++++++++++ .../queries/story/reports/acquisition.graphql | 15 +++++ .../components/-report/story/acquisition.hbs | 6 ++ .../portal/stories/manage/report.hbs | 10 +++ 4 files changed, 95 insertions(+) create mode 100644 app/components/-report/story/acquisition.js create mode 100644 app/gql/queries/story/reports/acquisition.graphql create mode 100644 app/templates/components/-report/story/acquisition.hbs diff --git a/app/components/-report/story/acquisition.js b/app/components/-report/story/acquisition.js new file mode 100644 index 00000000..050d450d --- /dev/null +++ b/app/components/-report/story/acquisition.js @@ -0,0 +1,64 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; +import { computed } from '@ember/object'; +import numeral from 'numeral'; + +import query from 'fortnight/gql/queries/story/reports/acquisition'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { + + init() { + this._super(...arguments); + this.query(); + }, + + series: computed('rows.[]', function() { + const rows = this.get('rows') || []; + const data = rows.map((row) => { + const { channelGrouping, metrics } = row; + return { name: channelGrouping, y: metrics.users }; + }); + return [{ + name: 'Channels', + colorByPoint: true, + data, + }]; + }), + + options: computed('series', 'data.length', function() { + return { + chart: { type: 'pie' }, + title: { text: false }, + tooltip: { + formatter: function() { + return `${this.point.name}
+ ${this.y} Users (${numeral(this.percentage).format('0.0')}%) + `; + }, + }, + plotOptions: { + pie: { + allowPointSelect: true, + cursor: 'pointer', + dataLabels: { enabled: false }, + showInLegend: true, + }, + }, + }; + }), + + async query() { + this.startAction(); + const variables = { input: { id: this.get('storyId') } }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'story'); + this.set('rows', reports.acquisition); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + +}); diff --git a/app/gql/queries/story/reports/acquisition.graphql b/app/gql/queries/story/reports/acquisition.graphql new file mode 100644 index 00000000..8f33fbab --- /dev/null +++ b/app/gql/queries/story/reports/acquisition.graphql @@ -0,0 +1,15 @@ +query StoryAcquisitionReport($input: ModelIdInput!) { + story(input: $input) { + id + reports { + acquisition { + channelGrouping + metrics { + users + sessions + pageviews + } + } + } + } +} diff --git a/app/templates/components/-report/story/acquisition.hbs b/app/templates/components/-report/story/acquisition.hbs new file mode 100644 index 00000000..4147f66b --- /dev/null +++ b/app/templates/components/-report/story/acquisition.hbs @@ -0,0 +1,6 @@ +{{-report/data-chart + title="Acquisition by Channel" + isLoading=isActionRunning + series=series + options=options +}} diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index 087daad2..061bda65 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -47,6 +47,16 @@

Metrics Over Time

{{-report/story/metrics-by-day storyId=model.id}} +

Details

+
+
+ {{-report/story/acquisition storyId=model.id}} +
+
+ +
+
+
From 8547882545e9c3dfad3bdf10e6f6f0ca0615951d Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Thu, 16 Aug 2018 08:34:46 -0500 Subject: [PATCH 14/56] Create device report --- app/components/-report/story/devices.js | 64 +++++++++++++++++++ app/gql/queries/story/reports/devices.graphql | 15 +++++ .../components/-report/story/devices.hbs | 6 ++ .../portal/stories/manage/report.hbs | 2 +- 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 app/components/-report/story/devices.js create mode 100644 app/gql/queries/story/reports/devices.graphql create mode 100644 app/templates/components/-report/story/devices.hbs diff --git a/app/components/-report/story/devices.js b/app/components/-report/story/devices.js new file mode 100644 index 00000000..30e4fae9 --- /dev/null +++ b/app/components/-report/story/devices.js @@ -0,0 +1,64 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; +import { computed } from '@ember/object'; +import numeral from 'numeral'; + +import query from 'fortnight/gql/queries/story/reports/devices'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { + + init() { + this._super(...arguments); + this.query(); + }, + + series: computed('rows.[]', function() { + const rows = this.get('rows') || []; + const data = rows.map((row) => { + const { deviceCategory, metrics } = row; + return { name: deviceCategory, y: metrics.users }; + }); + return [{ + name: 'Device Type', + colorByPoint: true, + data, + }]; + }), + + options: computed('series', 'data.length', function() { + return { + chart: { type: 'pie' }, + title: { text: false }, + tooltip: { + formatter: function() { + return `${this.point.name}
+ ${this.y} Users (${numeral(this.percentage).format('0.0')}%) + `; + }, + }, + plotOptions: { + pie: { + allowPointSelect: true, + cursor: 'pointer', + dataLabels: { enabled: false }, + showInLegend: true, + }, + }, + }; + }), + + async query() { + this.startAction(); + const variables = { input: { id: this.get('storyId') } }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'story'); + this.set('rows', reports.devices); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + +}); diff --git a/app/gql/queries/story/reports/devices.graphql b/app/gql/queries/story/reports/devices.graphql new file mode 100644 index 00000000..f05032a9 --- /dev/null +++ b/app/gql/queries/story/reports/devices.graphql @@ -0,0 +1,15 @@ +query StoryDeviceReport($input: ModelIdInput!) { + story(input: $input) { + id + reports { + devices { + deviceCategory + metrics { + users + sessions + pageviews + } + } + } + } +} diff --git a/app/templates/components/-report/story/devices.hbs b/app/templates/components/-report/story/devices.hbs new file mode 100644 index 00000000..30a3b0f7 --- /dev/null +++ b/app/templates/components/-report/story/devices.hbs @@ -0,0 +1,6 @@ +{{-report/data-chart + title="Device Types" + isLoading=isActionRunning + series=series + options=options +}} diff --git a/app/templates/portal/stories/manage/report.hbs b/app/templates/portal/stories/manage/report.hbs index 061bda65..b78d09ac 100644 --- a/app/templates/portal/stories/manage/report.hbs +++ b/app/templates/portal/stories/manage/report.hbs @@ -53,7 +53,7 @@ {{-report/story/acquisition storyId=model.id}}
- + {{-report/story/devices storyId=model.id}}
From f9cb7554f4c687cf278433d9ba259a30db54fd93 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 11:06:13 -0500 Subject: [PATCH 15/56] Update daily dashboard metrics --- app/gql/queries/dashboard/daily-metrics.graphql | 2 +- app/templates/manage/index.hbs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/gql/queries/dashboard/daily-metrics.graphql b/app/gql/queries/dashboard/daily-metrics.graphql index f89f1612..8f3900e2 100644 --- a/app/gql/queries/dashboard/daily-metrics.graphql +++ b/app/gql/queries/dashboard/daily-metrics.graphql @@ -5,7 +5,7 @@ query Dashboard($day: Date!) { clicks ctr } - dailyFallbackMetrics(day: $day) { + dailyTotalMetrics(day: $day) { placements views clicks diff --git a/app/templates/manage/index.hbs b/app/templates/manage/index.hbs index 5179e41e..aab9446c 100644 --- a/app/templates/manage/index.hbs +++ b/app/templates/manage/index.hbs @@ -24,7 +24,7 @@ title="Views" format="0.[00]a" value=model.dailyCampaignMetrics.views - secondaryValue=model.dailyFallbackMetrics.views + secondaryValue=model.dailyTotalMetrics.views color="text-info" }} @@ -34,7 +34,7 @@ title="Clicks" format="0.[0]a" value=model.dailyCampaignMetrics.clicks - secondaryValue=model.dailyFallbackMetrics.clicks + secondaryValue=model.dailyTotalMetrics.clicks color="text-warning" }} @@ -44,7 +44,7 @@ title="CTR" format="0.[000]%" value=model.dailyCampaignMetrics.ctr - secondaryValue=model.dailyFallbackMetrics.ctr + secondaryValue=model.dailyTotalMetrics.ctr color="text-success" }} From bf0aad43f513f076765e641cfc3065be95e18a73 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 11:44:46 -0500 Subject: [PATCH 16/56] Rework campaign summary tilte --- app/gql/fragments/campaign/portal.graphql | 5 ++ .../portal/campaigns/manage/report/summary.js | 17 ----- .../campaigns/manage/report/summary.hbs | 63 ++++++++++++++++++- 3 files changed, 65 insertions(+), 20 deletions(-) delete mode 100644 app/routes/portal/campaigns/manage/report/summary.js diff --git a/app/gql/fragments/campaign/portal.graphql b/app/gql/fragments/campaign/portal.graphql index ef4e36a8..2fa78f57 100644 --- a/app/gql/fragments/campaign/portal.graphql +++ b/app/gql/fragments/campaign/portal.graphql @@ -1,4 +1,5 @@ #import 'fortnight/gql/fragments/campaign-creative' +#import 'fortnight/gql/fragments/image/src' fragment CampaignPortalFragment on Campaign { id @@ -9,6 +10,10 @@ fragment CampaignPortalFragment on Campaign { url criteria { start + end + } + primaryImage { + ...ImageSrcFragment } story { id diff --git a/app/routes/portal/campaigns/manage/report/summary.js b/app/routes/portal/campaigns/manage/report/summary.js deleted file mode 100644 index 0f21a445..00000000 --- a/app/routes/portal/campaigns/manage/report/summary.js +++ /dev/null @@ -1,17 +0,0 @@ -import Route from '@ember/routing/route'; -import RouteQueryManager from 'ember-apollo-client/mixins/route-query-manager'; - -import query from 'fortnight/gql/queries/reports/campaign/summary'; - -export default Route.extend(RouteQueryManager, { - - model() { - const { advertiser, campaign } = this.modelFor('portal.campaigns.manage'); - const hash = campaign.hash; - const advertiserId = advertiser.id; - const variables = { input: { hash, advertiserId } }; - this.controllerFor(this.get('routeName')).set('campaign', campaign); - return this.get('apollo').watchQuery({ query, variables, fetchPolicy: 'network-only' }, 'reportCampaignSummary'); - } -}) - diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 02f48423..1f96b531 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -1,7 +1,64 @@ -
+
+
+
+ +
+
+ {{-report/title title="Campaign Summary Report" subtitle="A real-time summary of your campaign's most important metrics"}} +
+
+ +
+
+
+ +
+
+ {{#if model.campaign.primaryImage.src}} +
+ {{imgix-img + originalSrc=model.campaign.primaryImage.src + width=192 + height=108 + w="192" + h="108" + fit="crop" + crop="focalpoint" + fp-x=model.campaign.primaryImage.focalPoint.x + fp-y=model.campaign.primaryImage.focalPoint.y + }} +
+ {{/if}} +
+

{{model.campaign.name}}

+ {{#if model.campaign.description}} +
{{model.campaign.description}}
+ {{/if}} + {{#if model.campaign.story.id}} +

Story: {{model.campaign.story.title}}

+ {{/if}} +
+ {{campaign-date futureLabel="Starts" pastLabel="Started" date=model.campaign.criteria.start}} + {{campaign-date futureLabel="Ends" pastLabel="Ended" date=model.campaign.criteria.end}} +
+
+
+
+ +
+
+
+ +
+
+
+ + + +{{!--
- {{-report/title title="Campaign Summary Report" subtitle="A real-time summary of your campaign's most important metrics"}} +
@@ -67,4 +124,4 @@
- + --}} From 45f6ad30e6e3f059e4d166b1812e49bb9fe45d01 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 11:51:42 -0500 Subject: [PATCH 17/56] Add overall metrics to campaign report --- app/components/-report/campaign/metrics.js | 28 +++++++++++++++ app/gql/queries/campaign/metrics.graphql | 10 ++++++ .../components/-report/campaign/metrics.hbs | 34 +++++++++++++++++++ .../campaigns/manage/report/summary.hbs | 3 ++ 4 files changed, 75 insertions(+) create mode 100644 app/components/-report/campaign/metrics.js create mode 100644 app/gql/queries/campaign/metrics.graphql create mode 100644 app/templates/components/-report/campaign/metrics.hbs diff --git a/app/components/-report/campaign/metrics.js b/app/components/-report/campaign/metrics.js new file mode 100644 index 00000000..53d03b2d --- /dev/null +++ b/app/components/-report/campaign/metrics.js @@ -0,0 +1,28 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; + +import query from 'fortnight/gql/queries/campaign/metrics'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { + classNames: ['row'], + + init() { + this._super(...arguments); + this.query(); + }, + + async query() { + this.startAction(); + const variables = { input: { id: this.get('campaignId') } }; + try { + const { metrics } = await this.get('apollo').query({ query, variables }, 'campaign'); + this.set('metrics', metrics); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + +}); diff --git a/app/gql/queries/campaign/metrics.graphql b/app/gql/queries/campaign/metrics.graphql new file mode 100644 index 00000000..efb984b8 --- /dev/null +++ b/app/gql/queries/campaign/metrics.graphql @@ -0,0 +1,10 @@ +query CampaignMetrics($input: ModelIdInput!) { + campaign(input: $input) { + id + metrics { + views + clicks + ctr + } + } +} diff --git a/app/templates/components/-report/campaign/metrics.hbs b/app/templates/components/-report/campaign/metrics.hbs new file mode 100644 index 00000000..6d171a1c --- /dev/null +++ b/app/templates/components/-report/campaign/metrics.hbs @@ -0,0 +1,34 @@ +
+ {{-report/data-card + icon="eye" + title="Impressions" + format="0.[00]a" + value=metrics.views + color="text-info" + subtitle="Displayed viewable impressions" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="direction" + title="Clicks" + format="0.[0]a" + value=metrics.clicks + color="text-warning" + subtitle="Success of online ads" + isLoading=isActionRunning + }} +
+
+ {{-report/data-card + icon="area-graph" + title="CTR" + format="0.[000]%" + value=metrics.ctr + color="text-success" + subtitle="Click-through rate" + isLoading=isActionRunning + }} +
+ diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 1f96b531..8c06fc34 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -49,6 +49,9 @@ +

Total Metrics

+ {{-report/campaign/metrics campaignId=model.campaign.id}} + From 16f2c2fc1ffda1f7c444d21f8873542efe3c9a85 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 12:44:17 -0500 Subject: [PATCH 18/56] Create campaign metrics by day component --- .../-report/campaign/metrics-by-day.js | 85 +++++++++++++++++++ .../queries/campaign/reports/by-day.graphql | 16 ++++ .../-report/campaign/metrics-by-day.hbs | 6 ++ .../campaigns/manage/report/summary.hbs | 3 + 4 files changed, 110 insertions(+) create mode 100644 app/components/-report/campaign/metrics-by-day.js create mode 100644 app/gql/queries/campaign/reports/by-day.graphql create mode 100644 app/templates/components/-report/campaign/metrics-by-day.hbs diff --git a/app/components/-report/campaign/metrics-by-day.js b/app/components/-report/campaign/metrics-by-day.js new file mode 100644 index 00000000..81b421e4 --- /dev/null +++ b/app/components/-report/campaign/metrics-by-day.js @@ -0,0 +1,85 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; +import ActionMixin from 'fortnight/mixins/action-mixin'; +import { computed } from '@ember/object'; +import moment from 'moment'; + +import query from 'fortnight/gql/queries/campaign/reports/by-day'; + +export default Component.extend(ActionMixin, ObjectQueryManager, { + tagName: '', + + startDate: computed('endDate', function() { + return moment(this.get('endDate')).subtract(14, 'days'); + }), + + endDate: computed(function() { + return moment().startOf('day'); + }), + + data: computed('rows.[]', function() { + const rows = this.get('rows') || []; + return rows.map(row => row.metrics.views); + }), + + series: computed('data.length', function() { + const data = this.get('data'); + return [{ + name: 'Impressions', + data, + }]; + }), + + options: computed('series', 'data.length', function() { + const rows = this.get('rows') || []; + const { length } = this.get('data'); + return { + chart: { type: 'areaspline' }, + legend: { enabled: false }, + title: { text: false }, + xAxis: { + categories: rows.map(row => row.shortDate), + min: 0.5, + max: length - 1.5, + }, + tooltip: { + formatter: function() { + const { index, color } = this.point; + const { longDate } = rows[index]; + return `${longDate}
+ \u25CF ${this.series.name}: ${this.y} + `; + }, + }, + yAxis: { + title: { text: 'Impressions' }, + }, + plotOptions: { + areaspline: { fillOpacity: 0.5 }, + }, + }; + }), + + init() { + this._super(...arguments); + this.query(); + }, + + async query() { + this.startAction(); + const variables = { + input: { id: this.get('campaignId') }, + startDate: this.get('startDate').valueOf(), + endDate: this.get('endDate').valueOf(), + }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'campaign'); + this.set('rows', reports.byDay); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.endAction(); + } + }, + +}); diff --git a/app/gql/queries/campaign/reports/by-day.graphql b/app/gql/queries/campaign/reports/by-day.graphql new file mode 100644 index 00000000..1b21dee0 --- /dev/null +++ b/app/gql/queries/campaign/reports/by-day.graphql @@ -0,0 +1,16 @@ +query CampaignReportByDay($input: ModelIdInput!, $startDate: Date!, $endDate: Date!) { + campaign(input: $input) { + id + reports { + byDay(startDate: $startDate, endDate: $endDate) { + shortDate: day(format: "MMM D") + longDate: day(format: "dddd, MMMM Do, YYYY") + metrics { + views + clicks + ctr + } + } + } + } +} diff --git a/app/templates/components/-report/campaign/metrics-by-day.hbs b/app/templates/components/-report/campaign/metrics-by-day.hbs new file mode 100644 index 00000000..a21d1748 --- /dev/null +++ b/app/templates/components/-report/campaign/metrics-by-day.hbs @@ -0,0 +1,6 @@ +{{-report/data-chart + title="Impressions for the last 14 days" + isLoading=isActionRunning + series=series + options=options +}} diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 8c06fc34..a139cfa5 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -52,6 +52,9 @@

Total Metrics

{{-report/campaign/metrics campaignId=model.campaign.id}} +

Metrics Over Time

+ {{-report/campaign/metrics-by-day campaignId=model.campaign.id}} + From ec0a394cac1e8e9abffc17f4dc10d11a8d93a8f3 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 13:06:33 -0500 Subject: [PATCH 19/56] Add CTR to summary and add formatting --- .../-report/campaign/metrics-by-day.js | 25 +++++++++++++++---- .../-report/campaign/metrics-by-day.hbs | 2 +- .../campaigns/manage/report/summary.hbs | 3 ++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/components/-report/campaign/metrics-by-day.js b/app/components/-report/campaign/metrics-by-day.js index 81b421e4..bda21c65 100644 --- a/app/components/-report/campaign/metrics-by-day.js +++ b/app/components/-report/campaign/metrics-by-day.js @@ -3,11 +3,15 @@ import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager' import ActionMixin from 'fortnight/mixins/action-mixin'; import { computed } from '@ember/object'; import moment from 'moment'; +import numeral from 'numeral'; import query from 'fortnight/gql/queries/campaign/reports/by-day'; export default Component.extend(ActionMixin, ObjectQueryManager, { - tagName: '', + metric: 'views', + label: 'Impressions', + format: null, + labelFormat: null, startDate: computed('endDate', function() { return moment(this.get('endDate')).subtract(14, 'days'); @@ -19,13 +23,15 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { data: computed('rows.[]', function() { const rows = this.get('rows') || []; - return rows.map(row => row.metrics.views); + const key = this.get('metric'); + return rows.map(row => row.metrics[key]); }), series: computed('data.length', function() { const data = this.get('data'); + const name = this.get('label'); return [{ - name: 'Impressions', + name, data, }]; }), @@ -33,6 +39,8 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { options: computed('series', 'data.length', function() { const rows = this.get('rows') || []; const { length } = this.get('data'); + const format = this.get('format'); + const labelFormat = this.get('labelFormat'); return { chart: { type: 'areaspline' }, legend: { enabled: false }, @@ -44,15 +52,22 @@ export default Component.extend(ActionMixin, ObjectQueryManager, { }, tooltip: { formatter: function() { + + const value = format ? numeral(this.y).format(format) : this.y; const { index, color } = this.point; const { longDate } = rows[index]; return `${longDate}
- \u25CF ${this.series.name}: ${this.y} + \u25CF ${this.series.name}: ${value} `; }, }, yAxis: { - title: { text: 'Impressions' }, + title: { text: this.get('label') }, + labels: { + formatter: function() { + return labelFormat ? numeral(this.value).format(labelFormat) : this.value; + }, + }, }, plotOptions: { areaspline: { fillOpacity: 0.5 }, diff --git a/app/templates/components/-report/campaign/metrics-by-day.hbs b/app/templates/components/-report/campaign/metrics-by-day.hbs index a21d1748..8373f215 100644 --- a/app/templates/components/-report/campaign/metrics-by-day.hbs +++ b/app/templates/components/-report/campaign/metrics-by-day.hbs @@ -1,5 +1,5 @@ {{-report/data-chart - title="Impressions for the last 14 days" + title=(concat label " for the last 14 days") isLoading=isActionRunning series=series options=options diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index a139cfa5..a5834341 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -53,7 +53,8 @@ {{-report/campaign/metrics campaignId=model.campaign.id}}

Metrics Over Time

- {{-report/campaign/metrics-by-day campaignId=model.campaign.id}} + {{-report/campaign/metrics-by-day campaignId=model.campaign.id metric="views" label="Impressions" class="mb-4" labelFormat="0.[0]a" format="0,0"}} + {{-report/campaign/metrics-by-day campaignId=model.campaign.id metric="ctr" label="CTR" labelFormat="0.[000]%" format="0.[000]%"}} From 9d05a107d4e4e8f1e0c494199ad9fae08ce436e0 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 13:30:17 -0500 Subject: [PATCH 20/56] Remove old report summary code --- .../campaigns/manage/report/summary.hbs | 72 ------------------- 1 file changed, 72 deletions(-) diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index a5834341..902db592 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -60,75 +60,3 @@ - - -{{!--
-
-
- -
-
- -
-
-
-
- {{-report/campaign-title campaign=campaign}} -
-
-
-
- -
-
- {{-report/data-card - icon="eye" - title="Impressions" - value=impressions - color="text-info" - subtitle="Displayed viewable impressions" - }} -
-
- {{-report/data-card - icon="direction" - title="Clicks" - value=clicks - color="text-warning" - subtitle="Success of online ads" - }} -
-
- {{-report/data-card - icon="area-graph" - title="CTR" - value=(div ctr 100) - format="0.00%" - color="text-success" - subtitle="Click-through rate" - }} -
- -
- -
-
- {{-report/data-chart - title="Daily impressions" - series=impressionSummary.data - options=impressionSummary.options - }} -
-
- -
-
- {{-report/data-chart - title="Daily click-through rate" - series=ctrSummary.data - options=ctrSummary.options - }} -
-
- -
--}} From 4304a53c1160570d4d6c0b04b49d7aa791de54ca Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 14:17:54 -0500 Subject: [PATCH 21/56] Move metric cards to own component --- .../-report/campaign/metric-cards.js | 10 +++++ app/components/-report/campaign/metrics.js | 2 - .../-report/campaign/metric-cards.hbs | 34 ++++++++++++++++ .../components/-report/campaign/metrics.hbs | 40 +++---------------- 4 files changed, 50 insertions(+), 36 deletions(-) create mode 100644 app/components/-report/campaign/metric-cards.js create mode 100644 app/templates/components/-report/campaign/metric-cards.hbs diff --git a/app/components/-report/campaign/metric-cards.js b/app/components/-report/campaign/metric-cards.js new file mode 100644 index 00000000..2d0ed08f --- /dev/null +++ b/app/components/-report/campaign/metric-cards.js @@ -0,0 +1,10 @@ +import Component from '@ember/component'; + +export default Component.extend({ + classNames: ['row'], + views: 0, + clicks: 0, + ctr: 0, + + isLoading: false, +}); diff --git a/app/components/-report/campaign/metrics.js b/app/components/-report/campaign/metrics.js index 53d03b2d..61a60eea 100644 --- a/app/components/-report/campaign/metrics.js +++ b/app/components/-report/campaign/metrics.js @@ -5,8 +5,6 @@ import ActionMixin from 'fortnight/mixins/action-mixin'; import query from 'fortnight/gql/queries/campaign/metrics'; export default Component.extend(ActionMixin, ObjectQueryManager, { - classNames: ['row'], - init() { this._super(...arguments); this.query(); diff --git a/app/templates/components/-report/campaign/metric-cards.hbs b/app/templates/components/-report/campaign/metric-cards.hbs new file mode 100644 index 00000000..83051165 --- /dev/null +++ b/app/templates/components/-report/campaign/metric-cards.hbs @@ -0,0 +1,34 @@ +
+ {{-report/data-card + icon="eye" + title="Impressions" + format="0.[00]a" + value=views + color="text-info" + subtitle="Displayed viewable impressions" + isLoading=isLoading + }} +
+
+ {{-report/data-card + icon="direction" + title="Clicks" + format="0.[0]a" + value=clicks + color="text-warning" + subtitle="Success of online ads" + isLoading=isLoading + }} +
+
+ {{-report/data-card + icon="area-graph" + title="CTR" + format="0.[000]%" + value=ctr + color="text-success" + subtitle="Click-through rate" + isLoading=isLoading + }} +
+ diff --git a/app/templates/components/-report/campaign/metrics.hbs b/app/templates/components/-report/campaign/metrics.hbs index 6d171a1c..0f93257c 100644 --- a/app/templates/components/-report/campaign/metrics.hbs +++ b/app/templates/components/-report/campaign/metrics.hbs @@ -1,34 +1,6 @@ -
- {{-report/data-card - icon="eye" - title="Impressions" - format="0.[00]a" - value=metrics.views - color="text-info" - subtitle="Displayed viewable impressions" - isLoading=isActionRunning - }} -
-
- {{-report/data-card - icon="direction" - title="Clicks" - format="0.[0]a" - value=metrics.clicks - color="text-warning" - subtitle="Success of online ads" - isLoading=isActionRunning - }} -
-
- {{-report/data-card - icon="area-graph" - title="CTR" - format="0.[000]%" - value=metrics.ctr - color="text-success" - subtitle="Click-through rate" - isLoading=isActionRunning - }} -
- +{{-report/campaign/metric-cards + isLoading=isActionRunning + views=metrics.views + clicks=metrics.clicks + ctr=metrics.ctr +}} From 78eba220e9e5cff7429dc3eb1b2652241e8a8616 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 15:10:02 -0500 Subject: [PATCH 22/56] Create initial reuable metrics chart --- app/components/-report/metrics-chart.js | 34 +++++++++++++++++++ .../-report/metrics-chart/metric-selector.js | 14 ++++++++ .../components/-report/metrics-chart.hbs | 16 +++++++++ .../-report/metrics-chart/metric-selector.hbs | 9 +++++ 4 files changed, 73 insertions(+) create mode 100644 app/components/-report/metrics-chart.js create mode 100644 app/components/-report/metrics-chart/metric-selector.js create mode 100644 app/templates/components/-report/metrics-chart.hbs create mode 100644 app/templates/components/-report/metrics-chart/metric-selector.hbs diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js new file mode 100644 index 00000000..e166200a --- /dev/null +++ b/app/components/-report/metrics-chart.js @@ -0,0 +1,34 @@ +import Component from '@ember/component'; +import moment from 'moment'; +import InitValueMixin from 'fortnight/mixins/init-value'; +import ActionMixin from 'fortnight/mixins/action'; + +export default Component.extend(InitValueMixin, ActionMixin, { + classNames: ['card'], + dates: null, + + isLoading: false, + + selectedMetric: null, + metricOptions: null, + + init() { + this._super(...arguments); + this.initDates(); + }, + + initDates() { + const now = moment(); + if (!this.get('endDate')) { + this.set('endDate', now); + this.set('startDate', moment(now).subtract(7, 'days')) + } + }, + + actions: { + setMetric(metric) { + this.set('selectedMetric', metric); + this.sendEventAction('on-metric-change', metric); + } + }, +}); diff --git a/app/components/-report/metrics-chart/metric-selector.js b/app/components/-report/metrics-chart/metric-selector.js new file mode 100644 index 00000000..cd268694 --- /dev/null +++ b/app/components/-report/metrics-chart/metric-selector.js @@ -0,0 +1,14 @@ +import Component from '@ember/component'; +import InitValueMixin from 'fortnight/mixins/init-value'; + +export default Component.extend(InitValueMixin, { + selected: null, + options: null, + + disabled: false, + + init() { + this._super(...arguments); + this.initValue('metricOptions', []); + }, +}); diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs new file mode 100644 index 00000000..effc4fa2 --- /dev/null +++ b/app/templates/components/-report/metrics-chart.hbs @@ -0,0 +1,16 @@ +
+
+
+ {{-report/metrics-chart/metric-selector + selected=selectedMetric + options=metricOptions + disabled=isLoading + onchange=(action "setMetric") + }} +
+
+ Date Range +
+
+
+ diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs new file mode 100644 index 00000000..ea38f5fd --- /dev/null +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -0,0 +1,9 @@ +{{#power-select + options=options + selected=selected + searchField="label" + disabled=disabled + onchange=onchange as |metric| +}} + {{metric.label}} +{{/power-select}} From 30eab117d689b21a44b921ca3fe9e6596a05841a Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 15:51:06 -0500 Subject: [PATCH 23/56] Add metric chart date selector --- app/components/-report/metrics-chart.js | 19 ++++++++++----- .../-report/metrics-chart/date-selector.js | 24 +++++++++++++++++++ .../-report/metrics-chart/metric-selector.js | 10 +++++++- app/styles/app.scss | 4 ++++ .../components/-report/metrics-chart.hbs | 11 ++++++--- .../-report/metrics-chart/date-selector.hbs | 9 +++++++ .../-report/metrics-chart/metric-selector.hbs | 3 ++- 7 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 app/components/-report/metrics-chart/date-selector.js create mode 100644 app/templates/components/-report/metrics-chart/date-selector.hbs diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index e166200a..ce50ed68 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -5,13 +5,15 @@ import ActionMixin from 'fortnight/mixins/action'; export default Component.extend(InitValueMixin, ActionMixin, { classNames: ['card'], - dates: null, - isLoading: false, + startDate: null, + endDate: null, selectedMetric: null, metricOptions: null, + isLoading: false, + init() { this._super(...arguments); this.initDates(); @@ -26,9 +28,14 @@ export default Component.extend(InitValueMixin, ActionMixin, { }, actions: { - setMetric(metric) { - this.set('selectedMetric', metric); - this.sendEventAction('on-metric-change', metric); - } + dispatchChange() { + const { + startDate, + endDate, + selectedMetric, + } = this.getProperties('startDate', 'endDate', 'selectedMetric'); + console.info('dispatch', { startDate, endDate, selectedMetric }); + this.sendEventAction('onchange', { startDate, endDate, selectedMetric }); + }, }, }); diff --git a/app/components/-report/metrics-chart/date-selector.js b/app/components/-report/metrics-chart/date-selector.js new file mode 100644 index 00000000..8e9fdc12 --- /dev/null +++ b/app/components/-report/metrics-chart/date-selector.js @@ -0,0 +1,24 @@ +import Component from '@ember/component'; +import InitValueMixin from 'fortnight/mixins/init-value'; +import ActionMixin from 'fortnight/mixins/action'; +import moment from 'moment'; + +export default Component.extend(ActionMixin, InitValueMixin, { + center: null, + + disabled: false, + + init() { + this._super(...arguments); + const endDate = this.get('range.end'); + this.initValue('center', endDate ? moment(endDate) : moment()); + }, + + actions: { + setRange(range) { + this.set('range', range); + const { start, end } = range; + if (start && end) this.sendEventAction('onchange', range); + } + }, +}); diff --git a/app/components/-report/metrics-chart/metric-selector.js b/app/components/-report/metrics-chart/metric-selector.js index cd268694..0dc5e85a 100644 --- a/app/components/-report/metrics-chart/metric-selector.js +++ b/app/components/-report/metrics-chart/metric-selector.js @@ -1,7 +1,8 @@ import Component from '@ember/component'; import InitValueMixin from 'fortnight/mixins/init-value'; +import ActionMixin from 'fortnight/mixins/action'; -export default Component.extend(InitValueMixin, { +export default Component.extend(ActionMixin, InitValueMixin, { selected: null, options: null, @@ -11,4 +12,11 @@ export default Component.extend(InitValueMixin, { this._super(...arguments); this.initValue('metricOptions', []); }, + + actions: { + setMetric(metric) { + this.set('selected', metric); + this.sendEventAction('onchange', metric); + } + }, }); diff --git a/app/styles/app.scss b/app/styles/app.scss index 382a5aeb..4c0850e5 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -32,6 +32,10 @@ padding-bottom: 1rem; } +.metric-selector { + max-width: 200px !important; +} + // Utility for removing underlines in links. a.no-underline { diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index effc4fa2..6791dca9 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -5,11 +5,16 @@ selected=selectedMetric options=metricOptions disabled=isLoading - onchange=(action "setMetric") + onchange=(action "dispatchChange") }} -
- Date Range +
+ {{-report/metrics-chart/date-selector + class="float-right" + disabled=isLoading + range=(hash start=startDate end=endDate) + onchange=(action "dispatchChange") + }}
diff --git a/app/templates/components/-report/metrics-chart/date-selector.hbs b/app/templates/components/-report/metrics-chart/date-selector.hbs new file mode 100644 index 00000000..de47c089 --- /dev/null +++ b/app/templates/components/-report/metrics-chart/date-selector.hbs @@ -0,0 +1,9 @@ +{{#power-calendar-range + center=center + selected=range + disabled=disabled + onCenterChange=(action (mut center) value="moment") + onSelect=(action "setRange" value="moment") as |calendar|}} + {{calendar.nav}} + {{calendar.days}} +{{/power-calendar-range}} diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs index ea38f5fd..7e68caa7 100644 --- a/app/templates/components/-report/metrics-chart/metric-selector.hbs +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -1,9 +1,10 @@ {{#power-select + triggerClass="metric-selector" options=options selected=selected searchField="label" disabled=disabled - onchange=onchange as |metric| + onchange=(action "setMetric") as |metric| }} {{metric.label}} {{/power-select}} From 7958e3395b1c6379d07148be9c41235a38e10830 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 15:52:05 -0500 Subject: [PATCH 24/56] Do not assume a date range if not passed to chart --- app/components/-report/metrics-chart.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index ce50ed68..73fedc2d 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -1,5 +1,4 @@ import Component from '@ember/component'; -import moment from 'moment'; import InitValueMixin from 'fortnight/mixins/init-value'; import ActionMixin from 'fortnight/mixins/action'; @@ -14,19 +13,6 @@ export default Component.extend(InitValueMixin, ActionMixin, { isLoading: false, - init() { - this._super(...arguments); - this.initDates(); - }, - - initDates() { - const now = moment(); - if (!this.get('endDate')) { - this.set('endDate', now); - this.set('startDate', moment(now).subtract(7, 'days')) - } - }, - actions: { dispatchChange() { const { From e1ca7fcd32c5894f7aa05a49005d88edff88d068 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 16:11:21 -0500 Subject: [PATCH 25/56] Add dropdown to date selector --- .../-report/metrics-chart/date-selector.js | 19 ++++++++++-- .../-report/metrics-chart/date-selector.hbs | 31 +++++++++++++------ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/app/components/-report/metrics-chart/date-selector.js b/app/components/-report/metrics-chart/date-selector.js index 8e9fdc12..f4703623 100644 --- a/app/components/-report/metrics-chart/date-selector.js +++ b/app/components/-report/metrics-chart/date-selector.js @@ -5,6 +5,7 @@ import moment from 'moment'; export default Component.extend(ActionMixin, InitValueMixin, { center: null, + format: 'MMM Do, YYYY', disabled: false, @@ -12,13 +13,27 @@ export default Component.extend(ActionMixin, InitValueMixin, { this._super(...arguments); const endDate = this.get('range.end'); this.initValue('center', endDate ? moment(endDate) : moment()); + this.setDropdownLabel(); + }, + + setDropdownLabel() { + const { start, end } = this.get('range'); + const format = this.get('format'); + if (!start || !end) return 'Select Date Range'; + const label = `${moment(start).format(format)} - ${moment(end).format(format)}`; + this.set('dropdownLabel', label); }, actions: { - setRange(range) { + setRange(dropdown, value) { + const range = value.moment; this.set('range', range); const { start, end } = range; - if (start && end) this.sendEventAction('onchange', range); + if (start && end) { + this.setDropdownLabel(); + dropdown.actions.close(); + this.sendEventAction('onchange', range); + } } }, }); diff --git a/app/templates/components/-report/metrics-chart/date-selector.hbs b/app/templates/components/-report/metrics-chart/date-selector.hbs index de47c089..9d2f6cb8 100644 --- a/app/templates/components/-report/metrics-chart/date-selector.hbs +++ b/app/templates/components/-report/metrics-chart/date-selector.hbs @@ -1,9 +1,22 @@ -{{#power-calendar-range - center=center - selected=range - disabled=disabled - onCenterChange=(action (mut center) value="moment") - onSelect=(action "setRange" value="moment") as |calendar|}} - {{calendar.nav}} - {{calendar.days}} -{{/power-calendar-range}} +{{#basic-dropdown as |dropdown|}} + + + {{#dropdown.content}} +
+
+ {{#power-calendar-range + center=center + selected=range + disabled=disabled + onCenterChange=(action (mut center) value="moment") + onSelect=(action "setRange" dropdown) as |calendar|}} + {{calendar.nav}} + {{calendar.days}} + {{/power-calendar-range}} +
+
+ {{/dropdown.content}} +{{/basic-dropdown}} From 7abdeb869e8a8bd98cf61b1ffadb26777e81b19e Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Mon, 20 Aug 2018 16:23:57 -0500 Subject: [PATCH 26/56] Update metric selector to use dropdown toggle --- .../-report/metrics-chart/metric-selector.js | 11 +++++++--- .../components/-report/metrics-chart.hbs | 2 +- .../-report/metrics-chart/metric-selector.hbs | 20 +++++++++---------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/components/-report/metrics-chart/metric-selector.js b/app/components/-report/metrics-chart/metric-selector.js index 0dc5e85a..ae696107 100644 --- a/app/components/-report/metrics-chart/metric-selector.js +++ b/app/components/-report/metrics-chart/metric-selector.js @@ -1,21 +1,26 @@ import Component from '@ember/component'; +import { computed } from '@ember/object'; import InitValueMixin from 'fortnight/mixins/init-value'; import ActionMixin from 'fortnight/mixins/action'; export default Component.extend(ActionMixin, InitValueMixin, { - selected: null, + selectedKey: null, options: null, + selected: computed('selectedKey', 'options.@each.key', function() { + return this.get('options').find(option => option.key === this.get('selectedKey')); + }), + disabled: false, init() { this._super(...arguments); - this.initValue('metricOptions', []); + this.initValue('options', []); }, actions: { setMetric(metric) { - this.set('selected', metric); + this.set('selectedKey', metric.key); this.sendEventAction('onchange', metric); } }, diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index 6791dca9..58b353ad 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -2,7 +2,7 @@
{{-report/metrics-chart/metric-selector - selected=selectedMetric + selectedKey=selectedMetric options=metricOptions disabled=isLoading onchange=(action "dispatchChange") diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs index 7e68caa7..fa75a129 100644 --- a/app/templates/components/-report/metrics-chart/metric-selector.hbs +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -1,10 +1,10 @@ -{{#power-select - triggerClass="metric-selector" - options=options - selected=selected - searchField="label" - disabled=disabled - onchange=(action "setMetric") as |metric| -}} - {{metric.label}} -{{/power-select}} + From 459cc32bc7f596e696deac78cf0c262e416c3e3d Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 09:00:03 -0500 Subject: [PATCH 27/56] Create initial chart --- app/components/-report/metrics-chart/chart.js | 70 +++++++++++++++++++ .../components/-report/metrics-chart.hbs | 5 ++ .../-report/metrics-chart/chart.hbs | 4 ++ 3 files changed, 79 insertions(+) create mode 100644 app/components/-report/metrics-chart/chart.js create mode 100644 app/templates/components/-report/metrics-chart/chart.hbs diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js new file mode 100644 index 00000000..39c29679 --- /dev/null +++ b/app/components/-report/metrics-chart/chart.js @@ -0,0 +1,70 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import InitValueMixin from 'fortnight/mixins/init-value'; + +export default Component.extend(InitValueMixin, { + + /** + * The categories to display + */ + categories: null, + + /** + * The data to display + */ + data: null, + + label: 'Metric Label', + + isLoading: false, + + series: computed('data.length', 'label', function() { + const data = this.get('data'); + const name = this.get('label'); + return [{ + name, + data, + }]; + }), + + options: computed('series', 'data.length', function() { + const { length } = this.get('data'); + return { + chart: { type: 'areaspline' }, + legend: { enabled: false }, + title: { text: false }, + xAxis: { + categories: this.get('categories'), + min: 0.5, + max: length - 1.5, + }, + // tooltip: { + // formatter: function() { + // const value = format ? numeral(this.y).format(format) : this.y; + // const { index, color } = this.point; + // const { longDate } = rows[index]; + // return `${longDate}
+ // \u25CF ${this.series.name}: ${value} + // `; + // }, + // }, + yAxis: { + title: { text: this.get('label') }, + // labels: { + // formatter: function() { + // return labelFormat ? numeral(this.value).format(labelFormat) : this.value; + // }, + // }, + }, + plotOptions: { + areaspline: { fillOpacity: 0.5 }, + }, + }; + }), + + init() { + this._super(...arguments); + this.initValue('data', []); + this.initValue('categories', []); + }, +}); diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index 58b353ad..7ab19d6b 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -17,5 +17,10 @@ }}
+
+
+ {{-report/metrics-chart/chart}} +
+
diff --git a/app/templates/components/-report/metrics-chart/chart.hbs b/app/templates/components/-report/metrics-chart/chart.hbs new file mode 100644 index 00000000..a5d550f7 --- /dev/null +++ b/app/templates/components/-report/metrics-chart/chart.hbs @@ -0,0 +1,4 @@ +{{#if title}} +
{{title}}
+{{/if}} +{{high-charts series=series options=options}} From b7759648e8953dd0c6a7ac12650e05a7f48b93a6 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 09:20:14 -0500 Subject: [PATCH 28/56] Rework action handling --- app/components/-report/metrics-chart.js | 72 ++++++++++++++++--- .../-report/metrics-chart/metric-selector.js | 24 +++++-- .../components/-report/metrics-chart.hbs | 8 +-- .../-report/metrics-chart/metric-selector.hbs | 1 + 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index 73fedc2d..c6e9cb2e 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -1,27 +1,81 @@ import Component from '@ember/component'; +import { computed } from '@ember/object'; import InitValueMixin from 'fortnight/mixins/init-value'; import ActionMixin from 'fortnight/mixins/action'; export default Component.extend(InitValueMixin, ActionMixin, { classNames: ['card'], + /** + * The chart start date. + * + * @type {Date} + */ startDate: null, + + /** + * The chart end date. + * + * @type {Date} + */ endDate: null, - selectedMetric: null, + /** + * The currently selected metric key, e.g. `views`. + * + * @type {string} + */ + metricKey: '', + + /** + * An array of metric option objects. + * For example: + * `[ { key: 'views', label: 'Impressions' } ]` + * + * @type {object[]} + */ metricOptions: null, + /** + * Determines the selected metric option object, based on the `metricKey` value. + * + * @type {object} + */ + selectedMetric: computed('metricKey', 'metricOptions.@each.key', function() { + return this.get('metricOptions').find(option => option.key === this.get('metricKey')); + }), + + /** + * Whether data for the chart is being loaded. + * + * @type {boolean} + */ isLoading: false, + /** + * Dispatches the change event. + * Will send the `startDate`, `endDate`, and `selectedMetric` as an object + * as the first argument, and the component instance as the second. + */ + dispatchChange() { + const { + startDate, + endDate, + selectedMetric, + } = this.getProperties('startDate', 'endDate', 'selectedMetric'); + console.info('dispatch', { startDate, endDate, selectedMetric }); + this.sendEventAction('onchange', { startDate, endDate, selectedMetric }); + }, + actions: { - dispatchChange() { - const { - startDate, - endDate, - selectedMetric, - } = this.getProperties('startDate', 'endDate', 'selectedMetric'); - console.info('dispatch', { startDate, endDate, selectedMetric }); - this.sendEventAction('onchange', { startDate, endDate, selectedMetric }); + setMetric({ key }) { + this.set('metricKey', key); + this.dispatchChange(); + }, + setDates({ start, end }) { + this.set('startDate', start); + this.set('endDate', end); + this.dispatchChange(); }, }, }); diff --git a/app/components/-report/metrics-chart/metric-selector.js b/app/components/-report/metrics-chart/metric-selector.js index ae696107..d37d3e23 100644 --- a/app/components/-report/metrics-chart/metric-selector.js +++ b/app/components/-report/metrics-chart/metric-selector.js @@ -1,16 +1,29 @@ import Component from '@ember/component'; -import { computed } from '@ember/object'; import InitValueMixin from 'fortnight/mixins/init-value'; import ActionMixin from 'fortnight/mixins/action'; export default Component.extend(ActionMixin, InitValueMixin, { - selectedKey: null, + /** + * The metric options, as an array of metric objects. + * For example: + * `[ { key: 'views', label: 'Impressions' } ]` + * + * @type {object[]} + */ options: null, - selected: computed('selectedKey', 'options.@each.key', function() { - return this.get('options').find(option => option.key === this.get('selectedKey')); - }), + /** + * The selected metric object, e.g. `{ key: 'views', label: 'Impressions' }` + * + * @type {object} + */ + selected: null, + /** + * Whether the control is disabled. + * + * @type {boolean} + */ disabled: false, init() { @@ -20,7 +33,6 @@ export default Component.extend(ActionMixin, InitValueMixin, { actions: { setMetric(metric) { - this.set('selectedKey', metric.key); this.sendEventAction('onchange', metric); } }, diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index 7ab19d6b..9dda5ea0 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -2,10 +2,10 @@
{{-report/metrics-chart/metric-selector - selectedKey=selectedMetric + selected=selectedMetric options=metricOptions disabled=isLoading - onchange=(action "dispatchChange") + onchange=(action "setMetric") }}
@@ -13,11 +13,11 @@ class="float-right" disabled=isLoading range=(hash start=startDate end=endDate) - onchange=(action "dispatchChange") + onchange=(action "setDates") }}
-
+
{{-report/metrics-chart/chart}}
diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs index fa75a129..bbe760c4 100644 --- a/app/templates/components/-report/metrics-chart/metric-selector.hbs +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -1,5 +1,6 @@ diff --git a/app/templates/components/-report/metrics-chart/date-selector.hbs b/app/templates/components/-report/metrics-chart/date-selector.hbs index 9d2f6cb8..a2ffc373 100644 --- a/app/templates/components/-report/metrics-chart/date-selector.hbs +++ b/app/templates/components/-report/metrics-chart/date-selector.hbs @@ -1,5 +1,5 @@ {{#basic-dropdown as |dropdown|}} - diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs index bbe760c4..d732198d 100644 --- a/app/templates/components/-report/metrics-chart/metric-selector.hbs +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -1,5 +1,5 @@
- {{-report/metrics-chart/chart isLoading=isLoading}} + {{-report/metrics-chart/chart label=selectedMetric.label isLoading=isLoading}}
diff --git a/app/templates/components/-report/metrics-chart/chart.hbs b/app/templates/components/-report/metrics-chart/chart.hbs index a5d550f7..7173ce0b 100644 --- a/app/templates/components/-report/metrics-chart/chart.hbs +++ b/app/templates/components/-report/metrics-chart/chart.hbs @@ -1,4 +1,4 @@ {{#if title}}
{{title}}
{{/if}} -{{high-charts series=series options=options}} +
From e1c85db4bda8d779244d6f07eb9824a58e07f083 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:06:45 -0500 Subject: [PATCH 32/56] Chart rendering/redraw --- app/components/-report/metrics-chart.js | 26 +++++++- app/components/-report/metrics-chart/chart.js | 65 ++++++++++++------- .../-report/metrics-chart/date-selector.js | 16 +++-- .../-report/metrics-chart/metric-selector.js | 5 +- .../components/-report/metrics-chart.hbs | 9 ++- .../-report/metrics-chart/date-selector.hbs | 2 +- .../-report/metrics-chart/metric-selector.hbs | 2 +- 7 files changed, 88 insertions(+), 37 deletions(-) diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index 52fe4097..340bc2df 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -1,9 +1,8 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; -import InitValueMixin from 'fortnight/mixins/init-value'; import ActionMixin from 'fortnight/mixins/action'; -export default Component.extend(InitValueMixin, ActionMixin, { +export default Component.extend(ActionMixin, { classNames: ['card'], /** @@ -52,6 +51,28 @@ export default Component.extend(InitValueMixin, ActionMixin, { */ isLoading: false, + /** + * The report data rows. + * + * Expects an object with `shortDate`, `longDate`, and `metrics`. + * For example: + * ``` + * [ + * { shortDate: 'Aug 14', longDate: 'Tuesday, August 14th, 2018', metrics: { views: 24 } }, + * { shortDate: 'Aug 15', longDate: 'Wednesday, August 15th, 2018', metrics: { views: 12 } }, + * ] + * ``` + */ + rows: null, + + categories: computed.mapBy('rows', 'shortDate'), + + data: computed('rows.[]', function() { + const key = this.get('metricKey'); + const rows = this.get('rows') || []; + return rows.map(row => row.metrics[key]); + }), + /** * Dispatches the change event. * Will send the `startDate`, `endDate`, and `selectedMetric` as an object @@ -63,7 +84,6 @@ export default Component.extend(InitValueMixin, ActionMixin, { endDate, selectedMetric, } = this.getProperties('startDate', 'endDate', 'selectedMetric'); - console.info('dispatch', { startDate, endDate, selectedMetric }); this.sendEventAction('onchange', { startDate, endDate, selectedMetric }, this); }, diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js index 50827053..93c48f16 100644 --- a/app/components/-report/metrics-chart/chart.js +++ b/app/components/-report/metrics-chart/chart.js @@ -1,25 +1,38 @@ import Component from '@ember/component'; import { computed, observer } from '@ember/object'; -import InitValueMixin from 'fortnight/mixins/init-value'; -export default Component.extend(InitValueMixin, { +export default Component.extend({ /** * The categories to display + * + * @type {array} */ categories: null, /** - * The data to display + * The data to display. + * + * @type {array} */ data: null, + /** + * The y-axis label/title and series name. + * + * @type {string} + */ label: 'Metric Label', + /** + * Whether the chart is loading. + * + * @type {boolean} + */ isLoading: false, - series: computed('data.length', 'label', function() { - const data = this.get('data'); + series: computed(function() { + const data = this.get('data') || []; const name = this.get('label'); return [{ name, @@ -27,8 +40,9 @@ export default Component.extend(InitValueMixin, { }]; }), - options: computed('series', 'data.length', function() { + options: computed(function() { const { length } = this.get('data'); + const tooltipFormatter = this.get('tooltipFormatter'); return { chart: { type: 'areaspline' }, legend: { enabled: false }, @@ -38,16 +52,16 @@ export default Component.extend(InitValueMixin, { min: 0.5, max: length - 1.5, }, - // tooltip: { - // formatter: function() { - // const value = format ? numeral(this.y).format(format) : this.y; - // const { index, color } = this.point; - // const { longDate } = rows[index]; - // return `${longDate}
- // \u25CF ${this.series.name}: ${value} - // `; - // }, - // }, + tooltip: { + // formatter: function() { + // const value = format ? numeral(this.y).format(format) : this.y; + // const { index, color } = this.point; + // const { longDate } = rows[index]; + // return `${longDate}
+ // \u25CF ${this.series.name}: ${value} + // `; + // }, + }, yAxis: { title: { text: this.get('label') }, // labels: { @@ -62,7 +76,7 @@ export default Component.extend(InitValueMixin, { }; }), - config: computed('options', 'series', function() { + config: computed(function() { const config = this.get('options') || {}; config.series = this.get('series') || []; return config; @@ -77,11 +91,18 @@ export default Component.extend(InitValueMixin, { } }), - init() { - this._super(...arguments); - this.initValue('data', []); - this.initValue('categories', []); - }, + updateChart: observer('data.[]', function() { + const chart = this.get('chart'); + // Update the yAxis label. + chart.yAxis[0].setTitle({ text: this.get('label') }, false); + // Set the new xAxis categories and extremes. + chart.xAxis[0].setCategories(this.get('categories'), false); + chart.xAxis[0].setExtremes(0.5, this.get('data.length') - 1.5, false); + // Set the new series data and name. + chart.series[0].setData(this.get('data'), false); + chart.series[0].update({ name: this.get('label') }, false); + chart.redraw(true); + }), didInsertElement() { const config = this.get('config'); diff --git a/app/components/-report/metrics-chart/date-selector.js b/app/components/-report/metrics-chart/date-selector.js index f4703623..14485725 100644 --- a/app/components/-report/metrics-chart/date-selector.js +++ b/app/components/-report/metrics-chart/date-selector.js @@ -26,13 +26,15 @@ export default Component.extend(ActionMixin, InitValueMixin, { actions: { setRange(dropdown, value) { - const range = value.moment; - this.set('range', range); - const { start, end } = range; - if (start && end) { - this.setDropdownLabel(); - dropdown.actions.close(); - this.sendEventAction('onchange', range); + if (!this.get('disabled')) { + const range = value.moment; + this.set('range', range); + const { start, end } = range; + if (start && end) { + this.setDropdownLabel(); + dropdown.actions.close(); + this.sendEventAction('onchange', range); + } } } }, diff --git a/app/components/-report/metrics-chart/metric-selector.js b/app/components/-report/metrics-chart/metric-selector.js index d37d3e23..99efc9da 100644 --- a/app/components/-report/metrics-chart/metric-selector.js +++ b/app/components/-report/metrics-chart/metric-selector.js @@ -21,6 +21,7 @@ export default Component.extend(ActionMixin, InitValueMixin, { /** * Whether the control is disabled. + * Will not visibly change the control, but will not change the value if clicked. * * @type {boolean} */ @@ -33,7 +34,9 @@ export default Component.extend(ActionMixin, InitValueMixin, { actions: { setMetric(metric) { - this.sendEventAction('onchange', metric); + if (!this.get('disabled')) { + this.sendEventAction('onchange', metric); + } } }, }); diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index 88ba341a..dc8b90a3 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -17,9 +17,14 @@ }}
-
+
- {{-report/metrics-chart/chart label=selectedMetric.label isLoading=isLoading}} + {{-report/metrics-chart/chart + label=selectedMetric.label + isLoading=isLoading + categories=categories + data=data + }}
diff --git a/app/templates/components/-report/metrics-chart/date-selector.hbs b/app/templates/components/-report/metrics-chart/date-selector.hbs index a2ffc373..9d2f6cb8 100644 --- a/app/templates/components/-report/metrics-chart/date-selector.hbs +++ b/app/templates/components/-report/metrics-chart/date-selector.hbs @@ -1,5 +1,5 @@ {{#basic-dropdown as |dropdown|}} - diff --git a/app/templates/components/-report/metrics-chart/metric-selector.hbs b/app/templates/components/-report/metrics-chart/metric-selector.hbs index d732198d..bbe760c4 100644 --- a/app/templates/components/-report/metrics-chart/metric-selector.hbs +++ b/app/templates/components/-report/metrics-chart/metric-selector.hbs @@ -1,5 +1,5 @@ From ce4d8354e7cdca85508067c976393c2b6e5e1448 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:23:13 -0500 Subject: [PATCH 34/56] Add tooltip and label formatting --- app/components/-report/metrics-chart.js | 2 +- app/components/-report/metrics-chart/chart.js | 16 +++++++++------- .../components/-report/metrics-chart.hbs | 2 ++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index d31417d8..979cb125 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -29,7 +29,7 @@ export default Component.extend(ActionMixin, { /** * An array of metric option objects. * For example: - * `[ { key: 'views', label: 'Impressions' } ]` + * `[ { key: 'views', label: 'Impressions', tooltipFormat: '0,0', labelFormat: '0.[0]a' } ]` * * @type {object[]} */ diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js index 80c40f22..af5794eb 100644 --- a/app/components/-report/metrics-chart/chart.js +++ b/app/components/-report/metrics-chart/chart.js @@ -1,5 +1,6 @@ import Component from '@ember/component'; import { computed, observer } from '@ember/object'; +import numeral from 'numeral'; export default Component.extend({ /** @@ -73,8 +74,8 @@ export default Component.extend({ }, tooltip: { formatter: function() { - const value = this.y; - // const value = format ? numeral(this.y).format(format) : this.y; + const format = component.get('tooltipFormat'); + const value = format ? numeral(this.y).format(format) : this.y; const { index, color } = this.point; const longDate = component.get(`days.${index}.longDate`); return `${longDate}
@@ -84,11 +85,12 @@ export default Component.extend({ }, yAxis: { title: { text: this.get('label') }, - // labels: { - // formatter: function() { - // return labelFormat ? numeral(this.value).format(labelFormat) : this.value; - // }, - // }, + labels: { + formatter: function() { + const format = component.get('labelFormat'); + return format ? numeral(this.value).format(format) : this.value; + }, + }, }, plotOptions: { areaspline: { fillOpacity: 0.5 }, diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index f0993123..f30d7c6e 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -24,6 +24,8 @@ isLoading=isLoading days=days data=data + tooltipFormat=selectedMetric.tooltipFormat + labelFormat=selectedMetric.labelFormat }} From 19acbede2332c95227fe10e4343575c996986d89 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:26:33 -0500 Subject: [PATCH 35/56] Remove uneeded metrics by day components --- .../-report/campaign/metrics-by-day.js | 100 ------------------ .../-report/campaign/metrics-by-day.hbs | 6 -- 2 files changed, 106 deletions(-) delete mode 100644 app/components/-report/campaign/metrics-by-day.js delete mode 100644 app/templates/components/-report/campaign/metrics-by-day.hbs diff --git a/app/components/-report/campaign/metrics-by-day.js b/app/components/-report/campaign/metrics-by-day.js deleted file mode 100644 index bda21c65..00000000 --- a/app/components/-report/campaign/metrics-by-day.js +++ /dev/null @@ -1,100 +0,0 @@ -import Component from '@ember/component'; -import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; -import ActionMixin from 'fortnight/mixins/action-mixin'; -import { computed } from '@ember/object'; -import moment from 'moment'; -import numeral from 'numeral'; - -import query from 'fortnight/gql/queries/campaign/reports/by-day'; - -export default Component.extend(ActionMixin, ObjectQueryManager, { - metric: 'views', - label: 'Impressions', - format: null, - labelFormat: null, - - startDate: computed('endDate', function() { - return moment(this.get('endDate')).subtract(14, 'days'); - }), - - endDate: computed(function() { - return moment().startOf('day'); - }), - - data: computed('rows.[]', function() { - const rows = this.get('rows') || []; - const key = this.get('metric'); - return rows.map(row => row.metrics[key]); - }), - - series: computed('data.length', function() { - const data = this.get('data'); - const name = this.get('label'); - return [{ - name, - data, - }]; - }), - - options: computed('series', 'data.length', function() { - const rows = this.get('rows') || []; - const { length } = this.get('data'); - const format = this.get('format'); - const labelFormat = this.get('labelFormat'); - return { - chart: { type: 'areaspline' }, - legend: { enabled: false }, - title: { text: false }, - xAxis: { - categories: rows.map(row => row.shortDate), - min: 0.5, - max: length - 1.5, - }, - tooltip: { - formatter: function() { - - const value = format ? numeral(this.y).format(format) : this.y; - const { index, color } = this.point; - const { longDate } = rows[index]; - return `${longDate}
- \u25CF ${this.series.name}: ${value} - `; - }, - }, - yAxis: { - title: { text: this.get('label') }, - labels: { - formatter: function() { - return labelFormat ? numeral(this.value).format(labelFormat) : this.value; - }, - }, - }, - plotOptions: { - areaspline: { fillOpacity: 0.5 }, - }, - }; - }), - - init() { - this._super(...arguments); - this.query(); - }, - - async query() { - this.startAction(); - const variables = { - input: { id: this.get('campaignId') }, - startDate: this.get('startDate').valueOf(), - endDate: this.get('endDate').valueOf(), - }; - try { - const { reports } = await this.get('apollo').query({ query, variables }, 'campaign'); - this.set('rows', reports.byDay); - } catch (e) { - this.get('graphErrors').show(e); - } finally { - this.endAction(); - } - }, - -}); diff --git a/app/templates/components/-report/campaign/metrics-by-day.hbs b/app/templates/components/-report/campaign/metrics-by-day.hbs deleted file mode 100644 index 8373f215..00000000 --- a/app/templates/components/-report/campaign/metrics-by-day.hbs +++ /dev/null @@ -1,6 +0,0 @@ -{{-report/data-chart - title=(concat label " for the last 14 days") - isLoading=isActionRunning - series=series - options=options -}} From 571cc606ce422cd4fbfa79b9fe0ed32f9cf59275 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:26:47 -0500 Subject: [PATCH 36/56] Ensure campaign by day report uses campaign hash --- app/gql/queries/campaign/reports/by-day.graphql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/gql/queries/campaign/reports/by-day.graphql b/app/gql/queries/campaign/reports/by-day.graphql index 1b21dee0..ca5b2e70 100644 --- a/app/gql/queries/campaign/reports/by-day.graphql +++ b/app/gql/queries/campaign/reports/by-day.graphql @@ -1,5 +1,5 @@ -query CampaignReportByDay($input: ModelIdInput!, $startDate: Date!, $endDate: Date!) { - campaign(input: $input) { +query CampaignReportByDay($input: CampaignHashInput!, $startDate: Date!, $endDate: Date!) { + campaignHash(input: $input) { id reports { byDay(startDate: $startDate, endDate: $endDate) { From 76fa1946962ba274ef3ac741b87f9331f44e365b Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:27:17 -0500 Subject: [PATCH 37/56] Remove undeeded creatve breakdown route --- .../manage/report/creative-breakdown.js | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 app/routes/portal/campaigns/manage/report/creative-breakdown.js diff --git a/app/routes/portal/campaigns/manage/report/creative-breakdown.js b/app/routes/portal/campaigns/manage/report/creative-breakdown.js deleted file mode 100644 index a2659961..00000000 --- a/app/routes/portal/campaigns/manage/report/creative-breakdown.js +++ /dev/null @@ -1,17 +0,0 @@ -import Route from '@ember/routing/route'; -import RouteQueryManager from 'ember-apollo-client/mixins/route-query-manager'; - -import query from 'fortnight/gql/queries/reports/campaign/creative-breakdown'; - -export default Route.extend(RouteQueryManager, { - - model() { - const { advertiser, campaign } = this.modelFor('portal.campaigns.manage'); - const hash = campaign.hash; - const advertiserId = advertiser.id; - const variables = { input: { hash, advertiserId } }; - this.controllerFor(this.get('routeName')).set('campaign', campaign); - return this.get('apollo').watchQuery({ query, variables, fetchPolicy: 'network-only' }, 'reportCampaignCreativeBreakdown'); - } -}) - From 436098d51b92ead356a39b141a95c600e3179ee6 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:36:32 -0500 Subject: [PATCH 38/56] Update overall campaign metrics to use hash query --- app/components/-report/campaign/metrics.js | 8 ++++---- app/gql/queries/campaign/metrics.graphql | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/components/-report/campaign/metrics.js b/app/components/-report/campaign/metrics.js index 61a60eea..28354f47 100644 --- a/app/components/-report/campaign/metrics.js +++ b/app/components/-report/campaign/metrics.js @@ -5,16 +5,16 @@ import ActionMixin from 'fortnight/mixins/action-mixin'; import query from 'fortnight/gql/queries/campaign/metrics'; export default Component.extend(ActionMixin, ObjectQueryManager, { - init() { - this._super(...arguments); + didInsertElement() { this.query(); }, async query() { this.startAction(); - const variables = { input: { id: this.get('campaignId') } }; + const input = { hash: this.get('hash'), advertiserId: this.get('advertiserId') }; + const variables = { input }; try { - const { metrics } = await this.get('apollo').query({ query, variables }, 'campaign'); + const { metrics } = await this.get('apollo').query({ query, variables }, 'campaignHash'); this.set('metrics', metrics); } catch (e) { this.get('graphErrors').show(e); diff --git a/app/gql/queries/campaign/metrics.graphql b/app/gql/queries/campaign/metrics.graphql index efb984b8..c0a33415 100644 --- a/app/gql/queries/campaign/metrics.graphql +++ b/app/gql/queries/campaign/metrics.graphql @@ -1,5 +1,5 @@ -query CampaignMetrics($input: ModelIdInput!) { - campaign(input: $input) { +query CampaignMetrics($input: CampaignHashInput!) { + campaignHash(input: $input) { id metrics { views From c0eedd29ebaa93b62212d0d2a18a62688658fcdd Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:42:36 -0500 Subject: [PATCH 39/56] Add on chart insert action handling --- app/components/-report/metrics-chart.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/components/-report/metrics-chart.js b/app/components/-report/metrics-chart.js index 979cb125..ceca24ad 100644 --- a/app/components/-report/metrics-chart.js +++ b/app/components/-report/metrics-chart.js @@ -75,6 +75,10 @@ export default Component.extend(ActionMixin, { return rows.map(row => row.metrics[key]); }), + didInsertElement() { + this.sendEventAction('oninsert', this); + }, + /** * Dispatches the change event. * Will send the `startDate`, `endDate`, and `selectedMetric` as an object From f15d657c576c3dfd584d2ee8474424b885438288 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:42:52 -0500 Subject: [PATCH 40/56] Update campaign summary to use metrics chart --- .../portal/campaigns/manage/report/summary.js | 61 ++++++++++++++----- .../campaigns/manage/report/summary.hbs | 16 +++-- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/app/controllers/portal/campaigns/manage/report/summary.js b/app/controllers/portal/campaigns/manage/report/summary.js index 9823f0a1..182c1010 100644 --- a/app/controllers/portal/campaigns/manage/report/summary.js +++ b/app/controllers/portal/campaigns/manage/report/summary.js @@ -1,25 +1,54 @@ import Controller from '@ember/controller'; import { computed } from '@ember/object'; -import ImpressionDataMixin from 'fortnight/mixins/impression-data-mixin'; +import { inject } from '@ember/service'; +import moment from 'moment' -export default Controller.extend(ImpressionDataMixin, { +import query from 'fortnight/gql/queries/campaign/reports/by-day'; - impressionSummaryTimeSeries: computed('model.days.[]', function() { - const type = 'line'; - const name = 'Daily Impressions'; - const data = this.get('model.days').map((d) => { - return { x: d.date, y: d.views }; - }); - return [{ type, name, data }]; +export default Controller.extend({ + apollo: inject(), + + metricKey: 'ctr', + metricOptions: null, + isReportRunning: false, + + selectedMetric: computed('metricKey', 'metricOptions', function() { + return this.get('metricOptions').find(opt => opt.key === this.get('metricKey')); }), - ctrSummaryTimeSeries: computed('model.days.[]', function() { - const type = 'line'; - const name = 'Daily CTR'; - const data = this.get('model.days').map((d) => { - return { x: d.date, y: d.ctr }; - }); - return [{ type, name, data }]; + startDate: computed('endDate', function() { + return moment(this.get('endDate')).subtract(7, 'days'); }), + endDate: computed(function() { + return moment(); + }), + + init() { + this._super(...arguments); + this.set('metricOptions', [ + { key: 'views', label: 'Impressions', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'clicks', label: 'Clicks', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'ctr', label: 'CTR', tooltipFormat: '0.[000]%', labelFormat: '0.[000]%' }, + ]); + }, + + actions: { + async runByDayReport({ startDate, endDate }) { + this.set('isReportRunning', true); + const variables = { + input: { hash: this.get('model.campaign.hash'), advertiserId: this.get('model.advertiser.id') }, + startDate: startDate.startOf('day').valueOf(), + endDate: endDate.startOf('day').valueOf(), + }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'campaignHash'); + this.set('rows', reports.byDay); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.set('isReportRunning', false); + } + }, + }, }); diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 902db592..4ffd2a2a 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -50,12 +50,20 @@

Total Metrics

- {{-report/campaign/metrics campaignId=model.campaign.id}} + {{-report/campaign/metrics hash=model.campaign.hash advertiserId=model.advertiser.id}}

Metrics Over Time

- {{-report/campaign/metrics-by-day campaignId=model.campaign.id metric="views" label="Impressions" class="mb-4" labelFormat="0.[0]a" format="0,0"}} - {{-report/campaign/metrics-by-day campaignId=model.campaign.id metric="ctr" label="CTR" labelFormat="0.[000]%" format="0.[000]%"}} - + {{-report/metrics-chart + class="border-0 z-depth-half" + startDate=startDate + endDate=endDate + metricOptions=metricOptions + metricKey=metricKey + isLoading=isReportRunning + rows=rows + oninsert=(action "runByDayReport") + onchange=(action "runByDayReport") + }} From 7fa47800ad3c214560ca06173ac658e5554dcef0 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 11:49:57 -0500 Subject: [PATCH 41/56] Add support for single day/point --- app/components/-report/metrics-chart/chart.js | 12 +++++++++--- .../-report/metrics-chart/date-selector.hbs | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js index af5794eb..6c95efc6 100644 --- a/app/components/-report/metrics-chart/chart.js +++ b/app/components/-report/metrics-chart/chart.js @@ -61,6 +61,12 @@ export default Component.extend({ }]; }), + extremes: computed('data.length', function() { + const length = this.get('data.length'); + if (length > 1) return { min: 0.5, max: length - 1.5 }; + return {}; + }), + options: computed(function() { const component = this; return { @@ -69,8 +75,8 @@ export default Component.extend({ title: { text: false }, xAxis: { categories: this.get('categories'), - min: 0.5, - max: this.get('data.length') - 1.5, + min: this.get('extremes.min'), + max: this.get('extremes.max'), }, tooltip: { formatter: function() { @@ -119,7 +125,7 @@ export default Component.extend({ chart.yAxis[0].setTitle({ text: this.get('label') }, false); // Set the new xAxis categories and extremes. chart.xAxis[0].setCategories(this.get('categories'), false); - chart.xAxis[0].setExtremes(0.5, this.get('data.length') - 1.5, false); + chart.xAxis[0].setExtremes(this.get('extremes.min'), this.get('extremes.max'), false); // Set the new series data and name. chart.series[0].setData(this.get('data'), false); chart.series[0].update({ name: this.get('label') }, false); diff --git a/app/templates/components/-report/metrics-chart/date-selector.hbs b/app/templates/components/-report/metrics-chart/date-selector.hbs index 9d2f6cb8..4f64530f 100644 --- a/app/templates/components/-report/metrics-chart/date-selector.hbs +++ b/app/templates/components/-report/metrics-chart/date-selector.hbs @@ -11,6 +11,7 @@ center=center selected=range disabled=disabled + minRange=0 onCenterChange=(action (mut center) value="moment") onSelect=(action "setRange" dropdown) as |calendar|}} {{calendar.nav}} From de17f54449cb0aa85f755a3377183efb35956b8a Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 12:14:50 -0500 Subject: [PATCH 42/56] Create metrics service --- app/services/metrics.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 app/services/metrics.js diff --git a/app/services/metrics.js b/app/services/metrics.js new file mode 100644 index 00000000..be5fc929 --- /dev/null +++ b/app/services/metrics.js @@ -0,0 +1,22 @@ +import Service from '@ember/service'; +import EmberObject from '@ember/object'; + +const campaignMetrics = EmberObject.extend({ + init() { + this.set('array', [ + { key: 'views', label: 'Impressions', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'clicks', label: 'Clicks', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'ctr', label: 'CTR', tooltipFormat: '0.[000]%', labelFormat: '0.[000]%' }, + ]); + this.get('array').forEach((metric) => { + this.set(metric.key, metric); + }); + }, +}); + +export default Service.extend({ + init() { + this._super(...arguments); + this.set('campaign', campaignMetrics.create()); + }, +}); From d7eb4fc3dbcd0dc3a1df02ce56a455a4d5a79f90 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 12:15:37 -0500 Subject: [PATCH 43/56] Apply metrics service to summary --- .../portal/campaigns/manage/report/summary.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/controllers/portal/campaigns/manage/report/summary.js b/app/controllers/portal/campaigns/manage/report/summary.js index 182c1010..5642f2fa 100644 --- a/app/controllers/portal/campaigns/manage/report/summary.js +++ b/app/controllers/portal/campaigns/manage/report/summary.js @@ -7,13 +7,14 @@ import query from 'fortnight/gql/queries/campaign/reports/by-day'; export default Controller.extend({ apollo: inject(), + metrics: inject(), metricKey: 'ctr', - metricOptions: null, + metricOptions: computed.reads('metrics.campaign.array'), isReportRunning: false, - selectedMetric: computed('metricKey', 'metricOptions', function() { - return this.get('metricOptions').find(opt => opt.key === this.get('metricKey')); + selectedMetric: computed('metricKey', function() { + return this.get(`metrics.campaign.${this.get('metricKey')}`); }), startDate: computed('endDate', function() { @@ -24,15 +25,6 @@ export default Controller.extend({ return moment(); }), - init() { - this._super(...arguments); - this.set('metricOptions', [ - { key: 'views', label: 'Impressions', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, - { key: 'clicks', label: 'Clicks', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, - { key: 'ctr', label: 'CTR', tooltipFormat: '0.[000]%', labelFormat: '0.[000]%' }, - ]); - }, - actions: { async runByDayReport({ startDate, endDate }) { this.set('isReportRunning', true); From 3695a0543914126b9469f10a9e05a7a799d926e8 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 12:45:39 -0500 Subject: [PATCH 44/56] Set minrange of chart to 1 --- app/components/-report/metrics-chart/chart.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js index 6c95efc6..6bc36b1d 100644 --- a/app/components/-report/metrics-chart/chart.js +++ b/app/components/-report/metrics-chart/chart.js @@ -77,6 +77,7 @@ export default Component.extend({ categories: this.get('categories'), min: this.get('extremes.min'), max: this.get('extremes.max'), + minRange: 1, }, tooltip: { formatter: function() { From bf1d5362d26cf2206a70c51393edf1189ce6ba71 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 12:49:58 -0500 Subject: [PATCH 45/56] Place metric loading bar inside card and not over chart --- app/components/-report/metrics-chart/chart.js | 9 --------- app/templates/components/-report/metrics-chart.hbs | 4 ++++ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/components/-report/metrics-chart/chart.js b/app/components/-report/metrics-chart/chart.js index 6bc36b1d..36c08920 100644 --- a/app/components/-report/metrics-chart/chart.js +++ b/app/components/-report/metrics-chart/chart.js @@ -111,15 +111,6 @@ export default Component.extend({ return config; }), - showLoading: observer('isLoading', function() { - const chart = this.get('chart'); - if (this.get('isLoading')) { - chart.showLoading(); - } else { - chart.hideLoading(); - } - }), - updateChart: observer('data.[]', function() { const chart = this.get('chart'); // Update the yAxis label. diff --git a/app/templates/components/-report/metrics-chart.hbs b/app/templates/components/-report/metrics-chart.hbs index f30d7c6e..60be51d6 100644 --- a/app/templates/components/-report/metrics-chart.hbs +++ b/app/templates/components/-report/metrics-chart.hbs @@ -17,6 +17,9 @@ }} + +{{progress-bar show=isLoading}} +
{{-report/metrics-chart/chart @@ -31,3 +34,4 @@
+ From 69762633193371eb263ef99471153cf4c197efa1 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 14:18:14 -0500 Subject: [PATCH 46/56] Wrap campaign report into own component --- app/components/-report/campaign/chart.js | 23 +++++++++++++++++++ .../portal/campaigns/manage/report/summary.js | 19 --------------- .../components/-report/campaign/chart.hbs | 11 +++++++++ .../campaigns/manage/report/summary.hbs | 7 +----- 4 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 app/components/-report/campaign/chart.js create mode 100644 app/templates/components/-report/campaign/chart.hbs diff --git a/app/components/-report/campaign/chart.js b/app/components/-report/campaign/chart.js new file mode 100644 index 00000000..bb0bee7d --- /dev/null +++ b/app/components/-report/campaign/chart.js @@ -0,0 +1,23 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { inject } from '@ember/service'; +import moment from 'moment' + +export default Component.extend({ + metrics: inject(), + + isLoading: false, + + metricKey: 'ctr', + metricOptions: computed.reads('metrics.campaign.array').readOnly(), + selectedMetric: computed('metricKey', function() { + return this.get(`metrics.campaign.${this.get('metricKey')}`); + }).readOnly(), + + startDate: computed('endDate', function() { + return moment(this.get('endDate')).subtract(7, 'days'); + }), + endDate: computed(function() { + return moment(); + }), +}); diff --git a/app/controllers/portal/campaigns/manage/report/summary.js b/app/controllers/portal/campaigns/manage/report/summary.js index 5642f2fa..d5180373 100644 --- a/app/controllers/portal/campaigns/manage/report/summary.js +++ b/app/controllers/portal/campaigns/manage/report/summary.js @@ -1,29 +1,10 @@ import Controller from '@ember/controller'; -import { computed } from '@ember/object'; import { inject } from '@ember/service'; -import moment from 'moment' import query from 'fortnight/gql/queries/campaign/reports/by-day'; export default Controller.extend({ apollo: inject(), - metrics: inject(), - - metricKey: 'ctr', - metricOptions: computed.reads('metrics.campaign.array'), - isReportRunning: false, - - selectedMetric: computed('metricKey', function() { - return this.get(`metrics.campaign.${this.get('metricKey')}`); - }), - - startDate: computed('endDate', function() { - return moment(this.get('endDate')).subtract(7, 'days'); - }), - - endDate: computed(function() { - return moment(); - }), actions: { async runByDayReport({ startDate, endDate }) { diff --git a/app/templates/components/-report/campaign/chart.hbs b/app/templates/components/-report/campaign/chart.hbs new file mode 100644 index 00000000..c169e810 --- /dev/null +++ b/app/templates/components/-report/campaign/chart.hbs @@ -0,0 +1,11 @@ +{{-report/metrics-chart + class="border-0 z-depth-half" + startDate=startDate + endDate=endDate + metricOptions=metricOptions + metricKey=metricKey + isLoading=isLoading + rows=rows + oninsert=oninsert + onchange=onchange +}} diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 4ffd2a2a..85e87b0a 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -53,12 +53,7 @@ {{-report/campaign/metrics hash=model.campaign.hash advertiserId=model.advertiser.id}}

Metrics Over Time

- {{-report/metrics-chart - class="border-0 z-depth-half" - startDate=startDate - endDate=endDate - metricOptions=metricOptions - metricKey=metricKey + {{-report/campaign/chart isLoading=isReportRunning rows=rows oninsert=(action "runByDayReport") From cc4dd407f1e3f6d9cb94743397c46b7d6d2cb077 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 14:25:03 -0500 Subject: [PATCH 47/56] Move query outside of campaign metrics component --- app/components/-report/campaign/metrics.js | 24 ++++--------------- .../portal/campaigns/manage/report/summary.js | 23 ++++++++++++++++-- .../components/-report/campaign/metrics.hbs | 2 +- .../campaigns/manage/report/summary.hbs | 6 ++++- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/app/components/-report/campaign/metrics.js b/app/components/-report/campaign/metrics.js index 28354f47..4f7c24e5 100644 --- a/app/components/-report/campaign/metrics.js +++ b/app/components/-report/campaign/metrics.js @@ -1,26 +1,10 @@ import Component from '@ember/component'; -import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; -import ActionMixin from 'fortnight/mixins/action-mixin'; +import ActionMixin from 'fortnight/mixins/action'; -import query from 'fortnight/gql/queries/campaign/metrics'; +export default Component.extend(ActionMixin, { + isLoading: false, -export default Component.extend(ActionMixin, ObjectQueryManager, { didInsertElement() { - this.query(); + this.sendEventAction('oninsert', this); }, - - async query() { - this.startAction(); - const input = { hash: this.get('hash'), advertiserId: this.get('advertiserId') }; - const variables = { input }; - try { - const { metrics } = await this.get('apollo').query({ query, variables }, 'campaignHash'); - this.set('metrics', metrics); - } catch (e) { - this.get('graphErrors').show(e); - } finally { - this.endAction(); - } - }, - }); diff --git a/app/controllers/portal/campaigns/manage/report/summary.js b/app/controllers/portal/campaigns/manage/report/summary.js index d5180373..7b4186b6 100644 --- a/app/controllers/portal/campaigns/manage/report/summary.js +++ b/app/controllers/portal/campaigns/manage/report/summary.js @@ -1,11 +1,15 @@ import Controller from '@ember/controller'; import { inject } from '@ember/service'; -import query from 'fortnight/gql/queries/campaign/reports/by-day'; +import reportByDay from 'fortnight/gql/queries/campaign/reports/by-day'; +import campaignMetrics from 'fortnight/gql/queries/campaign/metrics'; export default Controller.extend({ apollo: inject(), + isReportRunning: false, + areMetricsLoading: false, + actions: { async runByDayReport({ startDate, endDate }) { this.set('isReportRunning', true); @@ -15,7 +19,7 @@ export default Controller.extend({ endDate: endDate.startOf('day').valueOf(), }; try { - const { reports } = await this.get('apollo').query({ query, variables }, 'campaignHash'); + const { reports } = await this.get('apollo').query({ query: reportByDay, variables }, 'campaignHash'); this.set('rows', reports.byDay); } catch (e) { this.get('graphErrors').show(e); @@ -23,5 +27,20 @@ export default Controller.extend({ this.set('isReportRunning', false); } }, + + async retrieveCampaignMetrics() { + this.set('areMetricsLoading', true); + const variables = { + input: { hash: this.get('model.campaign.hash'), advertiserId: this.get('model.advertiser.id') }, + }; + try { + const { metrics } = await this.get('apollo').query({ query: campaignMetrics, variables }, 'campaignHash'); + this.set('metrics', metrics); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.set('areMetricsLoading', false); + } + }, }, }); diff --git a/app/templates/components/-report/campaign/metrics.hbs b/app/templates/components/-report/campaign/metrics.hbs index 0f93257c..9a1c01ee 100644 --- a/app/templates/components/-report/campaign/metrics.hbs +++ b/app/templates/components/-report/campaign/metrics.hbs @@ -1,5 +1,5 @@ {{-report/campaign/metric-cards - isLoading=isActionRunning + isLoading=isLoading views=metrics.views clicks=metrics.clicks ctr=metrics.ctr diff --git a/app/templates/portal/campaigns/manage/report/summary.hbs b/app/templates/portal/campaigns/manage/report/summary.hbs index 85e87b0a..1e2d118a 100644 --- a/app/templates/portal/campaigns/manage/report/summary.hbs +++ b/app/templates/portal/campaigns/manage/report/summary.hbs @@ -50,7 +50,11 @@

Total Metrics

- {{-report/campaign/metrics hash=model.campaign.hash advertiserId=model.advertiser.id}} + {{-report/campaign/metrics + isLoading=areMetricsLoading + metrics=metrics + oninsert=(action "retrieveCampaignMetrics") + }}

Metrics Over Time

{{-report/campaign/chart From fb2d7877368536cb29f7f76ce3d853d4ef387484 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 14:40:30 -0500 Subject: [PATCH 48/56] Add campaign creative breakdown components --- app/components/-report/campaign/creative.js | 48 +++++++++++++++ .../queries/campaign/creative-metrics.graphql | 10 ++++ .../campaign/reports/creative-by-day.graphql | 16 +++++ .../components/-report/campaign/creative.hbs | 16 +++++ .../manage/report/creative-breakdown.hbs | 59 ++++++++++++++++++- 5 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 app/components/-report/campaign/creative.js create mode 100644 app/gql/queries/campaign/creative-metrics.graphql create mode 100644 app/gql/queries/campaign/reports/creative-by-day.graphql create mode 100644 app/templates/components/-report/campaign/creative.hbs diff --git a/app/components/-report/campaign/creative.js b/app/components/-report/campaign/creative.js new file mode 100644 index 00000000..abd84042 --- /dev/null +++ b/app/components/-report/campaign/creative.js @@ -0,0 +1,48 @@ +import Component from '@ember/component'; +import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; + +import reportByDay from 'fortnight/gql/queries/campaign/reports/creative-by-day'; +import creativeMetrics from 'fortnight/gql/queries/campaign/creative-metrics'; + +export default Component.extend(ObjectQueryManager, { + isReportRunning: false, + areMetricsLoading: false, + + campaignId: null, + creativeId: null, + + actions: { + async runByDayReport({ startDate, endDate }) { + this.set('isReportRunning', true); + const variables = { + input: { campaignId: this.get('campaignId'), creativeId: this.get('creativeId') }, + startDate: startDate.startOf('day').valueOf(), + endDate: endDate.startOf('day').valueOf(), + }; + try { + const { reports } = await this.get('apollo').query({ query: reportByDay, variables }, 'campaignCreative'); + this.set('rows', reports.byDay); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.set('isReportRunning', false); + } + }, + + async retrieveCreativeMetrics() { + this.set('areMetricsLoading', true); + const variables = { + input: { campaignId: this.get('campaignId'), creativeId: this.get('creativeId') }, + }; + try { + const { metrics } = await this.get('apollo').query({ query: creativeMetrics, variables }, 'campaignCreative'); + this.set('metrics', metrics); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.set('areMetricsLoading', false); + } + }, + }, + +}); diff --git a/app/gql/queries/campaign/creative-metrics.graphql b/app/gql/queries/campaign/creative-metrics.graphql new file mode 100644 index 00000000..bbc833a6 --- /dev/null +++ b/app/gql/queries/campaign/creative-metrics.graphql @@ -0,0 +1,10 @@ +query CampaignCreativeMetrics($input: CampaignCreativeInput!) { + campaignCreative(input: $input) { + id + metrics { + views + clicks + ctr + } + } +} diff --git a/app/gql/queries/campaign/reports/creative-by-day.graphql b/app/gql/queries/campaign/reports/creative-by-day.graphql new file mode 100644 index 00000000..8633ebc5 --- /dev/null +++ b/app/gql/queries/campaign/reports/creative-by-day.graphql @@ -0,0 +1,16 @@ +query CampaignCreativeReportByDay($input: CampaignCreativeInput!, $startDate: Date!, $endDate: Date!) { + campaignCreative(input: $input) { + id + reports { + byDay(startDate: $startDate, endDate: $endDate) { + shortDate: day(format: "MMM D") + longDate: day(format: "dddd, MMMM Do, YYYY") + metrics { + views + clicks + ctr + } + } + } + } +} diff --git a/app/templates/components/-report/campaign/creative.hbs b/app/templates/components/-report/campaign/creative.hbs new file mode 100644 index 00000000..8f57260e --- /dev/null +++ b/app/templates/components/-report/campaign/creative.hbs @@ -0,0 +1,16 @@ +{{-report/campaign/metrics + isLoading=areMetricsLoading + metrics=metrics + oninsert=(action "retrieveCreativeMetrics") +}} + +
+
+ {{-report/campaign/chart + isLoading=isReportRunning + rows=rows + oninsert=(action "runByDayReport") + onchange=(action "runByDayReport") + }} +
+
diff --git a/app/templates/portal/campaigns/manage/report/creative-breakdown.hbs b/app/templates/portal/campaigns/manage/report/creative-breakdown.hbs index 9bf11f44..9cca53c5 100644 --- a/app/templates/portal/campaigns/manage/report/creative-breakdown.hbs +++ b/app/templates/portal/campaigns/manage/report/creative-breakdown.hbs @@ -1,4 +1,59 @@ -
+
+
+
+ +
+
+ {{-report/title title="Campaign Creative Report" subtitle="A breakdown of how your individual creatives are performing"}} +
+
+ + {{#each model.campaign.creatives as |creative|}} +
+
+ +
+
+
+ {{campaign-creative/preview-grid creative=creative campaign=model.campaign}} +
+
+
+ +
+ {{-report/campaign/creative + campaignId=model.campaign.id + creativeId=creative.id + }} +
+ +
+
+ + + + {{!--
+
+ {{-report/creative-card + creative=creativeSummary.creative + campaign=model.campaignHash + clicks=creativeSummary.clicks + views=creativeSummary.views + ctr=creativeSummary.ctr + totalClicks=clicks + totalViews=impressions + totalCtr=ctr + }} +
+
--}} + {{/each}} + +
+
+
+ + +{{!--
@@ -57,4 +112,4 @@
-
+
--}} From f5555fc28d0dfd08a70033b4641b8190e9974814 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 15:07:45 -0500 Subject: [PATCH 49/56] Add story metrics --- app/components/-report/campaign/chart.js | 2 +- app/components/-report/story/chart.js | 23 +++++++++++++++++++++++ app/services/metrics.js | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 app/components/-report/story/chart.js diff --git a/app/components/-report/campaign/chart.js b/app/components/-report/campaign/chart.js index bb0bee7d..cb9a55fc 100644 --- a/app/components/-report/campaign/chart.js +++ b/app/components/-report/campaign/chart.js @@ -15,7 +15,7 @@ export default Component.extend({ }).readOnly(), startDate: computed('endDate', function() { - return moment(this.get('endDate')).subtract(7, 'days'); + return moment(this.get('endDate')).subtract(14, 'days'); }), endDate: computed(function() { return moment(); diff --git a/app/components/-report/story/chart.js b/app/components/-report/story/chart.js new file mode 100644 index 00000000..eded89e3 --- /dev/null +++ b/app/components/-report/story/chart.js @@ -0,0 +1,23 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { inject } from '@ember/service'; +import moment from 'moment' + +export default Component.extend({ + metrics: inject(), + + isLoading: false, + + metricKey: 'pageviews', + metricOptions: computed.reads('metrics.story.array').readOnly(), + selectedMetric: computed('metricKey', function() { + return this.get(`metrics.story.${this.get('metricKey')}`); + }).readOnly(), + + startDate: computed('endDate', function() { + return moment(this.get('endDate')).subtract(14, 'days'); + }), + endDate: computed(function() { + return moment(); + }), +}); diff --git a/app/services/metrics.js b/app/services/metrics.js index be5fc929..4540630e 100644 --- a/app/services/metrics.js +++ b/app/services/metrics.js @@ -14,9 +14,23 @@ const campaignMetrics = EmberObject.extend({ }, }); +const storyMetrics = EmberObject.extend({ + init() { + this.set('array', [ + { key: 'pageviews', label: 'Pageviews', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'sessions', label: 'Sessions', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'users', label: 'Users', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + ]); + this.get('array').forEach((metric) => { + this.set(metric.key, metric); + }); + }, +}); + export default Service.extend({ init() { this._super(...arguments); this.set('campaign', campaignMetrics.create()); + this.set('story', storyMetrics.create()); }, }); From 65187cc7216d34273c66cd519687eebdb68509c8 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Tue, 21 Aug 2018 15:16:24 -0500 Subject: [PATCH 50/56] Use new metrics chart for story report --- .../-report/story/metrics-by-day.js | 98 ++++--------------- app/gql/queries/story/reports/by-day.graphql | 1 + app/services/metrics.js | 1 + .../components/-report/story/chart.hbs | 11 +++ .../-report/story/metrics-by-day.hbs | 16 +-- 5 files changed, 43 insertions(+), 84 deletions(-) create mode 100644 app/templates/components/-report/story/chart.hbs diff --git a/app/components/-report/story/metrics-by-day.js b/app/components/-report/story/metrics-by-day.js index ac6d1105..7c5ea57b 100644 --- a/app/components/-report/story/metrics-by-day.js +++ b/app/components/-report/story/metrics-by-day.js @@ -1,85 +1,27 @@ import Component from '@ember/component'; import ObjectQueryManager from 'ember-apollo-client/mixins/object-query-manager'; -import ActionMixin from 'fortnight/mixins/action-mixin'; -import { computed } from '@ember/object'; -import moment from 'moment'; import query from 'fortnight/gql/queries/story/reports/by-day'; -export default Component.extend(ActionMixin, ObjectQueryManager, { - tagName: '', - - startDate: computed('endDate', function() { - return moment(this.get('endDate')).subtract(14, 'days'); - }), - - endDate: computed(function() { - return moment(); - }), - - data: computed('rows.[]', function() { - const rows = this.get('rows') || []; - return rows.map(row => row.metrics.pageviews); - }), - - series: computed('data.length', function() { - const data = this.get('data'); - return [{ - name: 'Pageviews', - data, - }]; - }), - - options: computed('series', 'data.length', function() { - const rows = this.get('rows') || []; - const { length } = this.get('data'); - return { - chart: { type: 'areaspline' }, - legend: { enabled: false }, - title: { text: false }, - xAxis: { - categories: rows.map(row => row.shortDate), - min: 0.5, - max: length - 1.5, - }, - tooltip: { - formatter: function() { - const { index, color } = this.point; - const { longDate } = rows[index]; - return `${longDate}
- \u25CF ${this.series.name}: ${this.y} - `; - }, - }, - yAxis: { - title: { text: 'Pageviews' }, - }, - plotOptions: { - areaspline: { fillOpacity: 0.5 }, - }, - }; - }), - - init() { - this._super(...arguments); - this.query(); - }, - - async query() { - this.startAction(); - const variables = { - input: { id: this.get('storyId') }, - startDate: this.get('startDate').valueOf(), - endDate: this.get('endDate').valueOf(), - }; - try { - const { reports } = await this.get('apollo').query({ query, variables }, 'story'); - this.set('rows', reports.byDay); - } catch (e) { - this.get('graphErrors').show(e); - } finally { - this.endAction(); - } +export default Component.extend( ObjectQueryManager, { + isReportRunning: false, + + actions: { + async runByDayReport({ startDate, endDate }) { + this.set('isReportRunning', true); + const variables = { + input: { id: this.get('storyId') }, + startDate: startDate.valueOf(), + endDate: endDate.valueOf(), + }; + try { + const { reports } = await this.get('apollo').query({ query, variables }, 'story'); + this.set('rows', reports.byDay); + } catch (e) { + this.get('graphErrors').show(e); + } finally { + this.set('isReportRunning', false); + } + }, }, - }); diff --git a/app/gql/queries/story/reports/by-day.graphql b/app/gql/queries/story/reports/by-day.graphql index cacbafae..cf3e8896 100644 --- a/app/gql/queries/story/reports/by-day.graphql +++ b/app/gql/queries/story/reports/by-day.graphql @@ -7,6 +7,7 @@ query StoryReportByDay($input: ModelIdInput!, $startDate: Date!, $endDate: Date! longDate: date(format: "dddd, MMMM Do, YYYY") metrics { users + sessions pageviews shares } diff --git a/app/services/metrics.js b/app/services/metrics.js index 4540630e..7666fe3a 100644 --- a/app/services/metrics.js +++ b/app/services/metrics.js @@ -20,6 +20,7 @@ const storyMetrics = EmberObject.extend({ { key: 'pageviews', label: 'Pageviews', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, { key: 'sessions', label: 'Sessions', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, { key: 'users', label: 'Users', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, + { key: 'shares', label: 'Shares', tooltipFormat: '0,0', labelFormat: '0.[0]a' }, ]); this.get('array').forEach((metric) => { this.set(metric.key, metric); diff --git a/app/templates/components/-report/story/chart.hbs b/app/templates/components/-report/story/chart.hbs new file mode 100644 index 00000000..c169e810 --- /dev/null +++ b/app/templates/components/-report/story/chart.hbs @@ -0,0 +1,11 @@ +{{-report/metrics-chart + class="border-0 z-depth-half" + startDate=startDate + endDate=endDate + metricOptions=metricOptions + metricKey=metricKey + isLoading=isLoading + rows=rows + oninsert=oninsert + onchange=onchange +}} diff --git a/app/templates/components/-report/story/metrics-by-day.hbs b/app/templates/components/-report/story/metrics-by-day.hbs index 05edc677..0e28f0c3 100644 --- a/app/templates/components/-report/story/metrics-by-day.hbs +++ b/app/templates/components/-report/story/metrics-by-day.hbs @@ -1,6 +1,10 @@ -{{-report/data-chart - title="Views for the last 14 days" - isLoading=isActionRunning - series=series - options=options -}} +
+
+ {{-report/story/chart + isLoading=isReportRunning + rows=rows + oninsert=(action "runByDayReport") + onchange=(action "runByDayReport") + }} +
+
From 1bc52354907c9f43db858d1e5f827405e88c1cbd Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 11:36:12 -0500 Subject: [PATCH 51/56] Remove placement metrics --- app/components/dashboard/placement-metrics.js | 40 ----------- .../dashboard/placement-metrics.hbs | 69 ------------------- 2 files changed, 109 deletions(-) delete mode 100644 app/components/dashboard/placement-metrics.js delete mode 100644 app/templates/components/dashboard/placement-metrics.hbs diff --git a/app/components/dashboard/placement-metrics.js b/app/components/dashboard/placement-metrics.js deleted file mode 100644 index 7a7ae2a9..00000000 --- a/app/components/dashboard/placement-metrics.js +++ /dev/null @@ -1,40 +0,0 @@ -import Component from '@ember/component'; -import ComponentQueryManager from 'ember-apollo-client/mixins/component-query-manager'; -import { getObservable } from 'ember-apollo-client'; - -import query from 'fortnight/gql/queries/placement/dashboard'; - -export default Component.extend(ComponentQueryManager, { - classNames: ['card', 'border-0', 'z-depth-half'], - start: null, - end: null, - - isLoading: true, - - didInsertElement() { - this.loadData(); - }, - - async loadData() { - this.set('isLoading', true); - - const pagination = { first: 25 }; - const sort = { field: 'createdAt', order: -1 }; - const variables = { - pagination, - sort, - metricsStartDate: this.get('start').valueOf(), - metricsEndDate: this.get('end').valueOf(), - }; - - try { - const data = await this.get('apollo').watchQuery({ query, variables, fetchPolicy: 'network-only' }, 'allPlacements'); - this.set('observable', getObservable(data)); - this.set('data', data); - } catch (e) { - this.get('graphErrors').show(e); - } finally { - this.set('isLoading', false); - } - }, -}); diff --git a/app/templates/components/dashboard/placement-metrics.hbs b/app/templates/components/dashboard/placement-metrics.hbs deleted file mode 100644 index e78c2a9a..00000000 --- a/app/templates/components/dashboard/placement-metrics.hbs +++ /dev/null @@ -1,69 +0,0 @@ -
- {{#if isLoading}} - Loading data... - {{progress-bar show=true}} - {{else}} -
Total Results: {{data.totalCount}}
- {{#fetch-more - class="table-responsive" - query=observable - edges=data.edges - hasNextPage=data.pageInfo.hasNextPage - endCursor=data.pageInfo.endCursor - on-fetch-start=(route-action "showLoading") - on-fetch-end=(route-action "hideLoading") - resultKey="allPlacements" as |fetch| - }} - - - - - - - - - - - - - - - {{#each fetch.nodes as |item|}} - - - - - - {{#with item.metrics as |metrics|}} - - - - {{/with}} - - {{else}} - - - - {{/each}} - - - - {{#if fetch.hasNextPage}} - - - - - - {{/if}} -
PublisherTopicTemplateLabelViewsClicksCTR
{{#link-to "manage.publisher.edit" item.publisher.id}}{{item.publisher.name}}{{/link-to}} - {{#if item.topic.id}} - {{#link-to "manage.topic.edit" item.topic.id}}{{item.topic.name}}{{/link-to}} - {{else}} - (none) - {{/if}} - {{#link-to "manage.template.edit" item.template.id}}{{item.template.name}}{{/link-to}}{{item.name}}{{number-format metrics.views "0,0"}}{{number-format metrics.clicks "0,0"}}{{number-format metrics.ctr "0.[000]%"}}
No placements found.
- {{/fetch-more}} - {{/if}} -
From cbe563f0091aee5d381662875139748599665870 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 11:36:25 -0500 Subject: [PATCH 52/56] Create initial dashboard publisher breakouts --- ...sher-metrics.js => publisher-breakouts.js} | 47 +++++++++++++++++-- ...er-metrics.hbs => publisher-breakouts.hbs} | 30 +++++++++++- app/templates/manage/index.hbs | 16 +------ 3 files changed, 74 insertions(+), 19 deletions(-) rename app/components/dashboard/{publisher-metrics.js => publisher-breakouts.js} (58%) rename app/templates/components/dashboard/{publisher-metrics.hbs => publisher-breakouts.hbs} (73%) diff --git a/app/components/dashboard/publisher-metrics.js b/app/components/dashboard/publisher-breakouts.js similarity index 58% rename from app/components/dashboard/publisher-metrics.js rename to app/components/dashboard/publisher-breakouts.js index 868dc478..f2f69095 100644 --- a/app/components/dashboard/publisher-metrics.js +++ b/app/components/dashboard/publisher-breakouts.js @@ -1,18 +1,57 @@ import Component from '@ember/component'; import ComponentQueryManager from 'ember-apollo-client/mixins/component-query-manager'; import { getObservable } from 'ember-apollo-client'; +import moment from 'moment'; import query from 'fortnight/gql/queries/publisher/dashboard'; + export default Component.extend(ComponentQueryManager, { classNames: ['card', 'border-0', 'z-depth-half'], - start: null, - end: null, - isLoading: true, + /** + * The chart start date. + * + * @type {Date} + */ + startDate: null, + + /** + * The chart end date. + * + * @type {Date} + */ + endDate: null, + + /** + * Whether data for the chart is being loaded. + * + * @type {boolean} + */ + isLoading: false, + + init() { + this._super(...arguments); + // Set initial dates. + const now = moment().startOf('day'); + this.set('endDate', now); + this.set('startDate', moment(now).subtract(14, 'days')); + }, + + actions: { + setDates({ start, end }) { + console.info('setDates', start, end); + this.set('startDate', moment(start).startOf('day')); + this.set('endDate', moment(end).startOf('day')); + }, + }, + + + //////////////// + didInsertElement() { - this.loadData(); + // this.loadData(); }, async loadData() { diff --git a/app/templates/components/dashboard/publisher-metrics.hbs b/app/templates/components/dashboard/publisher-breakouts.hbs similarity index 73% rename from app/templates/components/dashboard/publisher-metrics.hbs rename to app/templates/components/dashboard/publisher-breakouts.hbs index 0f60bc72..6f039135 100644 --- a/app/templates/components/dashboard/publisher-metrics.hbs +++ b/app/templates/components/dashboard/publisher-breakouts.hbs @@ -1,4 +1,32 @@
+
+
+ {{-report/metrics-chart/date-selector + disabled=isLoading + range=(hash start=startDate end=endDate) + onchange=(action "setDates") + }} +
+
+
+{{progress-bar show=isLoading}} +
+
+ {{!--
+ {{-report/metrics-chart/chart + label=selectedMetric.label + isLoading=isLoading + days=days + data=data + tooltipFormat=selectedMetric.tooltipFormat + labelFormat=selectedMetric.labelFormat + }} +
--}} +
+
+ + +{{!--
{{#if isLoading}} Loading data... {{progress-bar show=true}} @@ -54,4 +82,4 @@ {{/fetch-more}} {{/if}} -
+ --}} diff --git a/app/templates/manage/index.hbs b/app/templates/manage/index.hbs index aab9446c..5a135115 100644 --- a/app/templates/manage/index.hbs +++ b/app/templates/manage/index.hbs @@ -77,27 +77,15 @@ -{{!--
-
-

Placement Metrics since {{moment-format startDate "MMMM Do, YYYY"}}

-
-
- -
-
- {{dashboard/placement-metrics start=startDate end=endDate}} -
-
--}} -
-

Publisher Metrics since {{moment-format startDate "MMMM Do, YYYY"}}

+

Publisher Metrics

- {{dashboard/publisher-metrics start=startDate end=endDate}} + {{dashboard/publisher-breakouts}}
From 5e1446207e341df9b386a50f7c4d0edf59e9eab7 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 12:00:52 -0500 Subject: [PATCH 53/56] Add breakout checkboxes --- .../dashboard/publisher-breakouts.js | 13 ++++++++++++- .../dashboard/publisher-breakouts.hbs | 19 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/components/dashboard/publisher-breakouts.js b/app/components/dashboard/publisher-breakouts.js index f2f69095..ecb73afe 100644 --- a/app/components/dashboard/publisher-breakouts.js +++ b/app/components/dashboard/publisher-breakouts.js @@ -32,18 +32,29 @@ export default Component.extend(ComponentQueryManager, { init() { this._super(...arguments); + // Set initial dates. const now = moment().startOf('day'); this.set('endDate', now); this.set('startDate', moment(now).subtract(14, 'days')); + + // Set the initial breakouts + this.set('breakouts', { + publisher: true, + placement: false, + topic: false, + }); }, actions: { setDates({ start, end }) { - console.info('setDates', start, end); this.set('startDate', moment(start).startOf('day')); this.set('endDate', moment(end).startOf('day')); }, + setBreakout(property, event) { + const { checked } = event.target; + this.set(`breakouts.${property}`, checked); + }, }, diff --git a/app/templates/components/dashboard/publisher-breakouts.hbs b/app/templates/components/dashboard/publisher-breakouts.hbs index 6f039135..b6e63457 100644 --- a/app/templates/components/dashboard/publisher-breakouts.hbs +++ b/app/templates/components/dashboard/publisher-breakouts.hbs @@ -1,11 +1,28 @@
-
+
{{-report/metrics-chart/date-selector disabled=isLoading + class="mr-3" range=(hash start=startDate end=endDate) onchange=(action "setDates") }} + +
+
+ + +
+
+ + +
+
+ + +
+
+
From 3f1bf8bb9a81a2532668ab406201b9fec25c1769 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 12:26:35 -0500 Subject: [PATCH 54/56] Add ember-radio-button ^1.2.4 --- package.json | 1 + yarn.lock | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c284d8ef..9af57136 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "ember-notify": "^5.2.1", "ember-power-calendar": "^0.7.2", "ember-power-select": "^2.0.0-beta.5", + "ember-radio-button": "^1.2.4", "ember-resolver": "^4.0.0", "ember-route-action-helper": "^2.0.6", "ember-simple-auth": "^1.6.0", diff --git a/yarn.lock b/yarn.lock index f5531423..c31caeca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2986,7 +2986,7 @@ ember-cli-babel@^6.12.0: ember-cli-version-checker "^2.1.0" semver "^5.4.1" -ember-cli-babel@^6.9.0: +ember-cli-babel@^6.9.0, ember-cli-babel@^6.9.2: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: @@ -3046,7 +3046,7 @@ ember-cli-htmlbars-inline-precompile@^1.0.0: heimdalljs-logger "^0.1.7" silent-error "^1.1.0" -ember-cli-htmlbars@^1.0.3: +ember-cli-htmlbars@^1.0.3, ember-cli-htmlbars@^1.1.1: version "1.3.4" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.4.tgz#461289724b34af372a6a0c4b6635819156963353" dependencies: @@ -3567,6 +3567,13 @@ ember-qunit@^3.3.2: ember-cli-test-loader "^2.2.0" qunit "^2.5.0" +ember-radio-button@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/ember-radio-button/-/ember-radio-button-1.2.4.tgz#7ca1ac03f79036954dbeeb2926350965ee4db497" + dependencies: + ember-cli-babel "^6.9.2" + ember-cli-htmlbars "^1.1.1" + ember-resolver@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.5.0.tgz#9248bf534dfc197fafe3118fff538d436078bf99" From 9dbf0e85e928b5ef992e3b2153fda736848a7101 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 14:14:39 -0500 Subject: [PATCH 55/56] Add breakouts --- .../dashboard/publisher-breakouts.js | 77 +++++++++---------- .../dashboard/publisher-breakouts.graphql | 34 ++++++++ .../dashboard/publisher-breakouts.hbs | 72 ++++++++++++----- 3 files changed, 121 insertions(+), 62 deletions(-) create mode 100644 app/gql/queries/dashboard/publisher-breakouts.graphql diff --git a/app/components/dashboard/publisher-breakouts.js b/app/components/dashboard/publisher-breakouts.js index ecb73afe..a81f553a 100644 --- a/app/components/dashboard/publisher-breakouts.js +++ b/app/components/dashboard/publisher-breakouts.js @@ -1,14 +1,20 @@ import Component from '@ember/component'; import ComponentQueryManager from 'ember-apollo-client/mixins/component-query-manager'; -import { getObservable } from 'ember-apollo-client'; +import { computed } from '@ember/object'; import moment from 'moment'; -import query from 'fortnight/gql/queries/publisher/dashboard'; - +import query from 'fortnight/gql/queries/dashboard/publisher-breakouts'; export default Component.extend(ComponentQueryManager, { classNames: ['card', 'border-0', 'z-depth-half'], + /** + * The currently selected breakout. + * + * @type {string} + */ + breakout: 'publisher', + /** * The chart start date. * @@ -24,12 +30,17 @@ export default Component.extend(ComponentQueryManager, { endDate: null, /** - * Whether data for the chart is being loaded. + * Whether data for the table is being loaded. * * @type {boolean} */ isLoading: false, + rowsChanged: computed('rows.[]', function() { + console.info('rows changed'); + return true; + }), + init() { this._super(...arguments); @@ -37,54 +48,36 @@ export default Component.extend(ComponentQueryManager, { const now = moment().startOf('day'); this.set('endDate', now); this.set('startDate', moment(now).subtract(14, 'days')); - - // Set the initial breakouts - this.set('breakouts', { - publisher: true, - placement: false, - topic: false, - }); - }, - - actions: { - setDates({ start, end }) { - this.set('startDate', moment(start).startOf('day')); - this.set('endDate', moment(end).startOf('day')); - }, - setBreakout(property, event) { - const { checked } = event.target; - this.set(`breakouts.${property}`, checked); - }, }, - - //////////////// - - - didInsertElement() { - // this.loadData(); - }, - - async loadData() { + async query() { this.set('isLoading', true); - const pagination = { first: 25 }; - const sort = { field: 'name', order: 1 }; - const variables = { - pagination, - sort, - metricsStartDate: this.get('start').valueOf(), - metricsEndDate: this.get('end').valueOf(), + const input = { + startDay: this.get('startDate').valueOf(), + endDay: this.get('endDate').valueOf(), + breakout: this.get('breakout'), }; - + const variables = { input }; try { - const data = await this.get('apollo').watchQuery({ query, variables, fetchPolicy: 'network-only' }, 'allPublishers'); - this.set('observable', getObservable(data)); - this.set('data', data); + const rows = await this.get('apollo').query({ query, variables }, 'publisherMetricBreakouts'); + this.set('rows', rows); } catch (e) { this.get('graphErrors').show(e); } finally { this.set('isLoading', false); } }, + + actions: { + setDates({ start, end }) { + this.set('startDate', moment(start).startOf('day')); + this.set('endDate', moment(end).startOf('day')); + this.query(); + }, + setBreakout(breakout) { + this.set('breakout', breakout); + this.query(); + }, + }, }); diff --git a/app/gql/queries/dashboard/publisher-breakouts.graphql b/app/gql/queries/dashboard/publisher-breakouts.graphql new file mode 100644 index 00000000..83cf8476 --- /dev/null +++ b/app/gql/queries/dashboard/publisher-breakouts.graphql @@ -0,0 +1,34 @@ +query DashboardPublisherBreakouts($input: PublisherMetricsInput!) { + publisherMetricBreakouts(input: $input) { + publisher { + id + name + } + placement { + id + publisher { + id + name + } + template { + id + name + } + topic { + id + name + } + } + topic { + id + name + publisher { + id + name + } + } + views + clicks + ctr + } +} diff --git a/app/templates/components/dashboard/publisher-breakouts.hbs b/app/templates/components/dashboard/publisher-breakouts.hbs index b6e63457..aa627137 100644 --- a/app/templates/components/dashboard/publisher-breakouts.hbs +++ b/app/templates/components/dashboard/publisher-breakouts.hbs @@ -9,18 +9,18 @@ }}
-
- +
+ {{radio-button radioId="breakout-publisher" radioClass="custom-control-input" value="publisher" groupValue=breakout changed=(action "setBreakout")}}
-
- - -
-
- +
+ {{radio-button radioId="breakout-topic" radioClass="custom-control-input" value="topic" groupValue=breakout changed=(action "setBreakout")}}
+
+ {{radio-button radioId="breakout-placement" radioClass="custom-control-input" value="placement" groupValue=breakout changed=(action "setBreakout")}} + +
@@ -28,18 +28,50 @@
{{progress-bar show=isLoading}}
-
- {{!--
- {{-report/metrics-chart/chart - label=selectedMetric.label - isLoading=isLoading - days=days - data=data - tooltipFormat=selectedMetric.tooltipFormat - labelFormat=selectedMetric.labelFormat - }} -
--}} -
+ {{#if rowsChanged}} + + + + {{#if (eq breakout "publisher")}} + + {{/if}} + {{#if (eq breakout "topic")}} + + + {{/if}} + {{#if (eq breakout "placement")}} + + + + {{/if}} + + + + + + + {{#each rows as |row|}} + + {{#if (eq breakout "publisher")}} + + {{/if}} + {{#if (eq breakout "placement")}} + + + + {{/if}} + {{#if (eq breakout "topic")}} + + + {{/if}} + + + + + {{/each}} + +
PublisherPublisherTopicPublisherTopicPlacementViewsClicksCTR
{{row.publisher.name}}{{row.placement.publisher.name}}{{row.placement.topic.name}}{{row.placement.template.name}}{{row.topic.publisher.name}}{{row.topic.name}}{{number-format row.views "0,0"}}{{number-format row.clicks "0,0"}}{{number-format row.ctr "0.[000]%"}}
+ {{/if}}
From c0411a206f801e6c7983910fb20aa906843917e7 Mon Sep 17 00:00:00 2001 From: Jacob Bare Date: Wed, 22 Aug 2018 14:16:52 -0500 Subject: [PATCH 56/56] Query on load --- app/components/dashboard/publisher-breakouts.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/components/dashboard/publisher-breakouts.js b/app/components/dashboard/publisher-breakouts.js index a81f553a..38eb480d 100644 --- a/app/components/dashboard/publisher-breakouts.js +++ b/app/components/dashboard/publisher-breakouts.js @@ -37,7 +37,6 @@ export default Component.extend(ComponentQueryManager, { isLoading: false, rowsChanged: computed('rows.[]', function() { - console.info('rows changed'); return true; }), @@ -50,6 +49,10 @@ export default Component.extend(ComponentQueryManager, { this.set('startDate', moment(now).subtract(14, 'days')); }, + didInsertElement() { + this.query(); + }, + async query() { this.set('isLoading', true);