mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Improved anchor chart and reloading of charts
refs https://github.com/TryGhost/Team/issues/1510 - Fixes site status not loading (https://github.com/TryGhost/Team/issues/1510) for mocked data because of tasks were already pending (reloadAll now cancels them first) - Reload no longer required when switching anchor chart type - Removed paidOptionSelected (fixes bug when swiching) - Moved did-insert of anchor chart to topmost element - Renamed chartDisplay values
This commit is contained in:
parent
2072209d4d
commit
960536dcda
4 changed files with 61 additions and 50 deletions
|
@ -1,4 +1,4 @@
|
|||
<section class="gh-dashboard5-section gh-dashboard5-anchor">
|
||||
<section class="gh-dashboard5-section gh-dashboard5-anchor" {{did-insert this.loadCharts}}>
|
||||
<article class="gh-dashboard5-box">
|
||||
<div class="gh-dashboard5-hero {{unless this.hasPaidTiers 'is-solo'}}">
|
||||
{{#unless this.hasPaidTiers}}
|
||||
|
@ -15,17 +15,25 @@
|
|||
<div class="gh-dashboard5-chart-loading" style={{html-safe (concat "height: " this.chartHeight "px;")}}/>
|
||||
{{else}}
|
||||
<div class="gh-dashboard5-chart-container">
|
||||
<EmberChart
|
||||
@type={{this.chartType}}
|
||||
@data={{this.chartData}}
|
||||
@options={{this.chartOptions}}
|
||||
@height={{if this.hasPaidTiers this.chartHeight this.chartHeightSmall}} />
|
||||
{{#if (eq this.chartType 'bar')}}
|
||||
<EmberChart
|
||||
@type="bar"
|
||||
@data={{this.chartData}}
|
||||
@options={{this.chartOptions}}
|
||||
@height={{if this.hasPaidTiers this.chartHeight this.chartHeightSmall}} />
|
||||
{{else}}
|
||||
<EmberChart
|
||||
@type="line"
|
||||
@data={{this.chartData}}
|
||||
@options={{this.chartOptions}}
|
||||
@height={{if this.hasPaidTiers this.chartHeight this.chartHeightSmall}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if this.hasPaidTiers}}
|
||||
<div class="gh-dashboard5-stats{{unless this.hasPaidTiers ' is-solo'}}" {{did-insert this.loadCharts}}>
|
||||
<div class="gh-dashboard5-stats{{unless this.hasPaidTiers ' is-solo'}}">
|
||||
<button class="gh-dashboard5-stats-button {{if this.chartShowingTotal 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "total")}}>
|
||||
<Dashboard::v5::Parts::Metric
|
||||
@label={{gh-pluralize this.totalMembers "Total member" without-count=true}}
|
||||
|
@ -34,7 +42,7 @@
|
|||
@percentage={{this.totalMembersTrend}}
|
||||
@large={{true}} />
|
||||
</button>
|
||||
<button class="gh-dashboard5-stats-button {{if this.chartShowingPaid 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "paid")}}>
|
||||
<button class="gh-dashboard5-stats-button {{if this.chartShowingPaid 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "paid-total")}}>
|
||||
<Dashboard::v5::Parts::Metric
|
||||
@label={{gh-pluralize this.paidMembers "Total paid member" without-count=true}}
|
||||
@value={{format-number this.paidMembers}}
|
||||
|
@ -42,7 +50,7 @@
|
|||
@percentage={{this.paidMembersTrend}}
|
||||
@large={{true}} />
|
||||
</button>
|
||||
<button class="gh-dashboard5-stats-button {{if this.chartShowingMonthly 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "monthly")}}>
|
||||
<button class="gh-dashboard5-stats-button {{if this.chartShowingMrr 'is-selected'}}" type="button" {{on "click" (fn this.changeChartDisplay "mrr")}}>
|
||||
<Dashboard::v5::Parts::Metric
|
||||
@label="MRR"
|
||||
@value="${{gh-price-amount this.currentMRR}}"
|
||||
|
|
|
@ -22,17 +22,16 @@ const DAYS_OPTIONS = [{
|
|||
|
||||
const PAID_OPTIONS = [{
|
||||
name: 'Total Paid Members',
|
||||
value: 'paid'
|
||||
value: 'paid-total'
|
||||
}, {
|
||||
name: 'Paid Members By Day',
|
||||
value: 'breakdown'
|
||||
value: 'paid-breakdown'
|
||||
}];
|
||||
|
||||
export default class Anchor extends Component {
|
||||
@service dashboardStats;
|
||||
@service feature;
|
||||
@tracked chartDisplay = 'total';
|
||||
@tracked paidOptionSelected = 'paid';
|
||||
|
||||
daysOptions = DAYS_OPTIONS;
|
||||
paidOptions = PAID_OPTIONS;
|
||||
|
@ -59,13 +58,15 @@ export default class Anchor extends Component {
|
|||
@action
|
||||
changeChartDisplay(type) {
|
||||
this.chartDisplay = type;
|
||||
this.loadCharts();
|
||||
}
|
||||
|
||||
@action
|
||||
onPaidChange(selected) {
|
||||
this.paidOptionSelected = selected.value;
|
||||
this.changeChartDisplay(selected.value);
|
||||
|
||||
// The graph won't switch correctly from line -> bar
|
||||
// So we need to recreate it somehow.
|
||||
// Solution: recreate the DOM by using an #if in hbs
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -78,7 +79,7 @@ export default class Anchor extends Component {
|
|||
}
|
||||
|
||||
get selectedPaidOption() {
|
||||
return this.paidOptions.find(d => d.value === this.paidOptionSelected);
|
||||
return this.paidOptions.find(d => d.value === this.chartDisplay) ?? this.paidOptions[0];
|
||||
}
|
||||
|
||||
get chartShowingTotal() {
|
||||
|
@ -86,25 +87,21 @@ export default class Anchor extends Component {
|
|||
}
|
||||
|
||||
get chartShowingPaid() {
|
||||
return (this.chartDisplay === 'paid' || this.chartDisplay === 'breakdown');
|
||||
return (this.chartDisplay === 'paid-total' || this.chartDisplay === 'paid-breakdown');
|
||||
}
|
||||
|
||||
get chartShowingBreakdown() {
|
||||
return (this.chartDisplay === 'breakdown');
|
||||
}
|
||||
|
||||
get chartShowingMonthly() {
|
||||
return (this.chartDisplay === 'monthly');
|
||||
get chartShowingMrr() {
|
||||
return (this.chartDisplay === 'mrr');
|
||||
}
|
||||
|
||||
get loading() {
|
||||
if (this.chartDisplay === 'total') {
|
||||
return this.dashboardStats.memberCountStats === null;
|
||||
} else if (this.chartDisplay === 'paid') {
|
||||
} else if (this.chartDisplay === 'paid-total') {
|
||||
return this.dashboardStats.memberCountStats === null;
|
||||
} else if (this.chartDisplay === 'breakdown') {
|
||||
} else if (this.chartDisplay === 'paid-breakdown') {
|
||||
return this.dashboardStats.memberCountStats === null;
|
||||
} else if (this.chartDisplay === 'monthly') {
|
||||
} else if (this.chartDisplay === 'mrr') {
|
||||
return this.dashboardStats.mrrStats === null;
|
||||
}
|
||||
return true;
|
||||
|
@ -118,10 +115,6 @@ export default class Anchor extends Component {
|
|||
return this.dashboardStats.memberCounts?.paid ?? 0;
|
||||
}
|
||||
|
||||
get paidBreakdown() {
|
||||
return this.dashboardStats.memberCounts?.breakdown ?? 0;
|
||||
}
|
||||
|
||||
get freeMembers() {
|
||||
return this.dashboardStats.memberCounts?.free ?? 0;
|
||||
}
|
||||
|
@ -131,7 +124,10 @@ export default class Anchor extends Component {
|
|||
}
|
||||
|
||||
get hasTrends() {
|
||||
return this.dashboardStats.memberCounts !== null && this.dashboardStats.memberCountsTrend !== null;
|
||||
return this.dashboardStats.memberCounts !== null
|
||||
&& this.dashboardStats.memberCountsTrend !== null
|
||||
&& this.dashboardStats.currentMRR !== null
|
||||
&& this.dashboardStats.currentMRRTrend !== null;
|
||||
}
|
||||
|
||||
get totalMembersTrend() {
|
||||
|
@ -142,10 +138,6 @@ export default class Anchor extends Component {
|
|||
return this.calculatePercentage(this.dashboardStats.memberCountsTrend.paid, this.dashboardStats.memberCounts.paid);
|
||||
}
|
||||
|
||||
get paidBreakdownTrend() {
|
||||
return '40%';
|
||||
}
|
||||
|
||||
get freeMembersTrend() {
|
||||
return this.calculatePercentage(this.dashboardStats.memberCountsTrend.free, this.dashboardStats.memberCounts.free);
|
||||
}
|
||||
|
@ -159,7 +151,7 @@ export default class Anchor extends Component {
|
|||
}
|
||||
|
||||
get chartType() {
|
||||
if (this.chartDisplay === 'breakdown') {
|
||||
if (this.chartDisplay === 'paid-breakdown') {
|
||||
return 'bar';
|
||||
}
|
||||
|
||||
|
@ -173,7 +165,7 @@ export default class Anchor extends Component {
|
|||
let newData;
|
||||
let canceledData;
|
||||
|
||||
if (this.chartDisplay === 'breakdown') {
|
||||
if (this.chartDisplay === 'paid-breakdown') {
|
||||
stats = this.dashboardStats.filledMemberCountStats;
|
||||
labels = stats.map(stat => stat.date);
|
||||
newData = stats.map(stat => stat.paidSubscribed);
|
||||
|
@ -204,13 +196,13 @@ export default class Anchor extends Component {
|
|||
data = stats.map(stat => stat.paid + stat.free + stat.comped);
|
||||
}
|
||||
|
||||
if (this.chartDisplay === 'paid') {
|
||||
if (this.chartDisplay === 'paid-total') {
|
||||
stats = this.dashboardStats.filledMemberCountStats;
|
||||
labels = stats.map(stat => stat.date);
|
||||
data = stats.map(stat => stat.paid);
|
||||
}
|
||||
|
||||
if (this.chartDisplay === 'monthly') {
|
||||
if (this.chartDisplay === 'mrr') {
|
||||
stats = this.dashboardStats.filledMrrStats;
|
||||
labels = stats.map(stat => stat.date);
|
||||
data = stats.map(stat => stat.mrr);
|
||||
|
@ -249,7 +241,7 @@ export default class Anchor extends Component {
|
|||
maxNumberOfTicks = 20;
|
||||
}
|
||||
|
||||
if (this.chartDisplay === 'breakdown') {
|
||||
if (this.chartDisplay === 'paid-breakdown') {
|
||||
return {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
|
@ -386,10 +378,10 @@ export default class Anchor extends Component {
|
|||
if (this.chartDisplay === 'total') {
|
||||
return `Total members: ${valueText}`;
|
||||
}
|
||||
if (this.chartDisplay === 'paid') {
|
||||
if (this.chartDisplay === 'paid-total') {
|
||||
return `Paid members: ${valueText}`;
|
||||
}
|
||||
if (this.chartDisplay === 'monthly') {
|
||||
if (this.chartDisplay === 'mrr') {
|
||||
return `Monthly revenue (MRR): ${valueText}`;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -86,7 +86,6 @@ export default class ControlPanel extends Component {
|
|||
const parsed = JSON.parse(savedStatus);
|
||||
if (parsed) {
|
||||
this.dashboardMocks.siteStatus = {...this.dashboardMocks.siteStatus, ...parsed};
|
||||
//this.dashboardStats.loadSiteStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,18 +117,16 @@ export default class ControlPanel extends Component {
|
|||
this.dashboardMocks.updateMockedData(this.state);
|
||||
}
|
||||
|
||||
updateState() {
|
||||
this.dashboardStats.reloadAll();
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
// Convenience mappers
|
||||
get enabled() {
|
||||
return this.dashboardMocks.enabled;
|
||||
}
|
||||
|
||||
updateState() {
|
||||
this.dashboardStats.siteStatus = null;
|
||||
this.dashboardStats.loadSiteStatus();
|
||||
this.dashboardStats.reloadAll();
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
set enabled(val) {
|
||||
this.dashboardMocks.enabled = val;
|
||||
this.updateState();
|
||||
|
|
|
@ -591,7 +591,21 @@ export default class DashboardStatsService extends Service {
|
|||
* For now this is only used when reloading all the graphs after changing the mocked data
|
||||
* @todo: reload only data that we loaded earlier
|
||||
*/
|
||||
reloadAll() {
|
||||
async reloadAll() {
|
||||
// Clear all pending tasks (if any)
|
||||
// Promise.all doesn't work here because they sometimes return undefined
|
||||
await this._loadSiteStatus.cancelAll();
|
||||
await this._loadMrrStats.cancelAll();
|
||||
await this._loadMemberCountStats.cancelAll();
|
||||
await this._loadLastSeen.cancelAll();
|
||||
await this._loadPaidMembersByCadence.cancelAll();
|
||||
await this._loadNewsletterSubscribers.cancelAll();
|
||||
await this._loadEmailsSent.cancelAll();
|
||||
await this._loadEmailOpenRateStats.cancelAll();
|
||||
|
||||
// Restart tasks
|
||||
this.loadSiteStatus();
|
||||
|
||||
this.loadMrrStats();
|
||||
this.loadMemberCountStats();
|
||||
this.loadLastSeen();
|
||||
|
|
Loading…
Add table
Reference in a new issue