diff --git a/app/assets/javascripts/discourse-objects.js b/app/assets/javascripts/discourse-objects.js
new file mode 100644
index 000000000..d55626ef0
--- /dev/null
+++ b/app/assets/javascripts/discourse-objects.js
@@ -0,0 +1,2 @@
+window.Discourse = {};
+Discourse.SiteSettings = {};
diff --git a/app/assets/javascripts/env.js b/app/assets/javascripts/env.js
index 5537a6c10..d5fe88236 100644
--- a/app/assets/javascripts/env.js
+++ b/app/assets/javascripts/env.js
@@ -1,8 +1,3 @@
window.ENV = { };
-
-window.Discourse = {};
-Discourse.SiteSettings = {};
-
window.EmberENV = window.EmberENV || {};
window.EmberENV['FORCE_JQUERY'] = true;
-
diff --git a/app/assets/javascripts/vendor.js b/app/assets/javascripts/vendor.js
index a6a8c8142..22624ed00 100644
--- a/app/assets/javascripts/vendor.js
+++ b/app/assets/javascripts/vendor.js
@@ -1,5 +1,6 @@
//= require logster
//= require ./env
+//= require ./discourse-objects
//= require probes.js
//= require template_include.js
diff --git a/app/assets/javascripts/wizard-application.js b/app/assets/javascripts/wizard-application.js
new file mode 100644
index 000000000..1d77f9dfa
--- /dev/null
+++ b/app/assets/javascripts/wizard-application.js
@@ -0,0 +1,6 @@
+//= require wizard/resolver
+//= require wizard/router
+//= require wizard/wizard
+//= require_tree ./wizard/templates
+//= require_tree ./wizard/routes
+//= require_tree ./wizard/controllers
diff --git a/app/assets/javascripts/wizard-vendor.js b/app/assets/javascripts/wizard-vendor.js
new file mode 100644
index 000000000..cb0647466
--- /dev/null
+++ b/app/assets/javascripts/wizard-vendor.js
@@ -0,0 +1,2 @@
+//= require env
+//= require template_include.js
diff --git a/app/assets/javascripts/wizard/controllers/step.js.es6 b/app/assets/javascripts/wizard/controllers/step.js.es6
new file mode 100644
index 000000000..bc7c7b20b
--- /dev/null
+++ b/app/assets/javascripts/wizard/controllers/step.js.es6
@@ -0,0 +1,3 @@
+export default Ember.Controller.extend({
+ step: null,
+});
diff --git a/app/assets/javascripts/wizard/resolver.js.es6 b/app/assets/javascripts/wizard/resolver.js.es6
new file mode 100644
index 000000000..c89bfa593
--- /dev/null
+++ b/app/assets/javascripts/wizard/resolver.js.es6
@@ -0,0 +1,26 @@
+function resolveType(parsedName) {
+ const entries = requirejs.entries;
+
+ const named = `wizard/${parsedName.type}s/${parsedName.fullNameWithoutType}`;
+ if (entries[named]) {
+ const module = require(named, null, null, true /* force sync */);
+ return module.default;
+ }
+}
+
+export default Ember.DefaultResolver.extend({
+
+ resolveRoute(parsedName) {
+ return resolveType(parsedName) || this._super(parsedName);
+ },
+
+ resolveController(parsedName) {
+ return resolveType(parsedName) || this._super(parsedName);
+ },
+
+ resolveTemplate(parsedName) {
+ const templates = Ember.TEMPLATES;
+ const withoutType = parsedName.fullNameWithoutType;
+ return templates[`wizard/templates/${withoutType}`] || this._super(parsedName);
+ }
+});
diff --git a/app/assets/javascripts/wizard/router.js.es6 b/app/assets/javascripts/wizard/router.js.es6
new file mode 100644
index 000000000..d110766f8
--- /dev/null
+++ b/app/assets/javascripts/wizard/router.js.es6
@@ -0,0 +1,7 @@
+const Router = Ember.Router.extend();
+
+Router.map(function () {
+ this.route('step', { path: '/step/:step_id' });
+});
+
+export default Router;
diff --git a/app/assets/javascripts/wizard/routes/index.js.es6 b/app/assets/javascripts/wizard/routes/index.js.es6
new file mode 100644
index 000000000..2587b35d8
--- /dev/null
+++ b/app/assets/javascripts/wizard/routes/index.js.es6
@@ -0,0 +1,5 @@
+export default Ember.Route.extend({
+ beforeModel() {
+ this.replaceWith('step', 'welcome');
+ }
+});
diff --git a/app/assets/javascripts/wizard/routes/step.js.es6 b/app/assets/javascripts/wizard/routes/step.js.es6
new file mode 100644
index 000000000..4de6d180e
--- /dev/null
+++ b/app/assets/javascripts/wizard/routes/step.js.es6
@@ -0,0 +1,12 @@
+export default Ember.Route.extend({
+ model(params) {
+ return {
+ id: params.step_id,
+ title: "You're a wizard harry!"
+ };
+ },
+
+ setupController(controller, model) {
+ controller.set('step', model);
+ }
+});
diff --git a/app/assets/javascripts/wizard/templates/application.hbs b/app/assets/javascripts/wizard/templates/application.hbs
new file mode 100644
index 000000000..52416fc45
--- /dev/null
+++ b/app/assets/javascripts/wizard/templates/application.hbs
@@ -0,0 +1,7 @@
+
+
+ Discourse!
+
+ {{outlet}}
+
+
diff --git a/app/assets/javascripts/wizard/templates/step.hbs b/app/assets/javascripts/wizard/templates/step.hbs
new file mode 100644
index 000000000..c8e09a81f
--- /dev/null
+++ b/app/assets/javascripts/wizard/templates/step.hbs
@@ -0,0 +1,3 @@
+
+ {{step.title}}
+
diff --git a/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6 b/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6
new file mode 100644
index 000000000..f166e7b24
--- /dev/null
+++ b/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6
@@ -0,0 +1,10 @@
+
+module("Acceptance: wizard");
+
+test("Wizard loads", assert => {
+ visit("/");
+ andThen(() => {
+ assert.ok(exists('.wizard-column-contents'));
+ assert.equal(currentPath(), 'steps');
+ });
+});
diff --git a/app/assets/javascripts/wizard/test/test_helper.js b/app/assets/javascripts/wizard/test/test_helper.js
new file mode 100644
index 000000000..529c5e9b8
--- /dev/null
+++ b/app/assets/javascripts/wizard/test/test_helper.js
@@ -0,0 +1,40 @@
+/*global document, sinon, QUnit, Logster */
+
+//= require env
+//= require jquery.debug
+//= require loader
+//= require jquery.debug
+//= require handlebars
+//= require ember.debug
+//= require ember-template-compiler
+//= require ember-qunit
+//= require wizard-application
+//= require helpers/assertions
+//= require_tree ./acceptance
+
+// Trick JSHint into allow document.write
+var d = document;
+d.write('');
+d.write('');
+
+if (window.Logster) {
+ Logster.enabled = false;
+} else {
+ window.Logster = { enabled: false };
+}
+
+var wizard = require('wizard/wizard').default.create({
+ rootElement: '#ember-testing'
+});
+wizard.setupForTesting();
+wizard.injectTestHelpers();
+
+QUnit.testDone(function() {
+ wizard.reset();
+});
+
+Object.keys(requirejs.entries).forEach(function(entry) {
+ if ((/\-test/).test(entry)) {
+ require(entry, null, null, true);
+ }
+});
diff --git a/app/assets/javascripts/wizard/wizard.js.es6 b/app/assets/javascripts/wizard/wizard.js.es6
new file mode 100644
index 000000000..6318fec2b
--- /dev/null
+++ b/app/assets/javascripts/wizard/wizard.js.es6
@@ -0,0 +1,8 @@
+import Resolver from 'wizard/resolver';
+import Router from 'wizard/router';
+
+export default Ember.Application.extend({
+ rootElement: '#wizard-main',
+ Resolver,
+ Router
+});
diff --git a/app/assets/stylesheets/wizard.scss b/app/assets/stylesheets/wizard.scss
new file mode 100644
index 000000000..228b399f5
--- /dev/null
+++ b/app/assets/stylesheets/wizard.scss
@@ -0,0 +1,31 @@
+@import "vendor/normalize";
+@import "vendor/font_awesome/font-awesome";
+
+body {
+ background-color: rgb(231,238,247);
+ background-image: url('/images/wizard/bubbles.png');
+ background-repeat: repeat;
+ background-position: left top;
+}
+
+.wizard-column {
+ background-color: white;
+ border-radius: 2px;
+ box-shadow: 0 5px 10px rgba(0,0,0,0.2);
+ box-sizing: border-box;
+ margin: 0.75rem auto;
+ padding: 0;
+ max-width: 700px;
+ min-width: 280px;
+ width: 100%;
+ border: 1px solid #ccc;
+
+ .wizard-column-contents {
+ padding: 1em;
+
+ h1 {
+ margin: 0;
+ }
+ }
+}
+
diff --git a/app/controllers/wizard/wizard_controller.rb b/app/controllers/wizard/wizard_controller.rb
new file mode 100644
index 000000000..09e7ae1f9
--- /dev/null
+++ b/app/controllers/wizard/wizard_controller.rb
@@ -0,0 +1,16 @@
+class Wizard::WizardController < ApplicationController
+
+ before_filter :ensure_logged_in
+ before_filter :ensure_staff
+
+ skip_before_filter :check_xhr, :preload_json
+
+ layout false
+
+ def index
+ end
+
+ def qunit
+ end
+
+end
diff --git a/app/views/wizard/wizard/index.html.erb b/app/views/wizard/wizard/index.html.erb
new file mode 100644
index 000000000..249921a4e
--- /dev/null
+++ b/app/views/wizard/wizard/index.html.erb
@@ -0,0 +1,21 @@
+
+
+ <%= stylesheet_link_tag 'wizard' %>
+ <%= javascript_include_tag 'wizard-vendor' %>
+ <%= javascript_include_tag 'ember_jquery' %>
+ <%= javascript_include_tag 'wizard-application' %>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/views/wizard/wizard/qunit.html.erb b/app/views/wizard/wizard/qunit.html.erb
new file mode 100644
index 000000000..814bfb5c9
--- /dev/null
+++ b/app/views/wizard/wizard/qunit.html.erb
@@ -0,0 +1,15 @@
+
+
+
+ QUnit Test Runner
+ <%= stylesheet_link_tag "qunit" %>
+ <%= stylesheet_link_tag "test_helper" %>
+ <%= javascript_include_tag "qunit" %>
+ <%= javascript_include_tag "wizard/test/test_helper" %>
+ <%= csrf_meta_tags %>
+
+
+
+
+
+
diff --git a/config/application.rb b/config/application.rb
index 577d12799..70d4427f7 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -72,7 +72,8 @@ module Discourse
config.assets.precompile += ['vendor.js', 'common.css', 'desktop.css', 'mobile.css',
'admin.js', 'admin.css', 'shiny/shiny.css', 'preload-store.js.es6',
'browser-update.js', 'embed.css', 'break_string.js', 'ember_jquery.js',
- 'pretty-text-bundle.js']
+ 'pretty-text-bundle.js', 'wizard.css', 'wizard-application.js',
+ 'wizard-vendor.js']
# Precompile all available locales
Dir.glob("#{config.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
diff --git a/config/routes.rb b/config/routes.rb
index 131636111..4f516da13 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -53,6 +53,11 @@ Discourse::Application.routes.draw do
resources :forums
get "srv/status" => "forums#status"
+ namespace :wizard, constraints: StaffConstraint.new do
+ get "" => "wizard#index"
+ get "qunit" => "wizard#qunit"
+ end
+
namespace :admin, constraints: StaffConstraint.new do
get "" => "admin#index"
diff --git a/public/images/wizard/bubbles.png b/public/images/wizard/bubbles.png
new file mode 100644
index 000000000..6847ae359
Binary files /dev/null and b/public/images/wizard/bubbles.png differ
diff --git a/spec/controllers/wizard/wizard_controller_spec.rb b/spec/controllers/wizard/wizard_controller_spec.rb
new file mode 100644
index 000000000..d6dcc9a24
--- /dev/null
+++ b/spec/controllers/wizard/wizard_controller_spec.rb
@@ -0,0 +1,25 @@
+require 'rails_helper'
+
+describe Wizard::WizardController do
+
+ context 'index' do
+ render_views
+
+ it 'needs you to be logged in' do
+ expect { xhr :get, :index }.to raise_error(Discourse::NotLoggedIn)
+ end
+
+ it "raises an error if you aren't an admin" do
+ log_in
+ xhr :get, :index
+ expect(response).to be_forbidden
+ end
+
+ it "renders the wizard if you are an admin" do
+ log_in(:admin)
+ xhr :get, :index
+ expect(response).to be_success
+ end
+ end
+
+end