Skip to content

Commit 97c5c34

Browse files
authored
Added redirect from Ember Dashboard to new Analytics page (#24613)
ref https://linear.app/ghost/issue/PROD-2415/add-redirect-for-dashboard-analytics - added redirect from Dashboard -> Analytics This change helps preserve existing user bookmarks by simply pushing them towards the 'new dashboard'.
1 parent 6afe28c commit 97c5c34

File tree

3 files changed

+35
-95
lines changed

3 files changed

+35
-95
lines changed

ghost/admin/app/routes/dashboard.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,7 @@ export default class DashboardRoute extends AuthenticatedRoute {
44
async beforeModel() {
55
super.beforeModel(...arguments);
66

7-
if (this.session.user.isContributor) {
8-
return this.transitionTo('posts');
9-
} else if (!this.session.user.isAdmin) {
10-
return this.transitionTo('site');
11-
}
7+
// Redirect all users to analytics since dashboard has been retired
8+
return this.transitionTo('stats-x');
129
}
13-
14-
buildRouteInfoMetadata() {
15-
return {
16-
mainClasses: ['gh-main-wide']
17-
};
18-
}
19-
20-
// trigger a background load of members plus labels for filter dropdown
21-
setupController() {
22-
super.setupController(...arguments);
23-
}
24-
25-
model() {
26-
return this.controllerFor('dashboard').loadSiteStatusTask.perform();
27-
}
28-
}
10+
}
Lines changed: 11 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-support';
1+
import {authenticateSession} from 'ember-simple-auth/test-support';
2+
import {cleanupMockAnalyticsApps, mockAnalyticsApps} from '../helpers/mock-analytics-apps';
23
import {currentURL} from '@ember/test-helpers';
34
import {describe, it} from 'mocha';
45
import {expect} from 'chai';
@@ -10,71 +11,23 @@ describe('Acceptance: Dashboard', function () {
1011
const hooks = setupApplicationTest();
1112
setupMirage(hooks);
1213

13-
describe('permissions', function () {
14-
beforeEach(async function () {
15-
this.server.db.users.remove();
16-
await invalidateSession();
17-
});
14+
beforeEach(function () {
15+
mockAnalyticsApps();
16+
});
1817

19-
it('is not accessible when logged out', async function () {
20-
await visit('/dashboard');
21-
expect(currentURL()).to.equal('/signin');
22-
});
18+
afterEach(function () {
19+
cleanupMockAnalyticsApps();
20+
});
2321

24-
it('is accessible to owners', async function () {
22+
describe('redirects', function () {
23+
it('redirects to Analytics (stats-x)', async function () {
2524
let role = this.server.create('role', {name: 'Owner'});
2625
this.server.create('user', {roles: [role]});
2726

2827
await authenticateSession();
2928
await visit('/dashboard');
3029

31-
expect(currentURL()).to.equal('/dashboard');
32-
});
33-
34-
it('is not accessible to editors', async function () {
35-
this.server.db.users.remove();
36-
37-
let role = this.server.create('role', {name: 'Editor'});
38-
this.server.create('user', {roles: [role]});
39-
40-
await authenticateSession();
41-
await visit('/dashboard');
42-
43-
expect(currentURL()).to.equal('/site');
44-
});
45-
46-
it('is not accessible to authors', async function () {
47-
let role = this.server.create('role', {name: 'Author'});
48-
this.server.create('user', {roles: [role]});
49-
50-
await authenticateSession();
51-
await visit('/dashboard');
52-
expect(currentURL()).to.equal('/site');
53-
});
54-
55-
it('is not accessible to super editors', async function () {
56-
let role = this.server.create('role', {name: 'Super Editor'});
57-
this.server.create('user', {roles: [role]});
58-
59-
await authenticateSession();
60-
await visit('/dashboard');
61-
62-
expect(currentURL()).to.equal('/site');
63-
});
64-
});
65-
describe('as admin', function () {
66-
beforeEach(async function () {
67-
await invalidateSession();
68-
this.server.db.users.remove();
69-
70-
let role = this.server.create('role', {name: 'Administrator'});
71-
this.server.create('user', {roles: [role]});
72-
await authenticateSession();
73-
});
74-
75-
it('can visit /dashboard', async function () {
76-
await visit('/dashboard');
77-
expect(currentURL()).to.equal('/dashboard');
30+
expect(currentURL()).to.equal('/analytics');
7831
});
7932
});
8033
});

ghost/admin/tests/acceptance/search-test.js

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ctrlOrCmd from 'ghost-admin/utils/ctrl-or-cmd';
22
import {authenticateSession} from 'ember-simple-auth/test-support';
3+
import {cleanupMockAnalyticsApps, mockAnalyticsApps} from '../helpers/mock-analytics-apps';
34
import {click, currentURL, find, findAll, triggerKeyEvent, visit} from '@ember/test-helpers';
45
import {describe, it} from 'mocha';
56
import {expect} from 'chai';
@@ -15,21 +16,25 @@ const suites = [{
1516
name: 'Acceptance: Search (flex)',
1617
beforeEach() {
1718
// noop - default locale is 'en'
19+
mockAnalyticsApps();
1820
},
1921
confirmProvider() {
2022
const searchService = this.owner.lookup('service:search');
2123
expect(searchService.provider.constructor.name, 'provider name').to.equal('SearchProviderFlexService');
24+
cleanupMockAnalyticsApps();
2225
}
2326
}, {
2427
name: 'Acceptance: Search (basic)',
2528
beforeEach() {
2629
this.server.db.settings.update({key: 'locale'}, {value: 'de'});
30+
mockAnalyticsApps();
2731
},
2832
confirmProvider() {
2933
const settingsService = this.owner.lookup('service:settings');
3034
expect(settingsService.locale, 'settings.locale').to.equal('de');
3135
const searchService = this.owner.lookup('service:search');
3236
expect(searchService.provider.constructor.name, 'provider name').to.equal('SearchProviderBasicService');
37+
cleanupMockAnalyticsApps();
3338
}
3439
}];
3540

@@ -61,20 +66,20 @@ suites.forEach((suite) => {
6166
});
6267

6368
it('is using correct provider', async function () {
64-
await visit('/dashboard');
69+
await visit('/analytics');
6570
suite.confirmProvider.bind(this)();
6671
});
6772

6873
it('opens search modal when clicking icon', async function () {
69-
await visit('/dashboard');
70-
expect(currentURL(), 'currentURL').to.equal('/dashboard');
74+
await visit('/analytics');
75+
expect(currentURL(), 'currentURL').to.equal('/analytics');
7176
expect(find('[data-test-modal="search"]'), 'search modal').to.not.exist;
7277
await click('[data-test-button="search"]');
7378
expect(find('[data-test-modal="search"]'), 'search modal').to.exist;
7479
});
7580

7681
it('opens search icon when pressing Ctrl/Cmd+K', async function () {
77-
await visit('/dashboard');
82+
await visit('/analytics');
7883
expect(find('[data-test-modal="search"]'), 'search modal').to.not.exist;
7984
await triggerKeyEvent(document, 'keydown', 'K', {
8085
metaKey: ctrlOrCmd === 'command',
@@ -84,23 +89,23 @@ suites.forEach((suite) => {
8489
});
8590

8691
it('closes search modal on escape key', async function () {
87-
await visit('/dashboard');
92+
await visit('/analytics');
8893
await click('[data-test-button="search"]');
8994
expect(find('[data-test-modal="search"]'), 'search modal').to.exist;
9095
await triggerKeyEvent(document, 'keydown', 'Escape');
9196
expect(find('[data-test-modal="search"]'), 'search modal').to.not.exist;
9297
});
9398

9499
it('closes search modal on click outside', async function () {
95-
await visit('/dashboard');
100+
await visit('/analytics');
96101
await click('[data-test-button="search"]');
97102
expect(find('[data-test-modal="search"]'), 'search modal').to.exist;
98103
await click('.epm-backdrop');
99104
expect(find('[data-test-modal="search"]'), 'search modal').to.not.exist;
100105
});
101106

102107
it('finds posts, pages, staff, and tags when typing', async function () {
103-
await visit('/dashboard');
108+
await visit('/analytics');
104109
await click('[data-test-button="search"]');
105110
await typeInSearch('first'); // search is not case sensitive
106111

@@ -119,7 +124,7 @@ suites.forEach((suite) => {
119124
});
120125

121126
it('up/down arrows move selected item', async function () {
122-
await visit('/dashboard');
127+
await visit('/analytics');
123128
await click('[data-test-button="search"]');
124129
await typeInSearch('first post');
125130
expect(findAll('.ember-power-select-option')[0], 'first option (initial)').to.have.attribute('aria-current', 'true');
@@ -130,23 +135,23 @@ suites.forEach((suite) => {
130135
});
131136

132137
it('navigates to editor when post selected (Enter)', async function () {
133-
await visit('/dashboard');
138+
await visit('/analytics');
134139
await click('[data-test-button="search"]');
135140
await typeInSearch('first post');
136141
await triggerKeyEvent(trigger, 'keydown', 'Enter');
137142
expect(currentURL(), 'url after selecting post').to.equal(`/editor/post/${firstPost.id}`);
138143
});
139144

140145
it('navigates to editor when post selected (Clicked)', async function () {
141-
await visit('/dashboard');
146+
await visit('/analytics');
142147
await click('[data-test-button="search"]');
143148
await typeInSearch('first post');
144149
await click('.ember-power-select-option[aria-current="true"]');
145150
expect(currentURL(), 'url after selecting post').to.equal(`/editor/post/${firstPost.id}`);
146151
});
147152

148153
it('navigates to editor when highlighted text is clicked', async function () {
149-
await visit('/dashboard');
154+
await visit('/analytics');
150155
await click('[data-test-button="search"]');
151156
await typeInSearch('first post');
152157

@@ -159,15 +164,15 @@ suites.forEach((suite) => {
159164
});
160165

161166
it('navigates to editor when page selected', async function () {
162-
await visit('/dashboard');
167+
await visit('/analytics');
163168
await click('[data-test-button="search"]');
164169
await typeInSearch('page');
165170
await triggerKeyEvent(trigger, 'keydown', 'Enter');
166171
expect(currentURL(), 'url after selecting page').to.equal(`/editor/page/${firstPage.id}`);
167172
});
168173

169174
it('navigates to tag edit screen when tag selected', async function () {
170-
await visit('/dashboard');
175+
await visit('/analytics');
171176
await click('[data-test-button="search"]');
172177
await typeInSearch('tag');
173178
await triggerKeyEvent(trigger, 'keydown', 'Enter');
@@ -176,15 +181,15 @@ suites.forEach((suite) => {
176181

177182
// TODO: Staff settings are now part of AdminX so this isn't working, can we test AdminX from Ember tests?
178183
it.skip('navigates to user edit screen when user selected', async function () {
179-
await visit('/dashboard');
184+
await visit('/analytics');
180185
await click('[data-test-button="search"]');
181186
await typeInSearch('user');
182187
await triggerKeyEvent(trigger, 'keydown', 'Enter');
183188
expect(currentURL(), 'url after selecting user').to.equal(`/settings/staff/${firstUser.slug}`);
184189
});
185190

186191
it('shows no results message when no results', async function () {
187-
await visit('/dashboard');
192+
await visit('/analytics');
188193
await click('[data-test-button="search"]');
189194
await typeInSearch('x');
190195
expect(find('.ember-power-select-option--no-matches-message'), 'no results message').to.contain.text('No results found');
@@ -194,7 +199,7 @@ suites.forEach((suite) => {
194199
it('handles refresh on first search being slow', async function () {
195200
this.server.get('/posts/', getPosts, {timing: 200});
196201

197-
await visit('/dashboard');
202+
await visit('/analytics');
198203
await click('[data-test-button="search"]');
199204
await typeInSearch('first'); // search is not case sensitive
200205

0 commit comments

Comments
 (0)