Add new webui design from Joe

This commit is contained in:
Cody Soyland 2017-04-25 08:57:15 -05:00
parent 92ec0a0cb0
commit 60c8ba238c
9 changed files with 389 additions and 221 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -1,63 +0,0 @@
.output {
overflow: auto;
padding: 0 8px;
}
.output .query {
font-family: monospace;
}
.output .response {
font-family: monospace;
}
.input-bar {
padding-right: 2em;
background-color: #eeeeee;
}
.input-textarea {
font-family: monospace;
font-size: 14px;
background-color: #dddddd;
width: 100%;
border: 0;
outline: 0;
margin: 1em;
}
body {
padding-top: 5rem;
}
.controls {
padding: 1em;
}
.output {
padding: 1em;
}
.result {
background-color: #eeeeee;
padding: 1em;
margin-top: 1em;
}
.result > .tab-content > .tab-pane {
padding: 1em;
}
.query {
background-color: #dddddd;
padding: 0.5em
}
#exTab3 .nav-pills > li > a {
border-radius: 4px 4px 0 0 ;
}
#exTab3 .tab-content {
color : white;
background-color: #428bca;
padding : 5px 15px;
}

View file

@ -1,114 +0,0 @@
class REPL {
constructor(input, output) {
this.input = input
this.output = output
this.history = []
this.history_index = 0
this.history_buffer = ''
this.result_number = 0
}
bind_events() {
const repl = this
const keys = {
ENTER: 13,
UP_ARROW: 38,
DOWN_ARROW: 40
}
this.input.addEventListener("keydown", (e) => {
if (e.keyCode == keys.UP_ARROW) {
e.preventDefault()
if (this.input.value.substring(0, this.input.selectionStart).indexOf('\n') == '-1') {
if (this.history_index == 0) {
return
} else {
if (this.history_index == this.history.length) {
this.history_buffer = this.input.value
}
this.history_index--
this.input.value = this.history[this.history_index]
this.input.setSelectionRange(this.input.value.length, this.input.value.length)
}
}
}
if (e.keyCode == keys.DOWN_ARROW) {
e.preventDefault()
if (this.input.value.substring(this.input.selectionEnd, this.input.length).indexOf('\n') == '-1') {
if (this.history_index == this.history.length) {
return
} else {
this.history_index++
if (this.history_index == this.history.length) {
this.input.value = this.history_buffer
} else {
this.input.value = this.history[this.history_index]
}
this.input.setSelectionRange(this.input.value.length, this.input.value.length)
}
}
}
if (e.keyCode == keys.ENTER && !e.shiftKey) {
e.preventDefault()
this.history_buffer = ''
this.history_index = this.history.length
this.history[this.history_index] = this.input.value
this.history_index++
this.process_query(this.input.value)
this.input.value = ""
}
})
}
process_query(query) {
var xhr = new XMLHttpRequest();
var dbname = 'foo'; // todo: get db name from dropdown menu
xhr.open('POST', '/db/' + dbname + '/query');
xhr.setRequestHeader('Content-Type', 'application/text');
const repl = this
xhr.onload = function() {
repl.result_number++
//const entry = document.createElement('p')
const result = (
'<div class="container result">' +
'<ul class="nav nav-tabs" role="tablist">' +
'<li class="nav-item">' +
'<a class="nav-link active" data-toggle="tab" href="#result' + repl.result_number + '" role="tab">Result</a>' +
'</li>' +
'<li class="nav-item">' +
'<a class="nav-link" data-toggle="tab" href="#raw' + repl.result_number + '" role="tab">Raw</a>' +
'</li>' +
'</ul>' +
'' +
'<div class="tab-content">' +
'<div class="tab-pane active" id="result' + repl.result_number + '" role="tabpanel">' +
'<p class="query">' +
query +
'</p>' +
'<p>Response</p>' +
'<p class="response">' +
xhr.responseText +
'</p>' +
'</div>' +
'<div class="tab-pane" id="raw' + repl.result_number + '" role="tabpanel">' +
'<table class="table table-inverse"><tbody>' +
'<tr><th>Response code</th><td>' + xhr.status + '</td></tr>' +
'<tr><th>Response text</th><td>' + xhr.responseText + '</td></tr>' +
'<tr><th>Response URL</th><td>' + xhr.responseURL + '</td></tr>' +
'</tbody></table>' +
'</div>' +
'</div>' +
'</div>')
// TODO: remove jquery
$(repl.output).prepend($(result))
};
xhr.send(query);
}
}
function startup() {
const input = document.querySelector('.input-textarea')
const output = document.querySelector('.output')
repl = new REPL(input, output)
repl.bind_events()
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.75 36.67"><defs><style>.cls-1{fill:#1db598;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;stroke-width:5px;}</style></defs><title>nav_cluster_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><circle class="cls-1" cx="55.14" cy="18.24" r="9.61"/><circle class="cls-1" cx="18.33" cy="18.33" r="9.61"/><circle class="cls-1" cx="91.14" cy="18.24" r="9.61"/><circle class="cls-2" cx="18.33" cy="18.33" r="15.83"/></g></g></svg>

After

Width:  |  Height:  |  Size: 517 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 78.47 48.95"><defs><style>.cls-1{fill:none;stroke:#3c5f8d;stroke-miterlimit:10;stroke-width:6px;}.cls-2{fill:#1db598;}</style></defs><title>nav_console</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect class="cls-1" x="3" y="3" width="72.47" height="42.95"/><circle class="cls-2" cx="39.25" cy="25.92" r="9.61"/></g></g></svg>

After

Width:  |  Height:  |  Size: 416 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 44.5"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-miterlimit:10;stroke-width:5px;}.cls-2{fill:#1db598;}</style></defs><title>documentation</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><line class="cls-1" y1="2.5" x2="70" y2="2.5"/><line class="cls-1" y1="20" x2="70" y2="20"/><line class="cls-1" y1="38.5" x2="52.82" y2="38.5"/><circle class="cls-2" cx="63.5" cy="38.5" r="6"/></g></g></svg>

After

Width:  |  Height:  |  Size: 488 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.47 45.95"><defs><style>.cls-1{fill:none;stroke:#3c5f8d;stroke-miterlimit:10;stroke-width:3px;}.cls-2{fill:#1db598;}</style></defs><title>nav_item1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect class="cls-1" x="1.5" y="1.5" width="72.47" height="42.95"/><circle class="cls-2" cx="37.75" cy="24.42" r="9.61"/></g></g></svg>

After

Width:  |  Height:  |  Size: 418 B

220
webui/assets/style.css Normal file
View file

@ -0,0 +1,220 @@
*{
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body{
font-family: sans-serif;
background-color: #fbfcfd;
margin: 0;
color: #102445;
}
h2{
margin-bottom: 30px;
}
h5{
text-transform: uppercase;
letter-spacing: 2px;
line-height: 1.21;
margin: 0;
}
a{
line-height: 1.38;
letter-spacing: 0.2px;
text-decoration: none;
color: #102445;
}
a:hover{
color: #1db598;
}
textarea{
width: 100%;
margin-bottom: 10px;
border-radius: 2px;
background-color: #fbfcfd;
border: solid 1.5px #e4eff4;
font-family: monospace;
font-size: 16px;
line-height: 1.5;
letter-spacing: 1.1px;
outline: none;
padding: 30px;
}
select{
/*-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: url("img/chevron-down.png") no-repeat calc(100% - 10px) !important;*/
border-radius: 3px;
background-color: #fbfcfd;
width: 187px;
height: 50px;
border: solid 1.5px #e4eff4;
font-size: 18px;
font-weight: bold;
line-height: 1.39;
letter-spacing: 0.2px;
color: #102445;
padding: 10.5px;
}
button{
width: 165px;
height: 50px;
border-radius: 3px;
background-color: #1db598;
outline: none;
border: none;
font-size: 16px;
color: white;
}
em{
font-style: normal;
opacity: 0.5;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.2px;
color: #102445;
}
.header{
height: 92px;
display: flex;
align-items: center;
justify-content: space-between;
width: 90%;
margin: auto;
}
.container{
display: flex;
height:100%;
min-height: 100vh;
}
.nav{
color: white;
display: flex;
flex-direction: column;
width: 150px;
background: #3c5f8d;
}
.nav-item{
height:150px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-bottom: 3px solid #2a4871;
cursor: pointer;
}
.nav-active{
background: #f2f7f9;
font-weight: bold;
color: #1db598;
}
.interface{
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
background: #f2f7f9;
}
.query{
margin-bottom: 30px;
}
.query,
.output-container{
width: 75%;
}
.output{
margin-bottom: 30px;
}
.input-controls{
display: flex;
justify-content: flex-end;
}
.tabs{
display: flex;
background: #eaf2f6;
}
.active-tab{
background: white;
font-weight: bold;
color: #1db598;
}
.tab{
height:60px;
width: 100px;
border-top-right-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
visibility: visible;
cursor: pointer;
}
.pane{
background: white;
padding: 30px;
display: none;
}
.active{
display: block;
}
.result-io-header{
display: flex;
align-items: center;
margin-bottom: 15px;
}
.result-input,
.result-ouput{
border-radius: 2px;
background-color: #fafafa;
border: solid 1.5px #e4eff4;
font-family: monospace;
font-size: 16px;
line-height: 1.5;
letter-spacing: 1.1px;
color: #102445;
padding: 15px;
margin-bottom: 15px;
}
.result-ouput{
background-color: #edf9f7;
border-left: solid 4px #1db598;
}
.raw{
height: 253px;
display: flex;
align-items: center;
justify-content: center;
}

View file

@ -1,51 +1,172 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<link rel="stylesheet" href="/assets/main.css">
</head>
<body>
<nav class="navbar navbar-toggleable-md navbar-inverse bg-inverse fixed-top">
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="#">Pilosa</a>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Query <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/stats">Cluster Status</a>
</li>
</ul>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/style.css">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Pilosa Console</title>
</head>
<body>
<div class="header">
<img src="https://dc3kpxyuw05cb.cloudfront.net/img/logo.svg" width="110" alt="">
<a href='/' >Support</a>
</div>
<div class="container">
<div class="nav">
<div class="nav-item nav-active">
<img style='margin-bottom:10px;' height='40px' src="/assets/nav_console.svg" alt="">
Console
</div>
</nav>
<div class="container">
<div class="input-bar">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Database
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#">1</a>
<a class="dropdown-item" href="#">2</a>
</div>
</div>
<textarea class="input-textarea"></textarea>
<div class="nav-item">
<img style='margin-bottom:10px;' height='20px' src="/assets/nav_cluster.svg" alt="">
Cluster Admin
</div>
<div class="nav-item">
<img style='margin-bottom:10px;' height='30px' src="/assets/nav_documentation.svg" alt="">
Documentation
</div>
</div>
<div class="container output"></div>
<div class="interface">
<!-- todo: remove jquery and bootstrap -->
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<script src="/assets/main.js"></script>
<script>
startup()
</script>
</body>
<div class="query">
<h2>Query</h2>
<textarea name="name" id='query' rows="5" required></textarea>
<div class='input-controls'>
<select class="" name="">
<option value="">Index</option>
</select>
&nbsp;&nbsp;&nbsp;
<button id='query-btn'>Run Query</button>
</div>
</div>
<div class="output-container">
<h2>Output</h2>
<div id="outputs">
<!-- results -->
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
//helpers
function prependChild(parent, newFirstChild) {
parent.insertBefore(newFirstChild, parent.firstChild)
}
var createSingleOutput = function(res){
var node = document.createElement("div");
node.classList.add('output');
var markup =`
<div class="panes">
<div class="pane active">
<div class="result-io">
<div class="result-io-header">
<h5>Input</h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<em>Source: Index</em>
</div>
<div class="result-input">
${res.input}
</div>
</div>
<div class="result-io">
<div class="result-io-header">
<h5>output</h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<em>.42 ms</em>
</div>
<div class="result-ouput">
${res.output}
</div>
</div>
</div>
<div class="pane">
<div class="raw">
<a href="${res.url}">Export raw .csv</a>
</div>
</div>
</div>
`
node.innerHTML = markup;
prependChild(document.getElementById("outputs"),node);
}
// mock data load
var results=[
{
id:1,
input:'Union(Bitmap(id=1, frame=“foo”), Bitmap(id=1), frame=“bar”))',
output: '{“results”:[{“attrs”:bits”:[1,2,3,4,5,12,13,14]}]}',
},
{
id:2,
input:'SetBitmapAttrs(Bitmap(id=1, frame=“foo”), Bitmap(id=1), frame=“bar”))”))',
output: 'null',
}
]
for (var i = 0; i < results.length; i++){
createSingleOutput(results[i]);
}
//mock api
function callAPI(){
return {
input:document.getElementById("query").value,
output: `${queryBox.value} +1`
}
}
//events
var button = document.getElementById('query-btn');
var queryBox = document.getElementById("query")
button.onclick = function(){
var res = callAPI()
createSingleOutput(res);
}
queryBox.addEventListener("keyup", function(event) {
event.preventDefault();
if (event.key == 'Enter') {
button.click();
}
});
</script>
</body>
</html>