mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
Added outline launch wizard framework
refs https://github.com/TryGhost/Team/issues/450 - adds `launch/*` routes corresponding to launch wizard steps - sets up navigation between each wizard step - adds components for each `launch/*` step to contain step-related functionality and facilitate later refactoring to a generalised wizard component - adds link to the launch wizard from the dashboard screen
This commit is contained in:
parent
beac5543ce
commit
d48abaa1f8
@ -0,0 +1 @@
|
||||
<h2>Connect Stripe</h2>
|
@ -0,0 +1,4 @@
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
export default class GhLaunchWizardConnectStripeComponent extends Component {
|
||||
}
|
@ -0,0 +1 @@
|
||||
<h2>Customise design</h2>
|
@ -0,0 +1,4 @@
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
export default class GhLaunchWizardCustomiseDesignComponent extends Component {
|
||||
}
|
@ -0,0 +1 @@
|
||||
<h2>Set pricing</h2>
|
@ -0,0 +1,4 @@
|
||||
import Component from '@glimmer/component';
|
||||
|
||||
export default class GhLaunchWizardSetPricingComponent extends Component {
|
||||
}
|
12
ghost/admin/app/controllers/launch.js
Normal file
12
ghost/admin/app/controllers/launch.js
Normal file
@ -0,0 +1,12 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
close() {
|
||||
this.router.transitionTo('dashboard');
|
||||
}
|
||||
}
|
17
ghost/admin/app/controllers/launch/complete.js
Normal file
17
ghost/admin/app/controllers/launch/complete.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchCompleteController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
next() {
|
||||
this.router.transitionTo('dashboard');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.set-pricing');
|
||||
}
|
||||
}
|
17
ghost/admin/app/controllers/launch/connect-stripe.js
Normal file
17
ghost/admin/app/controllers/launch/connect-stripe.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchConnectStripeController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
next() {
|
||||
this.router.transitionTo('launch.set-pricing');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.customise-design');
|
||||
}
|
||||
}
|
12
ghost/admin/app/controllers/launch/customise-design.js
Normal file
12
ghost/admin/app/controllers/launch/customise-design.js
Normal file
@ -0,0 +1,12 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchCustomiseDesignController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
next() {
|
||||
this.router.transitionTo('launch.connect-stripe');
|
||||
}
|
||||
}
|
17
ghost/admin/app/controllers/launch/set-pricing.js
Normal file
17
ghost/admin/app/controllers/launch/set-pricing.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Controller from '@ember/controller';
|
||||
import {action} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchSetPricingController extends Controller {
|
||||
@service router;
|
||||
|
||||
@action
|
||||
next() {
|
||||
this.router.transitionTo('launch.complete');
|
||||
}
|
||||
|
||||
@action
|
||||
goBack() {
|
||||
this.router.transitionTo('launch.connect-stripe');
|
||||
}
|
||||
}
|
@ -21,6 +21,13 @@ Router.map(function () {
|
||||
this.route('signup', {path: '/signup/:token'});
|
||||
this.route('reset', {path: '/reset/:token'});
|
||||
|
||||
this.route('launch', function () {
|
||||
this.route('customise-design');
|
||||
this.route('connect-stripe');
|
||||
this.route('set-pricing');
|
||||
this.route('complete');
|
||||
});
|
||||
|
||||
this.route('about');
|
||||
this.route('site');
|
||||
this.route('dashboard');
|
||||
|
12
ghost/admin/app/routes/launch.js
Normal file
12
ghost/admin/app/routes/launch.js
Normal file
@ -0,0 +1,12 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default class LaunchRoute extends AuthenticatedRoute {
|
||||
@service config;
|
||||
|
||||
beforeModel() {
|
||||
if (!this.config.get('enableDeveloperExperiments')) {
|
||||
this.transitionTo('site');
|
||||
}
|
||||
}
|
||||
}
|
4
ghost/admin/app/routes/launch/complete.js
Normal file
4
ghost/admin/app/routes/launch/complete.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchCompleteRoute extends Route {
|
||||
}
|
4
ghost/admin/app/routes/launch/connect-stripe.js
Normal file
4
ghost/admin/app/routes/launch/connect-stripe.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchConnectStripeRoute extends Route {
|
||||
}
|
4
ghost/admin/app/routes/launch/customise-design.js
Normal file
4
ghost/admin/app/routes/launch/customise-design.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchCustomiseDesignRoute extends Route {
|
||||
}
|
7
ghost/admin/app/routes/launch/index.js
Normal file
7
ghost/admin/app/routes/launch/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
|
||||
|
||||
export default class LaunchIndexRoute extends AuthenticatedRoute {
|
||||
beforeModel() {
|
||||
this.transitionTo('launch.customise-design');
|
||||
}
|
||||
}
|
4
ghost/admin/app/routes/launch/set-pricing.js
Normal file
4
ghost/admin/app/routes/launch/set-pricing.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Route from '@ember/routing/route';
|
||||
|
||||
export default class LaunchSetPricingRoute extends Route {
|
||||
}
|
@ -62,6 +62,7 @@
|
||||
@import "layouts/preview-email.css";
|
||||
@import "layouts/portal-settings.css";
|
||||
@import "layouts/billing.css";
|
||||
@import "layouts/fullscreen-wizard.css";
|
||||
|
||||
|
||||
:root {
|
||||
|
@ -62,6 +62,7 @@
|
||||
@import "layouts/preview-email.css";
|
||||
@import "layouts/portal-settings.css";
|
||||
@import "layouts/billing.css";
|
||||
@import "layouts/fullscreen-wizard.css";
|
||||
|
||||
|
||||
/* ---------------------------✈️----------------------------- */
|
||||
|
11
ghost/admin/app/styles/layouts/fullscreen-wizard.css
Normal file
11
ghost/admin/app/styles/layouts/fullscreen-wizard.css
Normal file
@ -0,0 +1,11 @@
|
||||
.fullscreen-wizard-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
height: 100vh;
|
||||
background: white;
|
||||
overflow: auto;
|
||||
}
|
@ -6,6 +6,6 @@
|
||||
</GhCanvasHeader>
|
||||
|
||||
<section class="view-container">
|
||||
|
||||
<LinkTo @route="launch">Launch site - Finish setup</LinkTo>
|
||||
</section>
|
||||
</section>
|
8
ghost/admin/app/templates/launch.hbs
Normal file
8
ghost/admin/app/templates/launch.hbs
Normal file
@ -0,0 +1,8 @@
|
||||
<div class="fullscreen-wizard-container">
|
||||
<button type="button" class="close absolute top-6 right-6 w6" title="Close" {{on "click" this.close}} data-test-button="close-wizard">
|
||||
{{svg-jar "close"}}
|
||||
<span class="hidden">Close</span>
|
||||
</button>
|
||||
|
||||
{{outlet}}
|
||||
</div>
|
9
ghost/admin/app/templates/launch/complete.hbs
Normal file
9
ghost/admin/app/templates/launch/complete.hbs
Normal file
@ -0,0 +1,9 @@
|
||||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<h2>Congrats</h2>
|
||||
<button type="button" {{on "click" this.next}} data-test-button="wizard-next">Start publishing</button>
|
||||
</section>
|
9
ghost/admin/app/templates/launch/connect-stripe.hbs
Normal file
9
ghost/admin/app/templates/launch/connect-stripe.hbs
Normal file
@ -0,0 +1,9 @@
|
||||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<GhLaunchWizard::ConnectStripe />
|
||||
<button type="button" {{on "click" this.next}} data-test-button="wizard-next">Next</button>
|
||||
</section>
|
4
ghost/admin/app/templates/launch/customise-design.hbs
Normal file
4
ghost/admin/app/templates/launch/customise-design.hbs
Normal file
@ -0,0 +1,4 @@
|
||||
<section class="ma19">
|
||||
<GhLaunchWizard::CustomiseDesign />
|
||||
<button type="button" {{on "click" this.next}} data-test-button="wizard-next">Next</button>
|
||||
</section>
|
9
ghost/admin/app/templates/launch/set-pricing.hbs
Normal file
9
ghost/admin/app/templates/launch/set-pricing.hbs
Normal file
@ -0,0 +1,9 @@
|
||||
<button type="button" class="absolute top-6 left-6 w6" title="Previous step" {{on "click" this.goBack}} data-test-button="wizard-back">
|
||||
{{svg-jar "arrow-left"}}
|
||||
<span class="hidden">Go to previous step</span>
|
||||
</button>
|
||||
|
||||
<section class="ma19">
|
||||
<GhLaunchWizard::SetPricing />
|
||||
<button type="button" {{on "click" this.next}} data-test-button="wizard-next">Finish & launch my site</button>
|
||||
</section>
|
104
ghost/admin/tests/acceptance/launch-flow-test.js
Normal file
104
ghost/admin/tests/acceptance/launch-flow-test.js
Normal file
@ -0,0 +1,104 @@
|
||||
import {authenticateSession} from 'ember-simple-auth/test-support';
|
||||
import {currentURL, visit} from '@ember/test-helpers';
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {setupApplicationTest} from 'ember-mocha';
|
||||
import {setupMirage} from 'ember-cli-mirage/test-support';
|
||||
|
||||
describe('Acceptance: Launch flow', function () {
|
||||
const hooks = setupApplicationTest();
|
||||
setupMirage(hooks);
|
||||
|
||||
it('is not accessible when logged out', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/signin');
|
||||
});
|
||||
|
||||
describe('when logged in', function () {
|
||||
beforeEach(async function () {
|
||||
// TODO: remove this setup when out of dev experiments
|
||||
this.server.loadFixtures('configs');
|
||||
const config = this.server.schema.configs.first();
|
||||
config.update({
|
||||
enableDeveloperExperiments: true
|
||||
});
|
||||
|
||||
let role = this.server.create('role', {name: 'Administrator'});
|
||||
this.server.create('user', {roles: [role]});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('can visit /launch', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/launch/customise-design');
|
||||
});
|
||||
|
||||
it('can visit /launch/customise-design', async function () {
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/launch/customise-design');
|
||||
});
|
||||
|
||||
it('can visit /launch/connect-stripe', async function () {
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/launch/connect-stripe');
|
||||
});
|
||||
|
||||
it('can visit /launch/set-pricing', async function () {
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/launch/set-pricing');
|
||||
});
|
||||
|
||||
it('can visit /launch/complete', async function () {
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/launch/complete');
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: remove this whole section when out of dev experiments
|
||||
describe('developer experiments', function () {
|
||||
describe('when disabled', function () {
|
||||
beforeEach(async function () {
|
||||
this.server.loadFixtures('configs');
|
||||
const config = this.server.schema.configs.first();
|
||||
config.update({
|
||||
enableDeveloperExperiments: false
|
||||
});
|
||||
|
||||
let role = this.server.create('role', {name: 'Administrator'});
|
||||
this.server.create('user', {roles: [role]});
|
||||
|
||||
return await authenticateSession();
|
||||
});
|
||||
|
||||
it('redirects all routes to /site', async function () {
|
||||
await visit('/launch');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/customise-design');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/connect-stripe');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/set-pricing');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
|
||||
await visit('/launch/complete');
|
||||
expect(currentURL()).to.equal('/site');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/connect-stripe', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::ConnectStripe />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.equal('Connect Stripe');
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/customise-design', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::CustomiseDesign />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.equal('Customise design');
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {hbs} from 'ember-cli-htmlbars';
|
||||
import {render} from '@ember/test-helpers';
|
||||
import {setupRenderingTest} from 'ember-mocha';
|
||||
|
||||
describe('Integration: Component: gh-launch-wizard/set-pricing', function () {
|
||||
setupRenderingTest();
|
||||
|
||||
it('renders', async function () {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<GhLaunchWizard::SetPricing />`);
|
||||
|
||||
expect(this.element.textContent.trim()).to.equal('Set pricing');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user