From b540d9f0668babee99c3ae6d368d54d8b3a3b073 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Tue, 14 Sep 2021 10:12:16 +0100 Subject: [PATCH] Removed labs dashboard and feature flag no issue The updated dashboard is shelved for now whilst the underlying analytics architecture is improved. --- ghost/admin/app/controllers/dashboard-labs.js | 270 ------------ ghost/admin/app/router.js | 1 - ghost/admin/app/routes/dashboard-labs.js | 28 -- ghost/admin/app/routes/dashboard.js | 4 - ghost/admin/app/services/feature.js | 1 - ghost/admin/app/templates/dashboard-labs.hbs | 388 ------------------ ghost/admin/app/templates/settings/labs.hbs | 13 - 7 files changed, 705 deletions(-) delete mode 100644 ghost/admin/app/controllers/dashboard-labs.js delete mode 100644 ghost/admin/app/routes/dashboard-labs.js delete mode 100644 ghost/admin/app/templates/dashboard-labs.hbs diff --git a/ghost/admin/app/controllers/dashboard-labs.js b/ghost/admin/app/controllers/dashboard-labs.js deleted file mode 100644 index 40b6c67a5b..0000000000 --- a/ghost/admin/app/controllers/dashboard-labs.js +++ /dev/null @@ -1,270 +0,0 @@ -import Controller from '@ember/controller'; -import {action} from '@ember/object'; -import {getSymbol} from 'ghost-admin/utils/currency'; -import {inject as service} from '@ember/service'; -import {task} from 'ember-concurrency-decorators'; -import {tracked} from '@glimmer/tracking'; - -export default class DashboardController extends Controller { - @service feature; - @service session; - @service membersStats; - @service store; - @service settings; - @service whatsNew; - - @tracked eventsData = null; - @tracked eventsError = null; - @tracked eventsLoading = false; - - @tracked mrrStatsData = null; - @tracked mrrStatsError = null; - @tracked mrrStatsLoading = false; - - @tracked memberCountStatsData = null; - @tracked memberCountStatsError = null; - @tracked memberCountStatsLoading = false; - - @tracked topMembersData = null; - @tracked topMembersError = null; - @tracked topMembersLoading = false; - - @tracked newsletterOpenRatesData = null; - @tracked newsletterOpenRatesError = null; - @tracked newsletterOpenRatesLoading = false; - - @tracked latestNewsletters = null; - - @tracked whatsNewEntries = null; - @tracked whatsNewEntriesLoading = null; - @tracked whatsNewEntriesError = null; - - get topMembersDataHasOpenRates() { - return this.topMembersData && this.topMembersData.find((member) => { - return member.emailOpenRate !== null; - }); - } - - get showMembersData() { - return this.settings.get('membersSignupAccess') !== 'none'; - } - - initialise() { - this.loadEvents(); - this.loadTopMembers(); - this.loadCharts(); - this.loadLatestNewsletters.perform(); - this.loadWhatsNew(); - } - - async loadMRRStats() { - const products = await this.store.query('product', {include: 'monthly_price,yearly_price', limit: 'all'}); - const defaultProduct = products?.firstObject; - - this.mrrStatsLoading = true; - this.membersStats.fetchMRR().then((stats) => { - this.mrrStatsLoading = false; - const statsData = stats.data || []; - const defaultCurrency = defaultProduct?.monthlyPrice?.currency || 'usd'; - let currencyStats = statsData.find((stat) => { - return stat.currency === defaultCurrency; - }); - currencyStats = currencyStats || { - data: [], - currency: defaultCurrency - }; - if (currencyStats) { - const currencyStatsData = this.membersStats.fillDates(currencyStats.data) || {}; - const dateValues = Object.values(currencyStatsData).map(val => Math.round((val / 100))); - const currentMRR = dateValues.length ? dateValues[dateValues.length - 1] : 0; - const rangeStartMRR = dateValues.length ? dateValues[0] : 0; - const percentGrowth = rangeStartMRR !== 0 ? ((currentMRR - rangeStartMRR) / rangeStartMRR) * 100 : 0; - this.mrrStatsData = { - currentAmount: currentMRR, - currency: getSymbol(currencyStats.currency), - percentGrowth: percentGrowth.toFixed(1), - percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')), - options: { - rangeInDays: 30 - }, - data: { - label: 'MRR', - dateLabels: Object.keys(currencyStatsData), - dateValues - }, - title: 'MRR', - stats: currencyStats - }; - } - }, (error) => { - this.mrrStatsError = error; - this.mrrStatsLoading = false; - }); - } - - loadMemberCountStats() { - this.memberCountStatsLoading = true; - this.membersStats.fetchCounts().then((stats) => { - this.memberCountStatsLoading = false; - - if (stats) { - const statsDateObj = this.membersStats.fillCountDates(stats.data) || {}; - const dateValues = Object.values(statsDateObj); - const currentAllCount = dateValues.length ? dateValues[dateValues.length - 1].total : 0; - const currentPaidCount = dateValues.length ? dateValues[dateValues.length - 1].paid : 0; - const currentFreeCount = dateValues.length ? dateValues[dateValues.length - 1].free : 0; - const rangeStartAllCount = dateValues.length ? dateValues[0].total : 0; - const rangeStartPaidCount = dateValues.length ? dateValues[0].paid : 0; - const rangeStartFreeCount = dateValues.length ? dateValues[0].free : 0; - const allCountPercentGrowth = rangeStartAllCount !== 0 ? ((currentAllCount - rangeStartAllCount) / rangeStartAllCount) * 100 : 0; - const paidCountPercentGrowth = rangeStartPaidCount !== 0 ? ((currentPaidCount - rangeStartPaidCount) / rangeStartPaidCount) * 100 : 0; - const freeCountPercentGrowth = rangeStartFreeCount !== 0 ? ((currentFreeCount - rangeStartFreeCount) / rangeStartFreeCount) * 100 : 0; - - this.memberCountStatsData = { - all: { - percentGrowth: allCountPercentGrowth.toFixed(1), - percentClass: (allCountPercentGrowth > 0 ? 'positive' : (allCountPercentGrowth < 0 ? 'negative' : '')), - total: dateValues.length ? dateValues[dateValues.length - 1].total : 0, - options: { - rangeInDays: 30 - }, - data: { - label: 'Members', - dateLabels: Object.keys(statsDateObj), - dateValues: dateValues.map(d => d.total) - }, - title: 'Total Members', - stats: stats - }, - paid: { - percentGrowth: paidCountPercentGrowth.toFixed(1), - percentClass: (paidCountPercentGrowth > 0 ? 'positive' : (paidCountPercentGrowth < 0 ? 'negative' : '')), - total: dateValues.length ? dateValues[dateValues.length - 1].paid : 0, - options: { - rangeInDays: 30 - }, - data: { - label: 'Members', - dateLabels: Object.keys(statsDateObj), - dateValues: dateValues.map(d => d.paid) - }, - title: 'Paid Members', - stats: stats - }, - free: { - percentGrowth: freeCountPercentGrowth.toFixed(1), - percentClass: (freeCountPercentGrowth > 0 ? 'positive' : (freeCountPercentGrowth < 0 ? 'negative' : '')), - total: dateValues.length ? dateValues[dateValues.length - 1].free : 0, - options: { - rangeInDays: 30 - }, - data: { - label: 'Members', - dateLabels: Object.keys(statsDateObj), - dateValues: dateValues.map(d => d.paid) - }, - title: 'Free Members', - stats: stats - } - }; - } - }, (error) => { - this.memberCountStatsError = error; - this.memberCountStatsLoading = false; - }); - } - - loadCharts() { - this.loadMRRStats(); - this.loadMemberCountStats(); - this.loadNewsletterOpenRates(); - } - - loadEvents() { - this.eventsLoading = true; - this.membersStats.fetchTimeline({limit: 5}).then(({events}) => { - this.eventsData = events; - this.eventsLoading = false; - }, (error) => { - this.eventsError = error; - this.eventsLoading = false; - }); - } - - @task - *loadLatestNewsletters() { - this.latestNewsletters = yield this.store.query('email', { - limit: 5, - order: 'created_at desc' - }); - } - - loadNewsletterOpenRates() { - this.newsletterOpenRatesLoading = true; - this.membersStats.fetchNewsletterStats().then((results) => { - const rangeStartOpenRate = results.length > 1 ? results[results.length - 2].openRate : 0; - const rangeEndOpenRate = results.length > 0 ? results[results.length - 1].openRate : 0; - const percentGrowth = rangeStartOpenRate !== 0 ? ((rangeEndOpenRate - rangeStartOpenRate) / rangeStartOpenRate) * 100 : 0; - this.newsletterOpenRatesData = { - percentGrowth: percentGrowth.toFixed(1), - percentClass: (percentGrowth > 0 ? 'positive' : (percentGrowth < 0 ? 'negative' : '')), - current: rangeEndOpenRate, - options: { - rangeInDays: 30 - }, - data: { - label: 'Open rate', - dateLabels: results.map(d => d.subject), - dateValues: results.map(d => d.openRate) - }, - title: 'Open rate', - stats: results - }; - this.newsletterOpenRatesLoading = false; - }, (error) => { - this.newsletterOpenRatesError = error; - this.newsletterOpenRatesLoading = false; - }); - } - - loadTopMembers() { - this.topMembersLoading = true; - let query = { - filter: 'email_open_rate:-null', - order: 'email_open_rate desc', - limit: 5 - }; - this.store.query('member', query).then((result) => { - if (!result.length) { - return this.store.query('member', { - filter: 'status:paid', - order: 'created_at asc', - limit: 5 - }); - } - return result; - }).then((result) => { - this.topMembersData = result; - this.topMembersLoading = false; - }).catch((error) => { - this.topMembersError = error; - this.topMembersLoading = false; - }); - } - - loadWhatsNew() { - this.whatsNewEntriesLoading = true; - this.whatsNew.fetchLatest.perform().then(() => { - this.whatsNewEntriesLoading = false; - this.whatsNewEntries = this.whatsNew.entries.slice(0, 3); - }, (error) => { - this.whatsNewEntriesError = error; - this.whatsNewEntriesLoading = false; - }); - } - - @action - dismissLaunchBanner() { - this.feature.set('launchComplete', true); - } -} diff --git a/ghost/admin/app/router.js b/ghost/admin/app/router.js index 6685cf7cf2..1ac4ff9bf0 100644 --- a/ghost/admin/app/router.js +++ b/ghost/admin/app/router.js @@ -24,7 +24,6 @@ Router.map(function () { this.route('whatsnew'); this.route('site'); this.route('dashboard'); - this.route('dashboard-labs'); this.route('launch'); this.route('pro', function () { diff --git a/ghost/admin/app/routes/dashboard-labs.js b/ghost/admin/app/routes/dashboard-labs.js deleted file mode 100644 index 2421c38b7a..0000000000 --- a/ghost/admin/app/routes/dashboard-labs.js +++ /dev/null @@ -1,28 +0,0 @@ -import AuthenticatedRoute from 'ghost-admin/routes/authenticated'; -import {inject as service} from '@ember/service'; - -export default class DashboardRoute extends AuthenticatedRoute { - @service feature; - - beforeModel() { - super.beforeModel(...arguments); - - if (!this.session.user.isAdmin) { - return this.transitionTo('site'); - } - - if (!this.feature.dashboardTwo) { - return this.transitionTo('dashboard'); - } - } - - buildRouteInfoMetadata() { - return { - mainClasses: ['gh-main-wide'] - }; - } - - setupController() { - this.controller.initialise(); - } -} diff --git a/ghost/admin/app/routes/dashboard.js b/ghost/admin/app/routes/dashboard.js index ce67ab1c87..33291499a7 100644 --- a/ghost/admin/app/routes/dashboard.js +++ b/ghost/admin/app/routes/dashboard.js @@ -10,10 +10,6 @@ export default class DashboardRoute extends AuthenticatedRoute { if (!this.session.user.isAdmin) { return this.transitionTo('site'); } - - if (this.feature.dashboardTwo) { - return this.transitionTo('dashboard-labs'); - } } buildRouteInfoMetadata() { diff --git a/ghost/admin/app/services/feature.js b/ghost/admin/app/services/feature.js index 46dff73e9b..dd2fa391b9 100644 --- a/ghost/admin/app/services/feature.js +++ b/ghost/admin/app/services/feature.js @@ -57,7 +57,6 @@ export default Service.extend({ membersFiltering: feature('membersFiltering', {developer: true}), oauthLogin: feature('oauthLogin', {developer: true}), emailOnlyPosts: feature('emailOnlyPosts', {developer: true}), - dashboardTwo: feature('dashboardTwo', {developer: true}), _user: null, diff --git a/ghost/admin/app/templates/dashboard-labs.hbs b/ghost/admin/app/templates/dashboard-labs.hbs deleted file mode 100644 index f11056623b..0000000000 --- a/ghost/admin/app/templates/dashboard-labs.hbs +++ /dev/null @@ -1,388 +0,0 @@ -
- -

- Dashboard -

-
- -
- - {{#if (and this.session.user.isOwnerOnly (not this.feature.launchComplete))}} -
-
-

Select your publication style

-

Customize your brand and connect to Stripe to get your membership site ready to be shown to the world.

- Start setup guide -
- - - {{svg-jar "dotdotdot"}} - - - - - -
-
-
- {{else if this.showMembersData}} -
-
-
-

MRR

-

30 days

-
-
- {{#if this.mrrStatsLoading}} - Loading... - {{else}} - {{#if this.mrrStatsError}} -

- There was an error loading MRR - {{this.mrrStatsError.message}} -

- {{else}} -
-
{{this.mrrStatsData.currency}}{{format-number this.mrrStatsData.currentAmount}}
-
{{this.mrrStatsData.percentGrowth}}%
-
- {{#if this.mrrStatsData}} -
- -
- {{/if}} - {{/if}} - {{/if}} -
-
-
-
- {{#if this.memberCountStatsLoading}} - Loading... - {{else}} - {{#if this.memberCountStatsError}} -

- There was an error loading total members - {{this.memberCountStatsData.message}} -

- {{else}} -
-

Total members

-
-
{{format-number this.memberCountStatsData.all.total}}
-
{{this.memberCountStatsData.all.percentGrowth}}%
-
-
-
- -
- {{/if}} - {{/if}} -
-
- - -
- {{/if}} - -
-
-
-
-

Latest newsletters

-
-
- {{#if this.loadLatestNewsletters.isRunning}} - Loading... - {{else}} -
    -
  1. -
    Title
    -
    Sends
    -
    Open %
    -
  2. - {{#each this.latestNewsletters as |newsletter|}} -
  3. - {{newsletter.subject}} -
    {{newsletter.emailCount}}
    -
    {{newsletter.openRate}}%
    -
  4. - {{else}} -
  5. No newsletters sent.
  6. - {{/each}} -
- {{/if}} -
- -
-
- - {{#if (not this.feature.launchComplete)}} -
-
-

Start creating content

- {{#if this.showMembersData}} - - {{svg-jar "members"}} -
-

Create your first member

-

Add yourself or import members from CSV

-
-
- {{/if}} - - {{svg-jar "posts"}} -
-

Publish a post

-

Get familiar with the Ghost editor and start creating

-
-
-
-
- {{/if}} - -
-
-
-

Customize your site design

-

Stand out from the crowd. Ghost lets you customize everything so you can create a publication that doesn’t just look the same as what everyone else has.

-
- -
-
-
-

Looking for help with Ghost features?

-

Our product knowledgebase is packed full of guides, tutorials, answers to frequently asked questions, tips for dealing with common errors, and much more.

-
- -
-
- - -
-
-

6 types of newsletters you can start today

-

Choosing one of these newsletter types for your publication will help you create better content at a faster pace with less work.

-

Get some inspiration →

-
5 MIN READ
-
-
-
-
- - -
-
-

We're hiring! Join the team that makes Ghost.

-

The creator economy is growing faster than ever, and so are we! 📈 Join a team that's determined to make decentralised, open technology the heart and soul of new media 🌺

-
-
- See open roles → -
-
-
- - -
-
-
-

How to grow your audience, starting from 0

-

Starting from zero is hard. Thankfully, successful creators have given us clues on how to grow an audience by using something called a content funnel.

-

Here's how it works →

-
9 MIN READ
-
-
-
- -
-
-

Join the Ghost creator community.

-

Meet other people building both free & paid publications with Ghost. Talk strategy, get advice, or just hang out.

- Share the journey -
- community.ghost.org -
-
- -
- {{#if this.showMembersData}} - {{#if this.topMembersData}} -
-
-

Top members

- {{#if this.topMembersDataHasOpenRates}} -

Open rate

- {{else}} -

Member since

- {{/if}} -
-
- {{#if this.topMembersLoading}} - Loading... - {{else}} - {{#if this.topMembersError}} -

- There was an error loading member events. - -

- {{else}} -
    - {{#each this.topMembersData as |member|}} -
  • - - - {{#if member.name}} - {{member.name}} - {{else}} - - {{/if}} - - {{#if member.emailOpenRate}} - {{member.emailOpenRate}}% - {{else}} - - {{moment-format member.createdAtUTC "D MMM YYYY"}} - - {{/if}} -
  • - {{/each}} -
- {{/if}} - {{/if}} - -
-
- {{/if}} - -
-
- {{#if this.newsletterOpenRatesLoading}} - Loading... - {{else}} - {{#if this.newsletterOpenRatesError}} -

- There was an error loading newsletter open rates - {{this.memberCountStatsData.message}} -

- {{else}} -
-

Email open rate

- -
-
{{this.newsletterOpenRatesData.current}}%
-
{{this.newsletterOpenRatesData.percentGrowth}}%
-
-
-
- -
- {{/if}} - {{/if}} -
-
- - {{#unless (and this.session.user.isOwnerOnly (not this.feature.launchComplete))}} -
-

Activity feed

-
- {{#if this.eventsLoading}} - Loading... - {{else}} - {{#if this.eventsError}} -

- There was an error loading events - {{this.eventsError.message}} -

- {{else}} - - {{/if}} - {{/if}} -
-
- {{/unless}} - {{/if}} - - {{#unless (or whatsNewEntriesLoading whatsNewEntriesError)}} -
-
-

What's new?

- {{svg-jar "gift"}} -
- - -
- {{/unless}} -
-
-
\ No newline at end of file diff --git a/ghost/admin/app/templates/settings/labs.hbs b/ghost/admin/app/templates/settings/labs.hbs index b3955db46a..eeffc559d7 100644 --- a/ghost/admin/app/templates/settings/labs.hbs +++ b/ghost/admin/app/templates/settings/labs.hbs @@ -287,19 +287,6 @@ -
-
-
-

Dashboard 2.0

-

- More graphs. Better graphs. Fewer useless graphs. -

-
-
- -
-
-
{{/if}}