Adding skeletal structure for the ONLP gNMI GUI demo.

Change-Id: I6796ebf200e20a51bdc098fcc3696b78d7c1132e
diff --git a/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.css b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.css
new file mode 100644
index 0000000..8aa18f6
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.css
@@ -0,0 +1,2 @@
+/* css for layout topology overlay  */
+
diff --git a/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.html b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.html
new file mode 100644
index 0000000..377b3b0
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.html
@@ -0,0 +1,4 @@
+<!-- partial HTML -->
+<div id="ov-od-topov">
+    <p>This is a hidden view .. just a placeholder to house the javascript</p>
+</div>
diff --git a/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.js b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.js
new file mode 100644
index 0000000..d78c009
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopov.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ Module containing the "business logic" for the layout topology overlay.
+ */
+
+(function () {
+    'use strict';
+
+    // injected refs
+    var $log, flash, wss;
+
+    function doFoo(type, description) {
+        flash.flash(description);
+        wss.sendEvent('doFoo', {
+            type: type
+        });
+    }
+
+    function clear() {
+        // Nothing to do?
+    }
+
+    angular.module('ovOdTopov', [])
+        .factory('OnlpDemoTopovService',
+        ['$log', 'FlashService', 'WebSocketService',
+
+        function (_$log_, _flash_, _wss_) {
+            $log = _$log_;
+            flash = _flash_;
+            wss = _wss_;
+
+            return {
+                doFoo: doFoo,
+                clear: clear
+            };
+        }]);
+}());
diff --git a/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopovOverlay.js b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopovOverlay.js
new file mode 100644
index 0000000..682ea17
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/odTopov/odTopovOverlay.js
@@ -0,0 +1,59 @@
+// path painter topology overlay - client side
+//
+// This is the glue that binds our business logic (in ppTopov.js)
+// to the overlay framework.
+
+(function () {
+    'use strict';
+
+    // injected refs
+    var $log, tov, ns, lts, sel;
+
+    // our overlay definition
+    var overlay = {
+        overlayId: 'od-overlay',
+        glyphId: 'm_disjointPaths',
+        tooltip: 'ONLP Data Overlay',
+
+        activate: function () {
+            $log.debug("ONLP data topology overlay ACTIVATED");
+        },
+        deactivate: function () {
+            lts.clear();
+            $log.debug("ONLP data topology overlay DEACTIVATED");
+        },
+
+        // detail panel button definitions
+        buttons: {
+            showOnlpView: {
+                gid: 'chain',
+                tt: 'ONLP data',
+                cb: function (data) {
+                    $log.debug('ONLP action invoked on selection:', sel);
+                    ns.navTo('onlp', { devId: sel.id });
+                }
+            }
+        },
+
+        hooks: {
+            // hooks for when the selection changes...
+            single: function (data) {
+                $log.debug('selection data:', data);
+                sel = data;
+                tov.addDetailButton('showOnlpView');
+            }
+        }
+    };
+
+    // invoke code to register with the overlay service
+    angular.module('ovOdTopov')
+        .run(['$log', 'TopoOverlayService', 'NavService', 'OnlpDemoTopovService',
+
+            function (_$log_, _tov_, _ns_, _lts_) {
+                $log = _$log_;
+                tov = _tov_;
+                ns = _ns_;
+                lts = _lts_;
+                tov.register(overlay);
+            }]);
+}());
diff --git a/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.css b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.css
new file mode 100644
index 0000000..60e1c58
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.css
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ ONOS GUI -- Port View (layout) -- CSS file
+ */
+
+#ov-onlp h2 {
+    display: inline-block;
+}
+
+#ov-onlp div.ctrl-btns {
+}
+
+#ov-onlp td {
+    text-align: center;
+}
+
+#ov-onlp td.left {
+    text-align: left;
+}
+
+#ov-onlp tr.left {
+    text-align: left;
+}
+
+#ov-onlp tr.no-data td {
+    text-align: center;
+}
diff --git a/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.html b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.html
new file mode 100644
index 0000000..6972f40
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.html
@@ -0,0 +1,91 @@
+<!-- Port partial HTML -->
+<div id="ov-onlp">
+    <div class="tabular-header">
+        <h2>ONLP Data for {{devId || "(No device selected)"}}</h2>
+
+        <div class="ctrl-btns">
+            <div class="refresh" ng-class="{active: autoRefresh}"
+                 icon icon-size="42" icon-id="refresh"
+                 tooltip tt-msg="autoRefreshTip"
+                 ng-click="toggleRefresh()"></div>
+
+            <div class="separator"></div>
+
+            <div class="refresh" ng-class="{active: isNZ()}"
+                 icon icon-size="42" icon-id="nonzero"
+                 tooltip tt-msg="toggleNZTip"
+                 ng-click="toggleNZ()"></div>
+
+            <div class="refresh" ng-class="{active: isDelta()}"
+                 icon icon-size="42" icon-id="delta"
+                 tooltip tt-msg="toggleDeltaTip"
+                 ng-click="toggleDelta()"></div>
+
+            <div class="separator"></div>
+
+            <div class="active"
+                 icon icon-id="deviceTable" icon-size="42"
+                 tooltip tt-msg="deviceTip"
+                 ng-click="nav('device')"></div>
+
+            <div class="active"
+                 icon icon-id="flowTable" icon-size="42"
+                 tooltip tt-msg="flowTip"
+                 ng-click="nav('flow')"></div>
+
+            <div class="current-view"
+                 icon icon-id="portTable" icon-size="42"></div>
+
+            <div class="active"
+                 icon icon-id="groupTable" icon-size="42"
+                 tooltip tt-msg="groupTip"
+                 ng-click="nav('group')"></div>
+
+            <div class="active"
+                 icon icon-id="meterTable" icon-size="42"
+                 tooltip tt-msg="meterTip"
+                 ng-click="nav('meter')"></div>
+
+            <div class="active"
+                 icon icon-id="pipeconfTable" icon-size="42"
+                 tooltip tt-msg="pipeconfTip"
+                 ng-click="nav('pipeconf')"></div>
+        </div>
+    </div>
+
+
+     <div class="summary-list" onos-table-resize>
+        <div class="table-header" onos-sortable-header>
+            <table>
+                <tr>
+                    <td colId="id" col-width="60px" sortable>SFP ID </td>
+                    <td class="left" colId="id" col-width="30px" sortable> </td>
+                    <td class="left" colId="vendor" sortable>Vendor </td>
+                    <td class="left" colId="model_number" sortable>Model # </td>
+                    <td class="left" colId="serial_number" sortable>Serial # </td>
+                    <td class="left" colId="form_factor" sortable>Form Factor </td>
+                </tr>
+            </table>
+        </div>
+
+        <div class="table-body">
+            <table id-prop="id">
+                <tr ng-if="!tableData.length" class="no-data">
+                    <td colspan="6">{{annots.no_rows_msg}}</td>
+                </tr>
+
+                <tr ng-repeat="onlp in tableData"
+                    ng-class="{selected: onlp.id === selId}"
+                    ng-repeat-complete row-id="{{onlp.id}}">
+                    <td>{{onlp.id}}</td>
+                    <td class="left">{{onlp.presence}}</td>
+                    <td class="left">{{onlp.vendor}}</td>
+                    <td class="left">{{onlp.model_number}}</td>
+                    <td class="left">{{onlp.serial_number}}</td>
+                    <td class="left">{{onlp.form_factor}}</td>
+                </tr>
+            </table>
+        </div>
+    </div>
+
+</div>
diff --git a/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.js b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.js
new file mode 100644
index 0000000..81625d2
--- /dev/null
+++ b/apps/onlp-demo/src/main/resources/app/view/onlp/onlp.js
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ ONOS GUI -- Onlp View Module
+ */
+
+(function () {
+    'use strict';
+
+    // injected references
+    var $log, $scope, $location, tbs, fs, mast, wss, ns, prefs, is, ps;
+
+    // internal state
+    var nzFilter = true,
+        showDelta = false,
+        pStartY,
+        pHeight,
+        wSize;
+
+    var keyBindings = {
+    };
+
+    var defaultOnlpPrefsState = {
+    };
+
+    var prefsState = {};
+
+    function updatePrefsState(what, b) {
+        prefsState[what] = b ? 1 : 0;
+        prefs.setPrefs('onlp_prefs', prefsState);
+    }
+
+    function restoreConfigFromPrefs() {
+        prefsState = prefs.asNumbers(
+            prefs.getPrefs('onlp_prefs', defaultOnlpPrefsState)
+        );
+
+        $log.debug('ONLP - Prefs State:', prefsState);
+    }
+
+    angular.module('ovOnlp', [])
+        .controller('OvOnlpCtrl', [
+            '$log', '$scope', '$location',
+            'TableBuilderService', 'FnService', 'MastService', 'WebSocketService',
+            'NavService', 'PrefsService', 'IconService',
+            'PanelService',
+
+            function (_$log_, _$scope_, _$location_,
+                      _tbs_, _fs_, _mast_, _wss_,
+                      _ns_, _prefs_, _is_, _ps_) {
+                var params;
+                var tableApi;
+                $log = _$log_;
+                $scope = _$scope_;
+                $location = _$location_;
+                tbs = _tbs_;
+                fs = _fs_;
+                mast = _mast_;
+                wss = _wss_;
+                ns = _ns_;
+                prefs = _prefs_;
+                is = _is_;
+                ps = _ps_;
+
+                params = $location.search();
+
+                $scope.deviceTip = 'Show device table';
+                $scope.flowTip = 'Show flow view for this device';
+                $scope.groupTip = 'Show group view for this device';
+                $scope.meterTip = 'Show meter view for selected device';
+                $scope.pipeconfTip = 'Show pipeconf view for selected device';
+
+                if (params.hasOwnProperty('devId')) {
+                    $scope.devId = params['devId'];
+                }
+
+                $scope.payloadParams = {
+                    nzFilter: nzFilter,
+                    showDelta: showDelta,
+                };
+
+                tableApi = tbs.buildTable({
+                    scope: $scope,
+                    tag: 'onlp',
+                    query: params,
+                });
+
+                function filterToggleState() {
+                    return {
+                        nzFilter: nzFilter,
+                        showDelta: showDelta,
+                    };
+                }
+
+                $scope.nav = function (path) {
+                    if ($scope.devId) {
+                        ns.navTo(path, { devId: $scope.devId });
+                    }
+                };
+
+                function getOperatorFromQuery(query) {
+
+                    var operator = query.split(' '),
+                        opFunc = null;
+
+                    if (operator[0] === '>') {
+                        opFunc = _.gt;
+                    } else if (operator[0] === '>=') {
+                        opFunc = _.gte;
+                    } else if (operator[0] === '<') {
+                        opFunc = _.lt;
+                    } else if (operator[0] === '<=') {
+                        opFunc = _.lte;
+                    } else {
+                        return {
+                            operator: opFunc,
+                            searchText: query,
+                        };
+                    }
+
+                    return {
+                        operator: opFunc,
+                        searchText: operator[1],
+                    };
+                }
+
+                $scope.customFilter = function (prop, val) {
+                    if (!val) {
+                        return;
+                    }
+
+                    var search = getOperatorFromQuery(val),
+                        operator = search.operator,
+                        searchText = search.searchText;
+
+                    if (operator) {
+                        return function (row) {
+                            var queryBy = $scope.queryBy || '$';
+
+                            if (queryBy !== '$') {
+                                var rowValue = parseInt(row[$scope.queryBy].replace(/,/g, ''));
+                                return operator(rowValue, parseInt(searchText)) ? row : null;
+                            } else {
+                                var keys = _.keysIn(row);
+
+                                for (var i = 0, l = keys.length; i < l; i++) {
+                                    var rowValue = parseInt(row[keys[i]].replace(/,/g, ''));
+                                    if (operator(rowValue, parseInt(searchText))) {
+                                        return row;
+                                    }
+                                }
+                            }
+                        };
+                    } else {
+                        var out = {};
+                        out[$scope.queryBy || '$'] = $scope.query;
+                        return out;
+                    }
+                };
+
+                restoreConfigFromPrefs();
+
+                $scope.$on('$destroy', function () {
+                    dps.destroy();
+                });
+
+                $log.log('OvOnlpCtrl has been created');
+            }]);
+}());