website: use new step oriented system for interactive demo

This commit is contained in:
Jack Pearkes 2015-04-22 15:09:12 -07:00
parent 89dd4041b1
commit be2cfc8503
16 changed files with 319 additions and 190 deletions

View file

@ -0,0 +1,28 @@
<script type="text/x-handlebars" data-template-name="welcome">
<p>
<strong>Welcome to the Vault interactive demo!</strong>
</p>
<p>
This will cover:
</p>
<ul>
<li>- Unsealing your Vault</li>
<li>- Authorizing your requests</li>
<li>- Mounting a backend</li>
<li>- Reading, writing and deleting secrets</li>
<li>- Sealing your vault</li>
</ul>
<p>
Upon opening this terminal, a real in-memory Vault server was
initialized remotely. Any commands you send across will work, but closing this page
will end the session.
</p>
<p>
Please note that this is running in a shared
environment, so avoid setting any real secrets.
</p>
<p>
<strong>Type "next" to move foward</strong>. This will work throughout
the tutorial.
</p>
</script>

View file

@ -1,25 +1,21 @@
<!-- TODO Precompile ember templates -->
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="demo">
<div class="terminal">
<span class="close-terminal" {{action "close"}}>X</span>
{{outlet}}
{{#if isLoading}}
<div class="loading-bar"></div>
{{/if}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="demo/crud">
<script type="text/x-handlebars" data-template-name="demo/step">
{{#if notCleared}}
<div class="welcome">
Any Vault command you run passes through remotely to
the real Vault interface, so feel free to explore, but
be careful of the values you set.
<div class="instruction">
{{partial model.instructionTemplate}}
</div>
{{/if}}

View file

@ -3,6 +3,7 @@
//= require jquery.waypoints.min
//= require lib/ember-template-compiler
//= require lib/ember-1-10.min
//= require lib/ember-data-1-0.min
//= require lib/String.substitute
//= require lib/Function.prototype.bind

View file

@ -1,21 +1,25 @@
Demo.DemoRoute = Ember.Route.extend({
activate: function() {
Demo.ApplicationController = Ember.ObjectController.extend({
init: function() {
this._super.apply(this, arguments);
// connect to the websocket once we enter the application route
// var socket = window.io.connect('http://localhost:8080');
var socket = new WebSocket("ws://vault-demo-server.herokuapp.com/socket");
this.controllerFor('application').set('socket', socket);
this.set('socket', socket);
socket.onmessage = function(message) {
var data = JSON.parse(message.data),
controller = this.controllerFor('demo');
// Add the item
if (data.stdout) {
if (data.stdout !== "") {
console.log("stdout", data.stout);
controller.appendLog(data.stdout);
}
if (data.stderr) {
if (data.stderr !== "") {
console.log("stderr", data.stderr);
controller.appendLog(data.stderr);
}

View file

@ -1,34 +1,4 @@
Demo.DemoController = Ember.ObjectController.extend({
currentText: "vault help",
commandLog: [],
logs: "",
cursor: 0,
notCleared: true,
isLoading: false,
setFromHistory: function() {
var index = this.get('commandLog.length') + this.get('cursor');
var previousMessage = this.get('commandLog')[index];
this.set('currentText', previousMessage);
}.observes('cursor'),
appendLog: function(data, prefix) {
if (prefix) {
data = '$ ' + data;
}
this.set('logs', this.get('logs')+'\n'+data);
},
logCommand: function(command) {
var commandLog = this.get('commandLog');
commandLog.push(command);
this.set('commandLog', commandLog);
},
actions: {
close: function() {
this.transitionTo('index');

View file

@ -0,0 +1,70 @@
Demo.DemoStepController = Ember.ObjectController.extend({
needs: ['application'],
socket: Ember.computed.alias('controllers.application.socket'),
currentText: "",
commandLog: [],
logs: "",
cursor: 0,
notCleared: true,
isLoading: false,
setFromHistory: function() {
var index = this.get('commandLog.length') + this.get('cursor');
var previousMessage = this.get('commandLog')[index];
this.set('currentText', previousMessage);
}.observes('cursor'),
appendLog: function(data, prefix) {
if (prefix) {
data = '$ ' + data;
}
this.set('logs', this.get('logs')+'\n'+data);
Ember.run.later(function() {
var element = $('.demo-overlay');
// Scroll to the bottom of the element
element.scrollTop(element[0].scrollHeight);
}, 5);
},
logCommand: function(command) {
var commandLog = this.get('commandLog');
commandLog.push(command);
this.set('commandLog', commandLog);
},
actions: {
submitText: function() {
// Send the actual request (fake for now)
this.sendCommand();
}
},
sendCommand: function() {
var demoController = this.get('controllers.demo');
var command = this.getWithDefault('currentText', '');
var log = this.get('log');
this.set('currentText', '');
demoController.logCommand(command);
demoController.appendLog(command, true);
switch(command) {
case "":
break;
case "clear":
this.set('logs', "");
this.set('notCleared', false);
break;
default:
this.set('isLoading', true);
var data = JSON.stringify({type: "cli", data: {command: command}});
this.get('socket').send(data);
}
},
});

View file

@ -0,0 +1,18 @@
Ember.Application.initializer({
name: 'load-steps',
after: 'store',
initialize: function(container, application) {
var store = container.lookup('store:main');
var steps = {
"steps": [
{ id: 0, name: 'welcome', humanName: "Welcome to the Vault Interactive Demo!"},
{ id: 1, name: 'unseal', humanName: "Step 1: Unsealing your Vault"},
]
};
application.register('model:step', Demo.Step);
store.pushPayload('step', steps);
},
});

View file

@ -0,0 +1,6 @@
Demo.Step = DS.Model.extend({
name: DS.attr('string'),
humanName: DS.attr('string'),
instructionTemplate: Ember.computed.alias('name')
});

View file

@ -1,5 +1,5 @@
Demo.Router.map(function() {
this.route('demo', { path: '/demo' }, function() {
this.route('crud', { path: '/crud' });
this.route('demo', function() {
this.route('step', { path: '/:id' });
});
});

View file

@ -1,2 +0,0 @@
Demo.DemoCrudRoute = Ember.Route.extend({
});

View file

@ -0,0 +1,18 @@
Demo.DemoStepRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('step', params.id);
}
// socket: function() {
// return this.controllerFor('application').get('socket');
// }.property(),
// activate: function() {
// var data = JSON.stringify({type: "cli", data: {command: "vault init -key-shares=1 -key-threshold=1"}});
// var socket = this.get('socket');
// socket.onopen = function() {
// console.log("ws open");
// socket.send(data);
// };
// },
});

View file

@ -1,142 +1,3 @@
Demo.DemoView = Ember.View.extend({
classNames: ['demo-overlay'],
didInsertElement: function() {
var controller = this.get('controller'),
overlay = $('.sidebar-overlay'),
element = this.$();
overlay.addClass('active');
overlay.on('click', function() {
controller.transitionTo('index');
});
element.hide().fadeIn(300);
// Scroll to the bottom of the element
element.scrollTop(element[0].scrollHeight);
// Focus
element.find('input.shell')[0].focus();
// Hijack scrolling to only work within terminal
//
$(element).on('DOMMouseScroll mousewheel', function(ev) {
var scrolledEl = $(this),
scrollTop = this.scrollTop,
scrollHeight = this.scrollHeight,
height = scrolledEl.height(),
delta = (ev.type == 'DOMMouseScroll' ?
ev.originalEvent.detail * -40 :
ev.originalEvent.wheelDelta),
up = delta > 0;
var prevent = function() {
ev.stopPropagation();
ev.preventDefault();
ev.returnValue = false;
return false;
};
if (!up && -delta > scrollHeight - height - scrollTop) {
// Scrolling down, but this will take us past the bottom.
scrolledEl.scrollTop(scrollHeight);
return prevent();
} else if (up && delta > scrollTop) {
// Scrolling up, but this will take us past the top.
scrolledEl.scrollTop(0);
return prevent();
}
});
},
willDestroyElement: function() {
// Remove overlay
$('.sidebar-overlay').removeClass('active');
var element = this.$();
element.fadeOut(400);
// Allow scrolling
$('body').unbind('DOMMouseScroll mousewheel');
},
// click: function() {
// var element = this.$();
// // Record scoll position
// var x = element.scrollX, y = element.scrollY;
// // Focus
// element.find('input.shell')[0].focus();
// // Scroll back to where you were
// element.scrollTo(x, y);
// },
keyDown: function(ev) {
var cursor = this.get('controller.cursor'),
currentLength = this.get('controller.commandLog.length');
switch(ev.keyCode) {
// Down arrow
case 40:
if (cursor === 0) {
return;
}
this.incrementProperty('controller.cursor');
break;
// Up arrow
case 38:
if ((currentLength + cursor) === 0) {
return;
}
this.decrementProperty('controller.cursor');
break;
// command + k
case 75:
if (ev.metaKey) {
this.set('controller.logs', '');
this.set('controller.notCleared', false);
}
break;
// escape
case 27:
this.get('controller').transitionTo('index');
break;
}
},
deFocus: function() {
var element = this.$().find('input.shell');
// defocus while loading
if (this.get('controller.isLoading')) {
element.blur()
}
}.observes('controller.isLoading'),
focus: function() {
var element = this.$().find('input.shell');
element.focus()
}.observes('controller.cursor'),
submitted: function() {
var element = this.$();
console.log("submitted");
// Focus the input
element.find('input.shell')[0].focus();
// Scroll to the bottom of the element
element.scrollTop(element[0].scrollHeight);
}.observes('controller.logs.length')
classNames: ['demo-overlay']
});

View file

@ -0,0 +1,140 @@
Demo.DemoStepView = Ember.View.extend({
didInsertElement: function() {
var controller = this.get('controller'),
overlay = $('.sidebar-overlay'),
element = this.$();
overlay.addClass('active');
overlay.on('click', function() {
controller.transitionTo('index');
});
element.hide().fadeIn(300);
// Scroll to the bottom of the element
element.scrollTop(element[0].scrollHeight);
// Focus
element.find('input.shell')[0].focus();
// Hijack scrolling to only work within terminal
//
$(element).on('DOMMouseScroll mousewheel', function(ev) {
var scrolledEl = $(this),
scrollTop = this.scrollTop,
scrollHeight = this.scrollHeight,
height = scrolledEl.height(),
delta = (ev.type == 'DOMMouseScroll' ?
ev.originalEvent.detail * -40 :
ev.originalEvent.wheelDelta),
up = delta > 0;
var prevent = function() {
ev.stopPropagation();
ev.preventDefault();
ev.returnValue = false;
return false;
};
if (!up && -delta > scrollHeight - height - scrollTop) {
// Scrolling down, but this will take us past the bottom.
scrolledEl.scrollTop(scrollHeight);
return prevent();
} else if (up && delta > scrollTop) {
// Scrolling up, but this will take us past the top.
scrolledEl.scrollTop(0);
return prevent();
}
});
},
willDestroyElement: function() {
// Remove overlay
$('.sidebar-overlay').removeClass('active');
var element = this.$();
element.fadeOut(400);
// Allow scrolling
$('body').unbind('DOMMouseScroll mousewheel');
},
// click: function() {
// var element = this.$();
// // Record scoll position
// var x = element.scrollX, y = element.scrollY;
// // Focus
// element.find('input.shell')[0].focus();
// // Scroll back to where you were
// element.scrollTo(x, y);
// },
keyDown: function(ev) {
var cursor = this.get('controller.cursor'),
currentLength = this.get('controller.commandLog.length');
switch(ev.keyCode) {
// Down arrow
case 40:
if (cursor === 0) {
return;
}
this.incrementProperty('controller.cursor');
break;
// Up arrow
case 38:
if ((currentLength + cursor) === 0) {
return;
}
this.decrementProperty('controller.cursor');
break;
// command + k
case 75:
if (ev.metaKey) {
this.set('controller.logs', '');
this.set('controller.notCleared', false);
}
break;
// escape
case 27:
this.get('controller').transitionTo('index');
break;
}
},
deFocus: function() {
var element = this.$().find('input.shell');
// defocus while loading
if (this.get('controller.isLoading')) {
element.blur()
}
}.observes('controller.isLoading'),
focus: function() {
var element = this.$().find('input.shell');
element.focus()
}.observes('controller.cursor'),
submitted: function() {
var element = this.$();
console.log("submitted");
// Focus the input
element.find('input.shell')[0].focus();
// Scroll to the bottom of the element
element.scrollTop(element[0].scrollHeight);
}.observes('controller.logs.length')
});

File diff suppressed because one or more lines are too long

View file

@ -42,8 +42,22 @@
}
}
.welcome {
padding-top: 20px;
ul {
padding-left: 15px;
}
li {
list-style-type: none;
}
.instruction {
margin-top: 20px;
padding: 1px;
background-color: darken($blue, 25%);
p:last-child {
margin-bottom: 0px;
}
}
.log {

View file

@ -4,5 +4,6 @@
<%= yield %>
<%= partial "ember_templates" %>
<%= partial "ember_steps" %>
<%= partial "layouts/footer" %>