asterixdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ima...@apache.org
Subject [01/11] asterixdb git commit: ASTERIXDB-1375 - New Query UI implementation
Date Fri, 19 Aug 2016 23:01:42 GMT
Repository: asterixdb
Updated Branches:
  refs/heads/master 7a180bc25 -> a4815d353


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-app/src/main/resources/queryui/js/json-formatter.min.js
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/queryui/js/json-formatter.min.js b/asterixdb/asterix-app/src/main/resources/queryui/js/json-formatter.min.js
new file mode 100644
index 0000000..f499716
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/resources/queryui/js/json-formatter.min.js
@@ -0,0 +1,7 @@
+/*!
+ * jsonformatter
+ * 
+ * Version: 0.6.0 - 2016-04-29T03:24:40.672Z
+ * License: Apache-2.0
+ */
+"use strict";angular.module("jsonFormatter",["RecursionHelper"]).provider("JSONFormatterConfig",function(){var
n=!1,e=100,t=5;return{get hoverPreviewEnabled(){return n},set hoverPreviewEnabled(e){n=!!e},get
hoverPreviewArrayCount(){return e},set hoverPreviewArrayCount(n){e=parseInt(n,10)},get hoverPreviewFieldCount(){return
t},set hoverPreviewFieldCount(n){t=parseInt(n,10)},$get:function(){return{hoverPreviewEnabled:n,hoverPreviewArrayCount:e,hoverPreviewFieldCount:t}}}}).directive("jsonFormatter",["RecursionHelper","JSONFormatterConfig",function(n,e){function
t(n){return n.replace('"','"')}function r(n){if(void 0===n)return"";if(null===n)return"Object";if("object"==typeof
n&&!n.constructor)return"Object";var e=/function (.{1,})\(/,t=e.exec(n.constructor.toString());return
t&&t.length>1?t[1]:""}function o(n){return null===n?"null":typeof n}function s(n,e){var
r=o(n);return"null"===r||"undefined"===r?r:("string"===r&&(e='"'+t(e)+'"'),"function"===r?n.toString().replace(/[\r\n]/g,"").
 replace(/\{.*\}/,"")+"{…}":e)}function i(n){var e="";return angular.isObject(n)?(e=r(n),angular.isArray(n)&&(e+="["+n.length+"]")):e=s(n,n),e}function
a(n){n.isArray=function(){return angular.isArray(n.json)},n.isObject=function(){return angular.isObject(n.json)},n.getKeys=function(){return
n.isObject()?Object.keys(n.json).map(function(n){return""===n?'""':n}):void 0},n.type=o(n.json),n.hasKey="undefined"!=typeof
n.key,n.getConstructorName=function(){return r(n.json)},"string"===n.type&&("Invalid
Date"!==new Date(n.json).toString()&&(n.isDate=!0),0===n.json.indexOf("http")&&(n.isUrl=!0)),n.isEmptyObject=function(){return
n.getKeys()&&!n.getKeys().length&&n.isOpen&&!n.isArray()},n.isOpen=!!n.open,n.toggleOpen=function(){n.isOpen=!n.isOpen},n.childrenOpen=function(){return
n.open>1?n.open-1:0},n.openLink=function(e){e&&(window.location.href=n.json)},n.parseValue=function(e){return
s(n.json,e)},n.showThumbnail=function(){return!!e.hoverPreviewEnabled&&n.isObject()&&!n.isOpen},n.getTh
 umbnail=function(){if(n.isArray())return n.json.length>e.hoverPreviewArrayCount?"Array["+n.json.length+"]":"["+n.json.map(i).join(",
")+"]";var t=n.getKeys(),r=t.slice(0,e.hoverPreviewFieldCount),o=r.map(function(e){return
e+":"+i(n.json[e])}),s=t.length>=5?"…":"";return"{"+o.join(", ")+s+"}"}}return{templateUrl:"json-formatter.html",restrict:"E",replace:!0,scope:{json:"=",key:"=",open:"="},compile:function(e){return
n.compile(e,a)}}}]),"object"==typeof module&&(module.exports="jsonFormatter"),angular.module("RecursionHelper",[]).factory("RecursionHelper",["$compile",function(n){return{compile:function(e,t){angular.isFunction(t)&&(t={post:t});var
r,o=e.contents().remove();return{pre:t&&t.pre?t.pre:null,post:function(e,s){r||(r=n(o)),r(e,function(n){s.append(n)}),t&&t.post&&t.post.apply(null,arguments)}}}}}]),angular.module("jsonFormatter").run(["$templateCache",function(n){n.put("json-formatter.html",'<div
ng-init="isOpen = open && open > 0" class="json-formatter-row"><a ng-click=
 "toggleOpen()"><span class="toggler {{isOpen ? \'open\' : \'\'}}" ng-if="isObject()"></span>
<span class="key" ng-if="hasKey"><span class="key-text">{{key}}</span><span
class="colon">:</span></span> <span class="value"><span ng-if="isObject()"><span
class="constructor-name">{{getConstructorName(json)}}</span> <span ng-if="isArray()"><span
class="bracket">[</span><span class="number">{{json.length}}</span><span
class="bracket">]</span></span></span> <span ng-if="!isObject()" ng-click="openLink(isUrl)"
class="{{type}}" ng-class="{date: isDate, url: isUrl}">{{parseValue(json)}}</span></span>
<span ng-if="showThumbnail()" class="thumbnail-text">{{getThumbnail()}}</span></a><div
class="children" ng-if="getKeys().length && isOpen"><json-formatter ng-repeat="key
in getKeys() track by $index" json="json[key]" key="key" open="childrenOpen()"></json-formatter></div><div
class="children empty object" ng-if="isEmptyObject()"></div><div class="children
empty array" ng-if="getKeys() && !getKeys()
 .length && isOpen && isArray()"></div></div>')}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-app/src/main/resources/queryui/js/main.js
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/queryui/js/main.js b/asterixdb/asterix-app/src/main/resources/queryui/js/main.js
new file mode 100644
index 0000000..991e624
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/resources/queryui/js/main.js
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var SERVER_HOST = "";
+var DATAVERSE_QUERY = "for $x in dataset Metadata.Dataverse return $x;"
+var DATE_TIME_REGEX = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)$/;
+var DATE_REGEX = /^(\d{4}-\d{2}-\d{2})$/;
+
+var app = angular.module('queryui', ['jsonFormatter','ui.codemirror']);
+
+app.service('recordFunctions', function(){
+  this.ObjectKeys = function(obj){
+    var typeStr = Object.prototype.toString.call(obj);
+    var res = [];
+    if (typeStr === "[object Object]"){
+        for (var key in obj) {
+              if (obj.hasOwnProperty(key) && !(key === "$$hashKey")) {
+                res.push(key)
+              }
+            }
+    }else{
+        res = [-1];
+    }
+    return res;
+  }
+  this.isObject = function(obj){
+    var typeStr = Object.prototype.toString.call(obj);
+    if (typeStr === "[object Object]"){
+      return true;
+    }else{
+      return false;
+    }
+  }
+  this.isArray = function(obj){
+    var typeStr = Object.prototype.toString.call(obj);
+    if ((typeStr === "[object Array]" )){
+      return true;
+    }else{
+      return false;
+    }
+  }
+  this.isNested = function(obj){
+    return  this.isObject(obj) || this.isArray(obj);
+  }
+  this.ObjectValue = function(obj,key){
+    var typeStr;
+    var value;
+    if (key == -1){
+        typeStr = Object.prototype.toString.call(obj);
+        value = obj;
+    }else{
+        typeStr = Object.prototype.toString.call(obj[key]);
+        value = obj[key];
+    }
+    if (typeStr === "[object Array]"){
+      return "List +";
+    }else if (typeStr === "[object Object]"){
+      return "Record +";
+    }else if (typeStr == "[object Null]"){
+      return "NULL";
+    }else if(DATE_REGEX.exec(value) != null){
+      var dat = new Date(value);
+      return dat.getUTCFullYear()+"/"+dat.getUTCMonth()+"/"+dat.getUTCDay();
+    }else if(DATE_TIME_REGEX.exec(value) != null){
+      var dat = new Date(value);
+      return dat.getUTCFullYear()+"/"+dat.getUTCMonth()+"/"+dat.getUTCDay()
+        +" "+dat.getUTCHours()+":"+dat.getUTCMinutes()+":"+dat.getUTCSeconds();
+    }else{
+      return value;
+    }
+  }
+});
+
+app.controller('queryCtrl', function($rootScope, $scope, $http, recordFunctions) {
+
+  $scope.recordFunctions = recordFunctions;
+  $scope.current_tab = 0;
+  $scope.current_preview_tab = 0;
+  $scope.current_list = 0;
+  $scope.maximized = false;
+  $scope.collapsed = false;
+  $scope.results = [];
+  $scope.history = [];
+  $scope.dataverses = [];
+  $scope.selectedItem = null;
+  $scope.selected_dataverse = "";
+  $scope.errorText = null;
+  $scope.statusText = "Wait...";
+  $scope.query_input =  "";
+  $scope.uiReady = false;
+
+  $scope.queryCmOptions ={
+      lineNumbers: true,
+      indentWithTabs: true,
+      lineWrapping: false,
+      mode: 'aql'
+  }
+
+  $scope.queryPreviewOptions ={
+      indentWithTabs: true,
+      lineWrapping: true,
+      mode: 'javascript',
+      readOnly : true
+  }
+
+$scope.init= function(){
+    $http.post("/").then(function(response){
+        SERVER_HOST = location.protocol + "//" + location.hostname + ":" + response.data.api_port;
+        $scope.initDataverses();
+    },function(response){
+        $scope.statusText = "Unable to get Asterix HTTP API Port";
+    });
+}
+
+  $scope.initDataverses = function(){
+    $http.get(SERVER_HOST+"/query?query="+encodeURI(DATAVERSE_QUERY)).then(function(response){
+      for (i in response.data){
+        $scope.dataverses.push(response.data[i].DataverseName);
+        $scope.selected_dataverse = $scope.dataverses[0];
+        $scope.statusText = "Web UI Ready";
+        $scope.uiReady = true;
+      }
+    },
+    function(response){
+      $scope.statusText = "Error Occurred Executing Query";
+      $scope.errorText = response.data.summary;
+      $scope.maximized = false;
+    });
+    $scope.load();
+  }
+
+  $scope.query = function(){
+    var timer = new Date().getTime();
+    $scope.save($scope.query_input,$scope.selected_dataverse);
+    $http.get(SERVER_HOST+"/query?query="+encodeURI("use dataverse "+$scope.selected_dataverse+";"+$scope.query_input)).then(function(response){
+      $scope.results = response.data;
+      console.log(response);
+      timer = new Date().getTime() - timer;
+      $scope.statusText = "Query returned " + $scope.results.length + " records in " + timer
+ "ms";
+      $scope.errorText = null;
+      $scope.maximized = false;
+    },
+    function(response){
+      $scope.statusText = "Error Occurred Executing Query";
+      $scope.errorText = response.data.summary;
+      $scope.maximized = false;
+      $scope.results = [];
+    });
+  }
+
+  $scope.isNested = function(obj){
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) {
+        var typeStr = Object.prototype.toString.call(obj[key]);
+        if (typeStr === "[object Array]" || typeStr === "[object Object]") return true;
+      }
+    }
+    return false;
+  }
+
+  $scope.isRecordPlus = function(obj,key){
+      var value;
+      if (key == -1){
+          value = obj;
+      }else{
+          value = obj[key];
+      }
+      return $scope.recordFunctions.isNested(value) ? "asterix-nested" : "";
+  }
+
+  $scope.viewRecord = function(obj){
+    $scope.selectedItem = obj;
+    $scope.current_preview_tab = 0;
+    $("#recordModel").modal();
+  }
+
+  $scope.previewJSON = function(obj){
+    return JSON.stringify(obj,null,4);
+  }
+
+  $scope.save = function(query, database){
+    var toSave = [query, database];
+    if ($scope.history.length >= 1){
+        var i = $scope.history.length - 1;
+        if (new String(query).valueOf() === new String($scope.history[i][0]).valueOf()){
+            if (new String(database).valueOf() === new String($scope.history[i][1]).valueOf())
return;
+        }
+    }
+    if($scope.history.push(toSave) == 11){
+      $scope.history.shift();
+    }
+    localStorage.setItem("history",JSON.stringify($scope.history));
+  }
+
+  $scope.load = function(){
+      var history = JSON.parse(localStorage.getItem("history"));
+      if (history != null) $scope.history = history;
+  }
+
+  $scope.previewHistory = function(entry){
+      $scope.current_tab = 0;
+      $scope.query_input = entry[0];
+      $scope.selected_dataverse = entry[1];
+  }
+
+  $scope.leftContainerClass =function(){
+      if ($scope.maximized){
+           return 'col-md-12';
+      }else{
+           if($scope.collapsed){
+               return 'col-md-1';
+           }else{
+               return 'col-md-4'
+           }
+      }
+  }
+
+  $scope.rightContainerClass =function(){
+      if ($scope.maximized){
+           return 'col-md-0';
+      }else{
+           if($scope.collapsed){
+               return 'col-md-11';
+           }else{
+               return 'col-md-8'
+           }
+      }
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-app/src/main/resources/queryui/js/ui-codemirror.js
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/queryui/js/ui-codemirror.js b/asterixdb/asterix-app/src/main/resources/queryui/js/ui-codemirror.js
new file mode 100644
index 0000000..480f4f2
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/resources/queryui/js/ui-codemirror.js
@@ -0,0 +1,150 @@
+'use strict';
+
+/**
+ * Binds a CodeMirror widget to a <textarea> element.
+ */
+angular.module('ui.codemirror', [])
+  .constant('uiCodemirrorConfig', {})
+  .directive('uiCodemirror', uiCodemirrorDirective);
+
+/**
+ * @ngInject
+ */
+function uiCodemirrorDirective($timeout, uiCodemirrorConfig) {
+
+  return {
+    restrict: 'EA',
+    require: '?ngModel',
+    compile: function compile() {
+
+      // Require CodeMirror
+      if (angular.isUndefined(window.CodeMirror)) {
+        throw new Error('ui-codemirror needs CodeMirror to work... (o rly?)');
+      }
+
+      return postLink;
+    }
+  };
+
+  function postLink(scope, iElement, iAttrs, ngModel) {
+
+    var codemirrorOptions = angular.extend(
+      { value: iElement.text() },
+      uiCodemirrorConfig.codemirror || {},
+      scope.$eval(iAttrs.uiCodemirror),
+      scope.$eval(iAttrs.uiCodemirrorOpts)
+    );
+
+    var codemirror = newCodemirrorEditor(iElement, codemirrorOptions);
+
+    configOptionsWatcher(
+      codemirror,
+      iAttrs.uiCodemirror || iAttrs.uiCodemirrorOpts,
+      scope
+    );
+
+    configNgModelLink(codemirror, ngModel, scope);
+
+    configUiRefreshAttribute(codemirror, iAttrs.uiRefresh, scope);
+
+    // Allow access to the CodeMirror instance through a broadcasted event
+    // eg: $broadcast('CodeMirror', function(cm){...});
+    scope.$on('CodeMirror', function(event, callback) {
+      if (angular.isFunction(callback)) {
+        callback(codemirror);
+      } else {
+        throw new Error('the CodeMirror event requires a callback function');
+      }
+    });
+
+    // onLoad callback
+    if (angular.isFunction(codemirrorOptions.onLoad)) {
+      codemirrorOptions.onLoad(codemirror);
+    }
+  }
+
+  function newCodemirrorEditor(iElement, codemirrorOptions) {
+    var codemirrot;
+
+    if (iElement[0].tagName === 'TEXTAREA') {
+      // Might bug but still ...
+      codemirrot = window.CodeMirror.fromTextArea(iElement[0], codemirrorOptions);
+    } else {
+      iElement.html('');
+      codemirrot = new window.CodeMirror(function(cm_el) {
+        iElement.append(cm_el);
+      }, codemirrorOptions);
+    }
+
+    return codemirrot;
+  }
+
+  function configOptionsWatcher(codemirrot, uiCodemirrorAttr, scope) {
+    if (!uiCodemirrorAttr) { return; }
+
+    var codemirrorDefaultsKeys = Object.keys(window.CodeMirror.defaults);
+    scope.$watch(uiCodemirrorAttr, updateOptions, true);
+    function updateOptions(newValues, oldValue) {
+      if (!angular.isObject(newValues)) { return; }
+      codemirrorDefaultsKeys.forEach(function(key) {
+        if (newValues.hasOwnProperty(key)) {
+
+          if (oldValue && newValues[key] === oldValue[key]) {
+            return;
+          }
+
+          codemirrot.setOption(key, newValues[key]);
+        }
+      });
+    }
+  }
+
+  function configNgModelLink(codemirror, ngModel, scope) {
+    if (!ngModel) { return; }
+    // CodeMirror expects a string, so make sure it gets one.
+    // This does not change the model.
+    ngModel.$formatters.push(function(value) {
+      if (angular.isUndefined(value) || value === null) {
+        return '';
+      } else if (angular.isObject(value) || angular.isArray(value)) {
+        throw new Error('ui-codemirror cannot use an object or an array as a model');
+      }
+      return value;
+    });
+
+
+    // Override the ngModelController $render method, which is what gets called when the
model is updated.
+    // This takes care of the synchronizing the codeMirror element with the underlying model,
in the case that it is changed by something else.
+    ngModel.$render = function() {
+      //Code mirror expects a string so make sure it gets one
+      //Although the formatter have already done this, it can be possible that another formatter
returns undefined (for example the required directive)
+      var safeViewValue = ngModel.$viewValue || '';
+      codemirror.setValue(safeViewValue);
+    };
+
+
+    // Keep the ngModel in sync with changes from CodeMirror
+    codemirror.on('change', function(instance) {
+      var newValue = instance.getValue();
+      if (newValue !== ngModel.$viewValue) {
+        scope.$evalAsync(function() {
+          ngModel.$setViewValue(newValue);
+        });
+      }
+    });
+  }
+
+  function configUiRefreshAttribute(codeMirror, uiRefreshAttr, scope) {
+    if (!uiRefreshAttr) { return; }
+
+    scope.$watch(uiRefreshAttr, function(newVal, oldVal) {
+      // Skip the initial watch firing
+      if (newVal !== oldVal) {
+        $timeout(function() {
+          codeMirror.refresh();
+        });
+      }
+    });
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-app/src/main/resources/queryui/queryui.html
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/resources/queryui/queryui.html b/asterixdb/asterix-app/src/main/resources/queryui/queryui.html
new file mode 100644
index 0000000..3c640fb
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/resources/queryui/queryui.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>AsterixDB Console</title>
+  <link rel="stylesheet" href="/queryui/css/bootstrap.min.css" media="screen" title="no
title" charset="utf-8">
+  <link rel="stylesheet" href="/queryui/css/bootstrap-theme.min.css" media="screen" title="no
title" charset="utf-8">
+  <link rel="stylesheet" href="/queryui/css/master.css" media="screen" title="no title"
charset="utf-8">
+  <link rel="stylesheet" href="/queryui/css/json-formatter.min.css" media="screen" title="no
title" charset="utf-8">
+  <link rel="stylesheet" href="/queryui/css/codemirror.css" media="screen" title="no title"
charset="utf-8">
+  <script src="/queryui/js/jquery-1.12.4.min.js" charset="utf-8"></script>
+  <script src="/queryui/js/angular.min.js" charset="utf-8"></script>
+  <script src="/queryui/js/json-formatter.min.js" charset="utf-8"></script>
+  <script src="/queryui/js/bootstrap.min.js" charset="utf-8"></script>
+  <script src="/queryui/js/codemirror.js" charset="utf-8"></script>
+  <script src="/queryui/js/ui-codemirror.js" charset="utf-8"></script>
+  <script src="/queryui/js/aql-mode.js" charset="utf-8"></script>
+  <script src="/queryui/js/javascript.js" charset="utf-8"></script>
+  <script src="/queryui/js/main.js" charset="utf-8"></script>
+</head>
+<body ng-app="queryui">
+  <div class="row main-container" ng-controller="queryCtrl" ng-init="init()">
+    <div class="col-md-4 left-container" ng-class="leftContainerClass()">
+        <div>
+            <div class="row" ng-show="collapsed">
+                <div class="row-fluid">
+                    <div class="col-sm-12 text-center"><img class="logo-collapsed"
src="/queryui/img/asterixlogo-collapsed.png" alt=""/></div>
+                </div>
+                <div class="row-fluid">
+                    <div class="col-sm-12 text-center"><span class="glyphicon glyphicon-menu-hamburger
asterix-button"
+                                                           ng-class="collapsed == true ?
'asterix-button-selected' : '' "
+                                                           ng-click="collapsed = !collapsed"></span></div>
+                </div>
+            </div>
+            <div class="row" ng-hide="collapsed">
+                <div class="col-sm-10"><img class="logo" src="/queryui/img/finalasterixlogo.png"
alt=""/></div>
+                <div class="col-sm-2 text-right" ng-hide="maximized"><span class="glyphicon
glyphicon-menu-left asterix-button"
+                                                       ng-class="collapsed == true ? 'asterix-button-selected'
: '' "
+                                                       ng-click="collapsed = !collapsed"></span></div>
+            </div>
+            <div ng-hide="collapsed" class="row">
+                <div class="col-sm-12">
+                    <div class="left-using-container">
+                        <label for="usingSelect" class="col-sm-2 control-label">Using</label>
+                        <div class="col-sm-10">
+                            <select class="form-control" id="usingSelect" ng-model="selected_dataverse">
+                                <option ng-repeat="entry in dataverses" >{{entry}}</option>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div ng-hide="collapsed" class="row">
+                <div class="col-sm-12">
+                    <div class="input-container">
+                        <div id="input-tab">
+                            <ul class="nav nav-justified asterix-nav">
+                                <li ng-class="current_tab == 0 ? 'asterix-nav-active'
: '' "><a href="#" ng-click="current_tab = 0">Query</a></li>
+                                <li ng-class="current_tab == 1 ? 'asterix-nav-active'
: '' "><a href="#" ng-click="current_tab = 1">History</a></li>
+                            </ul>
+                            <div class="asterix-tabpage" ng-if="current_tab == 0">
+                                <textarea ui-codemirror="queryCmOptions" name="Text1"
ng-model="$parent.query_input" class="form-control input-container-code" placeholder="Query"
cols="40" rows="15"></textarea>
+                                <div class="icon-maximize"><span class="glyphicon
glyphicon-fullscreen asterix-button" aria-hidden="true"
+                                                                 ng-class="$parent.maximized
== true ? 'asterix-button-selected' : '' "
+                                                                 ng-click="$parent.maximized
= !$parent.maximized"></span></div>
+                            </div>
+                            <div class="asterix-tabpage" ng-if="current_tab == 1">
+                                <div class="asterix-tabpage-scroll">
+                                    <div class="asterix-well margin-bottom" ng-repeat="query
in history.slice().reverse() track by $index">
+                                        <div class="row">
+                                            <div class="col-md-8"><code>{{query[0]}}</code></div>
+                                            <div class="col-md-4 asterix-well-right"><a
href="" ng-click="previewHistory(query)">Preview</a></div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div class="icon-maximize"><span class="glyphicon
glyphicon-fullscreen asterix-button" aria-hidden="true"
+                                                                 ng-class="$parent.maximized
== true ? 'asterix-button-selected' : '' "
+                                                                 ng-click="$parent.maximized
= !$parent.maximized"></span></div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div ng-hide="collapsed" class="row vh-spacer">
+                <div class="col-sm-12">
+                    <button type="button" class="btn btn-asterix center-block" ng-click="query()"
ng-if="uiReady">Run</button>
+                    <button type="button" class="btn btn-asterix center-block" ng-if="!uiReady">Loading
Wait..</button>
+                </div>
+            </div>
+        </div>
+        <div ng-show="false">
+            <div class="row">
+                <div class="col-sm-12"><img class="logo logo-collapsed" src="/queryui/img/finalasterixlogo.png"
alt="" /></div>
+            </div>
+            <div class="row">
+                <div class="col-sm-12 text-center"><span class="glyphicon glyphicon-menu-hamburger
asterix-button"
+                                                         ng-class="collapsed == true ? 'asterix-button-selected'
: '' "
+                                                         ng-click="collapsed = !collapsed"></span></div>
+            </div>
+        </div>
+    </div>
+    <div class="col-md-8 right-container" ng-class="rightContainerClass()">
+      <p class="asterix-status">{{statusText}}</p>
+      <div class="alert alert-danger" role="alert" ng-if="errorText != null">{{errorText}}</div>
+      <div class="right-toolbar">
+        <span class="glyphicon glyphicon-align-justify asterix-button" aria-hidden="true"
+          ng-class="current_list == 0 ? 'asterix-button-selected' : '' "
+          ng-click="current_list = 0"></span>
+        <span class="glyphicon glyphicon-th-large asterix-button" aria-hidden="true"
+          ng-class="current_list == 1 ? 'asterix-button-selected' : '' "
+          ng-click="current_list = 1"></span>
+      </div>
+      <div class="asterix-list-view" ng-if="current_list == 0 && results.length
!= 0">
+        <table class="table table-hover asterix-table">
+          <tbody>
+            <tr ng-repeat="record in $parent.results track by $index">
+              <td ng-repeat="key in recordFunctions.ObjectKeys(record)" class="asterix-inline-item"
ng-class="isRecordPlus(record,key)" ng-click="viewRecord(record)">
+                <p class="small asterix-small">{{key == -1 ? 'value' : key}}</p>{{recordFunctions.ObjectValue(record,key)}}
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+      <div class="asterix-list-wells" ng-if="current_list == 1 && results.length
!= 0">
+        <div ng-repeat="record in $parent.results track by $index" class="asterix-well
flex-well" ng-click="viewRecord(record)">
+          <div ng-repeat="key in recordFunctions.ObjectKeys(record)" class="row asterix-well-row">
+            <div class="col-sm-6" ng-class="isRecordPlus(record,key)">{{recordFunctions.ObjectValue(record,key)}}</div>
+            <div class="col-sm-6 asterix-well-right"><p class="small asterix-small">{{key
== -1 ? 'value' : key}}</p></div>
+          </div>
+          <div class="row">
+            <div class="col-sm-12" ng-if="isNested(record)">
+              <span class="label label-warning">NESTED</span>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="modal fade" id="recordModel" role="dialog">
+          <div class="modal-dialog">
+            <div id="input-tab">
+              <ul class="nav nav-justified asterix-nav">
+                <li ng-class="current_preview_tab == 0 ? 'asterix-nav-active' : '' "><a
href="#" ng-click="current_preview_tab = 0">Record Viewer</a></li>
+                <li ng-class="current_preview_tab == 1 ? 'asterix-nav-active' : '' "><a
href="#" ng-click="current_preview_tab = 1">JSON Viewer</a></li>
+                <!-- <li><a href="#" data-dismiss="modal">
+                  <span class="glyphicon glyphicon-remove"></span>
+                </a></li> -->
+              </ul>
+              <div class="asterix-tabpage" ng-if="current_preview_tab == 0">
+              <json-formatter open="2" ng-if="selectedItem != null" json="selectedItem"></json-formatter>
+              </div>
+              <div class="asterix-tabpage" ng-if="current_preview_tab == 1">
+                <pre ng-bind="previewJSON(selectedItem)"></pre>
+              </div>
+            </div>
+          </div>
+        </div>
+    </div>
+  </div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/AsterixExternalProperties.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/AsterixExternalProperties.java
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/AsterixExternalProperties.java
index 026583d..b2a43e3 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/AsterixExternalProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/AsterixExternalProperties.java
@@ -28,6 +28,9 @@ public class AsterixExternalProperties extends AbstractAsterixProperties
{
     private static final String EXTERNAL_SECONDARY_WEBPORT_KEY = "web.secondary.port";
     private static int EXTERNAL_SECONDARY_WEBPORT_DEFAULT = 19005;
 
+    private static final String QUERY_WEBPORT_KEY = "web.queryinterface.port";
+    private static final int QUERY_WEBPORT_DEFAULT = 19006;
+
     private static final String EXTERNAL_LOGLEVEL_KEY = "log.level";
     private static Level EXTERNAL_LOGLEVEL_DEFAULT = Level.WARNING;
 
@@ -63,6 +66,11 @@ public class AsterixExternalProperties extends AbstractAsterixProperties
{
                 PropertyInterpreters.getIntegerPropertyInterpreter());
     }
 
+    public int getQueryWebInterfacePort() {
+        return accessor.getProperty(QUERY_WEBPORT_KEY, QUERY_WEBPORT_DEFAULT,
+                PropertyInterpreters.getIntegerPropertyInterpreter());
+    }
+
     public int getAPIServerPort() {
         return accessor.getProperty(EXTERNAL_APISERVER_KEY, EXTERNAL_APISERVER_DEFAULT,
                 PropertyInterpreters.getIntegerPropertyInterpreter());

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/a4815d35/asterixdb/asterix-installer/src/main/resources/conf/asterix-configuration.xml
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-installer/src/main/resources/conf/asterix-configuration.xml
b/asterixdb/asterix-installer/src/main/resources/conf/asterix-configuration.xml
index a7c5c6d..aa8ad8d 100644
--- a/asterixdb/asterix-installer/src/main/resources/conf/asterix-configuration.xml
+++ b/asterixdb/asterix-installer/src/main/resources/conf/asterix-configuration.xml
@@ -240,6 +240,13 @@
   </property>
 
   <property>
+    <name>web.queryinterface.port</name>
+    <value>19006</value>
+    <description>The port for the ASTERIX web query interface. (Default = 19006)
+    </description>
+  </property>
+
+  <property>
     <name>api.port</name>
     <value>19002</value>
     <description>The port for the ASTERIX API server. (Default = 19002)


Mime
View raw message