KYLIN-1600 diagnosis project & job
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/136a333d Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/136a333d Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/136a333d Branch: refs/heads/1.5.x-HBase1.x Commit: 136a333d3300d1e3cc68faafd117045a816c69cd Parents: a1032bd Author: Jason <jiat...@163.com> Authored: Tue May 3 19:15:44 2016 +0800 Committer: Jason <jiat...@163.com> Committed: Tue May 3 19:23:46 2016 +0800 ---------------------------------------------------------------------- webapp/app/index.html | 2 + webapp/app/js/controllers/admin.js | 13 +- webapp/app/js/controllers/badQuery.js | 68 +++++++ webapp/app/js/controllers/job.js | 22 ++- webapp/app/js/model/jobConfig.js | 11 +- webapp/app/js/services/badQuery.js | 23 +++ webapp/app/partials/admin/admin.html | 278 +++++++++++++++------------- webapp/app/partials/jobs/badQuery.html | 53 ++++++ webapp/app/partials/jobs/jobList.html | 140 ++++++++++++++ webapp/app/partials/jobs/jobs.html | 169 +++-------------- 10 files changed, 498 insertions(+), 281 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/index.html ---------------------------------------------------------------------- diff --git a/webapp/app/index.html b/webapp/app/index.html index e109215..6286667 100644 --- a/webapp/app/index.html +++ b/webapp/app/index.html @@ -160,6 +160,7 @@ <!--New GUI--> <script src="js/model/modelsManager.js"></script> +<script src="js/services/badQuery.js"></script> <script src="js/controllers/page.js"></script> <script src="js/controllers/index.js"></script> @@ -188,6 +189,7 @@ <script src="js/controllers/modelEdit.js"></script> <script src="js/controllers/streamingConfig.js"></script> +<script src="js/controllers/badQuery.js"></script> <!--New GUI--> <script src="js/controllers/models.js"></script> http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/js/controllers/admin.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/admin.js b/webapp/app/js/controllers/admin.js index ac96729..e77729a 100644 --- a/webapp/app/js/controllers/admin.js +++ b/webapp/app/js/controllers/admin.js @@ -18,7 +18,7 @@ 'use strict'; -KylinApp.controller('AdminCtrl', function ($scope, AdminService, CacheService, TableService, loadingRequest, MessageService, $modal, SweetAlert,kylinConfig) { +KylinApp.controller('AdminCtrl', function ($scope, AdminService, CacheService, TableService, loadingRequest, MessageService, $modal, SweetAlert,kylinConfig,ProjectModel,$window) { $scope.configStr = ""; $scope.envStr = ""; @@ -247,6 +247,17 @@ KylinApp.controller('AdminCtrl', function ($scope, AdminService, CacheService, T } }; + $scope.downloadBadQueryFiles = function(){ + var _project = ProjectModel.selectedProject; + if (_project == null){ + SweetAlert.swal('', "No project selected.", 'info'); + return; + } + var downloadUrl = Config.service.url + 'diag/project/'+_project+'/download'; + $window.open(downloadUrl); + } + + $scope.getEnv(); $scope.getConfig(); }); http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/js/controllers/badQuery.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/badQuery.js b/webapp/app/js/controllers/badQuery.js new file mode 100644 index 0000000..65cf65b --- /dev/null +++ b/webapp/app/js/controllers/badQuery.js @@ -0,0 +1,68 @@ +/* + * 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. +*/ + +'use strict'; + +KylinApp + .controller('BadQueryCtrl', function ($scope,BadQueryService, $q, $routeParams, $interval, $modal, ProjectService, MessageService, JobService,SweetAlert,ProjectModel,$window) { + + $scope.badQueryList = []; + + $scope.bqstate={ + loading:true, + filterAttr: 'last_modified', + filterReverse: true, + reverseColumn: 'last_modified' + } + + $scope.list = function(){ + var _project = ProjectModel.selectedProject; + $scope.badQueryList = []; + if (_project == null){ + $scope.bqstate.loading = false; + return; + } + BadQueryService.list({ + entity:_project + }, function (queryList) { + angular.forEach(queryList, function (query) { + $scope.badQueryList.push(query); + }) + $scope.bqstate.loading = false; + }, function (e) { + $scope.bqstate.loading = false; + if (e.data && e.data.exception) { + var message = e.data.exception; + var msg = !!(message) ? message : 'Failed to load query.'; + SweetAlert.swal('Oops...', msg, 'error'); + } else { + SweetAlert.swal('Oops...', "Failed to load query.", 'error'); + } + }); + } + + $scope.list(); + + $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) { + if(newValue!=oldValue||newValue==null){ + $scope.list(); + } + + }); + + }); http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/js/controllers/job.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/controllers/job.js b/webapp/app/js/controllers/job.js index c859c12..ae963c3 100644 --- a/webapp/app/js/controllers/job.js +++ b/webapp/app/js/controllers/job.js @@ -19,7 +19,7 @@ 'use strict'; KylinApp - .controller('JobCtrl', function ($scope, $q, $routeParams, $interval, $modal, ProjectService, MessageService, JobService,SweetAlert,loadingRequest,UserService,jobConfig,JobList) { + .controller('JobCtrl', function ($scope, $q, $routeParams, $interval, $modal, ProjectService, MessageService, JobService,SweetAlert,loadingRequest,UserService,jobConfig,JobList,$window) { $scope.jobList = JobList; JobList.removeAll(); @@ -41,6 +41,17 @@ KylinApp + $scope.tabs=[ + { + "title":"Jobs", + "active":true + }, + { + "title": "Slow Queries", + "active": false + } + ] + // projectName from page ctrl $scope.state = {loading: false, refreshing: false, filterAttr: 'last_modified', filterReverse: true, reverseColumn: 'last_modified', projectName:$scope.projectModel.selectedProject}; @@ -166,6 +177,15 @@ KylinApp }); } + $scope.diagnosisJob =function(job) { + if (!job){ + SweetAlert.swal('', "No job selected.", 'info'); + return; + } + var downloadUrl = Config.service.url + 'diag/job/'+job.uuid+'/download'; + $window.open(downloadUrl); + } + $scope.openModal = function () { if (angular.isDefined($scope.state.selectedStep)) { if ($scope.state.stepAttrToShow == "output") { http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/js/model/jobConfig.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/model/jobConfig.js b/webapp/app/js/model/jobConfig.js index af7044c..ae0a306 100644 --- a/webapp/app/js/model/jobConfig.js +++ b/webapp/app/js/model/jobConfig.js @@ -38,6 +38,15 @@ KylinApp.constant('jobConfig', { {attr: 'progress', name: 'Progress'}, {attr: 'last_modified', name: 'Last Modified Time'}, {attr: 'duration', name: 'Duration'} - ] + ], + queryitems: [ + {attr: 'server', name: 'Server'}, + {attr: 'sql', name: 'Sql'}, + {attr: 'adj', name: 'Description'}, + {attr: 'running_seconds', name: 'Running Seconds'}, + {attr: 'start_time', name: 'Start Time'}, + {attr: 'last_modified', name: 'Last Modified'}, + {attr: 'thread', name: 'Thread'} +] }); http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/js/services/badQuery.js ---------------------------------------------------------------------- diff --git a/webapp/app/js/services/badQuery.js b/webapp/app/js/services/badQuery.js new file mode 100755 index 0000000..7734da1 --- /dev/null +++ b/webapp/app/js/services/badQuery.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +KylinApp.factory('BadQueryService', ['$resource', function ($resource, config) { + return $resource(Config.service.url + 'diag/:entity/:id/:action', {}, { + list: {method: 'GET', params: {action:'sql'}, cache: false, isArray: true} + }); +}]); http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/partials/admin/admin.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/admin/admin.html b/webapp/app/partials/admin/admin.html index 1411978..673187f 100644 --- a/webapp/app/partials/admin/admin.html +++ b/webapp/app/partials/admin/admin.html @@ -17,157 +17,169 @@ --> <div class="container" style="padding-top: 80px"> - <div class="col-md-5"> - <div> - <h3>Server Config <button class="btn btn-xs btn-success" ng-click="getConfig()"><i class="fa fa-refresh"></i></button></h3> - </div> - <div style="padding-top: 10px"> - <pre>{{configStr}}</pre> - </div> + <div class="col-md-5"> + <div> + <h3>Server Config <button class="btn btn-xs btn-success" ng-click="getConfig()"><i class="fa fa-refresh"></i></button></h3> </div> + <div style="padding-top: 10px"> + <pre>{{configStr}}</pre> + </div> + </div> - <div class="col-md-5"> - <div> - <h3>Server Environment <button class="btn btn-xs btn-success" ng-click="getEnv()"><i class="fa fa-refresh"></i></button></h3> - </div> - <div style="padding-top: 10px"> - <pre>{{envStr}}</pre> - </div> + <div class="col-md-5"> + <div> + <h3>Server Environment <button class="btn btn-xs btn-success" ng-click="getEnv()"><i class="fa fa-refresh"></i></button></h3> + </div> + <div style="padding-top: 10px"> + <pre>{{envStr}}</pre> </div> + </div> - <div class="col-md-2"> - <div> - <h3>Actions</h3> - </div> - <div style="padding-top: 10px;width: 180px;"> - <button class="btn btn-primary btn-lg btn-block" ng-click="reloadMeta()"> - <label tooltip="Reload all metadata and clean cache" style="cursor: pointer;">Reload Metadata</label> - </button> - </div> - <div style="padding-top: 10px;width: 180px;"> - <button class="btn btn-primary btn-lg btn-block" ng-click="calCardinality()"> - <label tooltip="Calculate cardinality of tables" style="cursor: pointer;">Calculate Cardinality</label> - </button> - </div> - <div style="padding-top: 10px;width: 180px;" ng-if="false"> - <button class="btn btn-success btn-lg btn-block" ng-click="cleanStorage()"> - <label tooltip="Clean unused HDFS and HBASE space" style="cursor: pointer;">Clean Up Storage</label> - </button> - </div> - <div style="padding-top: 10px;width: 180px;" ng-if="isCacheEnabled()"> - <button class="btn btn-primary btn-lg btn-block" ng-click="disableCache()"> - <label tooltip="Disable Query Cache" style="cursor: pointer;">Disable Cache</label> - </button> - </div> - <div style="padding-top: 10px;width: 180px;" ng-if="!isCacheEnabled()"> - <button class="btn btn-primary btn-lg btn-block" ng-click="enableCache()"> - <label tooltip="Enable Query Cache" style="cursor: pointer;">Enable Cache</label> - </button> - </div> - <div style="padding-top: 10px;width: 180px;"> - <button class="btn btn-primary btn-lg btn-block" ng-click="toSetConfig()"> - <label tooltip="Update Server Config" style="cursor: pointer;">Set Config</label> - </button> - </div> - <div> - <h3>Links</h3> - </div> - <div style="padding-top: 10px" ng-if="config.reference_links['hadoop']"> - <a class="label-lg label-yellow arrowed-right"style="font-size:18px;" tooltip="Cluster Resource Monitoring" href="{{config.reference_links['hadoop'].link}}" > - Hadoop Monitor - </a> - </div> + <div class="col-md-2"> + <div> + <h3>Actions</h3> + </div> + <div style="padding-top: 10px;width: 260px;"> + <!--<button class="btn btn-primary btn-lg btn-block" ng-click="reloadMeta()">--> + <!--<label tooltip="Reload all metadata and clean cache" style="cursor: pointer;">Reload Metadata</label>--> + <!--</button>--> + <a class="btn btn-primary btn-lg btn-block" tooltip="Reload all metadata and clean cache" ng-click="reloadMeta()">Reload Metadata</a> + </div> + <div style="padding-top: 10px;width: 260px;"> + <a ng-click="calCardinality();" tooltip="Calculate cardinality of tables" class="btn btn-primary btn-lg btn-block">Calculate Cardinality</a> + + <!--<button class="btn btn-primary btn-lg btn-block" ng-click="calCardinality()">--> + <!--<label tooltip="Calculate cardinality of tables" style="cursor: pointer;">Calculate Cardinality</label>--> + + <!--</button>--> + </div> + <div style="padding-top: 10px;width: 260px;" ng-if="false"> + <!--<button class="btn btn-success btn-lg btn-block" ng-click="cleanStorage()">--> + <!--<label tooltip="Clean unused HDFS and HBASE space" style="cursor: pointer;">Clean Up Storage</label>--> + <!--</button>--> + <a class="btn btn-success btn-lg btn-block" tooltip="Clean unused HDFS and HBASE space" ng-click="cleanStorage()">Clean Up Storage</a> + </div> + <div style="padding-top: 10px;width: 260px;" ng-if="isCacheEnabled()"> + <!--<button class="btn btn-primary btn-lg btn-block" ng-click="disableCache()">--> + <!--<label tooltip="Disable Query Cache" style="cursor: pointer;">Disable Cache</label>--> + <!--</button>--> + <a class="btn btn-primary btn-lg btn-block" ng-click="disableCache()">Disable Cache</a> + </div> + <div style="padding-top: 10px;width: 260px;" ng-if="!isCacheEnabled()"> + <!--<button class="btn btn-primary btn-lg btn-block" ng-click="enableCache()">--> + <!--<label tooltip="Enable Query Cache" style="cursor: pointer;">Enable Cache</label>--> + <!--</button>--> + <a class="btn btn-primary btn-lg btn-block" tooltip="Enable Query Cache" ng-click="enableCache()">Enable Cache</a> + </div> + <div style="padding-top: 10px;width: 260px;"> + <!--<button class="btn btn-primary btn-lg btn-block" ng-click="toSetConfig()">--> + <!--<label tooltip="Update Server Config" style="cursor: pointer;">Set Config</label>--> + <!--</button>--> + <a class="btn btn-primary btn-lg btn-block" tooltip="Update Server Config" class="btn btn-primary btn-lg" ng-click="toSetConfig()">Set Config</a> + </div> + <div style="padding-top: 10px;width: 260px;"> + <a ng-click="downloadBadQueryFiles();" tooltip="Download selected project Diagnosis Info" class="btn btn-primary btn-lg btn-block"><i class="fa fa-ambulance"></i> Diagnosis</a> + </div> + + <div> + <h3>Links</h3> + </div> + <div style="padding-top: 10px" ng-if="config.reference_links['hadoop']"> + <a class="label-lg label-yellow arrowed-right"style="font-size:18px;" tooltip="Cluster Resource Monitoring" href="{{config.reference_links['hadoop'].link}}" > + Hadoop Monitor + </a> </div> + </div> </div> <script type="text/ng-template" id="calCardinality.html"> - <div class="modal-header"> - <h4>Load Hive Table Metadata</h4> - </div> - <div class="modal-body load-hive-metawrapper"> - <label for="table">Table Name:</label> - <input ng-model="$parent.tableName" class="form-control" id="table" placeholder="table1,table2"/> - <label>Delimiter:</label> + <div class="modal-header"> + <h4>Load Hive Table Metadata</h4> + </div> + <div class="modal-body load-hive-metawrapper"> + <label for="table">Table Name:</label> + <input ng-model="$parent.tableName" class="form-control" id="table" placeholder="table1,table2"/> + <label>Delimiter:</label> - <div class="radio"> - <label> - <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="0">default - -- System will try to get the format from hive metadata, if you are not sure, please choose the - "default". - </label> - </div> - <div class="radio"> - <label> - <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="1">\177 - </label> - </div> - <div class="radio"> - <label> - <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="2">tab - </label> - </div> - <label>Format:</label> + <div class="radio"> + <label> + <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="0">default + -- System will try to get the format from hive metadata, if you are not sure, please choose the + "default". + </label> + </div> + <div class="radio"> + <label> + <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="1">\177 + </label> + </div> + <div class="radio"> + <label> + <input type="radio" name="deliRadios" data-ng-model="$parent.delimiter" ng-value="2">tab + </label> + </div> + <label>Format:</label> - <div class="radio"> - <label> - <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="0">default - -- System will try to get the format from hive metadata, if you are not sure, please choose the - "default". - </label> - </div> - <div class="radio"> - <label> - <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="1">text - </label> - </div> - <div class="radio"> - <label> - <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="2">sequence - </label> - </div> + <div class="radio"> + <label> + <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="0">default + -- System will try to get the format from hive metadata, if you are not sure, please choose the + "default". + </label> </div> - <div class="modal-footer"> - <button class="btn btn-primary" ng-click="calculate()">Sync</button> - <button class="btn btn-primary" ng-click="cancel()">Cancel</button> + <div class="radio"> + <label> + <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="1">text + </label> + </div> + <div class="radio"> + <label> + <input type="radio" name="formatRadios" data-ng-model="$parent.format" ng-value="2">sequence + </label> </div> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" ng-click="calculate()">Sync</button> + <button class="btn btn-primary" ng-click="cancel()">Cancel</button> + </div> </script> <script type="text/ng-template" id="updateConfig.html"> - <ng-form name="config_update_form"> - <div class="modal-header"> - <h4>Update Config</h4> - </div> - <div class="modal-body"> - <div class="form-group"> - <label><b>Key</b></label> + <ng-form name="config_update_form"> + <div class="modal-header"> + <h4>Update Config</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label><b>Key</b></label> - <div class="clearfix"> - <input name="key_input" type="text" class="form-control" placeholder="Config Key.." - ng-model="state.key" - required/> + <div class="clearfix"> + <input name="key_input" type="text" class="form-control" placeholder="Config Key.." + ng-model="state.key" + required/> - <p class="text-warning" - ng-show="config_update_form.key_input.$invalid && !config_update_form.key_input.$pristine"> Key - is required.</p> - </div> - </div> - <div class="form-group"> - <label><b>Value</b></label> + <p class="text-warning" + ng-show="config_update_form.key_input.$invalid && !config_update_form.key_input.$pristine"> Key + is required.</p> + </div> + </div> + <div class="form-group"> + <label><b>Value</b></label> - <div class="clearfix"> - <input name="value_input" type="text" class="form-control" placeholder="Config Value.." - ng-model="state.value" - required/> + <div class="clearfix"> + <input name="value_input" type="text" class="form-control" placeholder="Config Value.." + ng-model="state.value" + required/> - <p class="text-warning" - ng-show="config_update_form.value_input.$invalid && !config_update_form.value_input.$pristine"> Value - is required.</p> - </div> - </div> - </div> - <div class="modal-footer"> - <button class="btn btn-primary" ng-click="update()">Update</button> - <button class="btn btn-primary" ng-click="cancel()">Cancel</button> + <p class="text-warning" + ng-show="config_update_form.value_input.$invalid && !config_update_form.value_input.$pristine"> Value + is required.</p> </div> - </ng-form> + </div> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" ng-click="update()">Update</button> + <button class="btn btn-primary" ng-click="cancel()">Cancel</button> + </div> + </ng-form> </script> http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/partials/jobs/badQuery.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/jobs/badQuery.html b/webapp/app/partials/jobs/badQuery.html new file mode 100644 index 0000000..73806a7 --- /dev/null +++ b/webapp/app/partials/jobs/badQuery.html @@ -0,0 +1,53 @@ + +<div class="row" style="margin-top:15px;" ng-controller="BadQueryCtrl"> + + <!--No Job--> + <div ng-if="!bqstate.loading && badQueryList.length==0"> + <div ng-if="projectModel.selectedProject==null" no-result text="No project selected"></div> + <div ng-if="projectModel.selectedProject!==null" no-result text="No Slow Query."></div> + </div> + <!--Loading Jobs--> + <div ng-if="bqstate.loading"> + <loading text="Loading Queries ..."></loading> + </div> + <!--Jobs Table Content--> + <table ng-if="badQueryList.length>0" class="table table-striped table-bordered table-hover dataTable no-footer"> + <thead> + <tr style="cursor: pointer"> + <th ng-repeat="queryitem in jobConfig.queryitems" + ng-click="bqstate.filterAttr= queryitem.attr;bqstate.reverseColumn=queryitem.attr;bqstate.filterReverse=!bqstate.filterReverse; "> + {{queryitem.name}} + <i ng-if="bqstate.reverseColumn!= queryitem.attr" + class="fa fa-unsorted"></i> + <i ng-if="bqstate.reverseColumn== queryitem.attr && !bqstate.filterReverse" + class="fa fa-sort-asc"></i> + <i ng-if="bqstate.reverseColumn== queryitem.attr && bqstate.filterReverse" + class="fa fa-sort-desc"></i> + </th> + </tr> + </thead> + <tbody class="odd table table-striped table-bordered table-hover dataTable no-footer"> + <tr + ng-repeat="bquery in badQueryList | orderObjectBy:bqstate.filterAttr:bqstate.filterReverse" + ng-class="{accordion:true}" ng-click="bqstate.selectedQuery = bquery" + style="cursor: pointer" + class="{{bquery==bqstate.selectedQuery? 'tr-highlight': ''}} table-bordered"> + <td style="max-width: 350px;word-wrap: break-word;word-break: normal;"> + {{bquery.server}} + </td> + <td>{{bquery.sql}}</td> + <td> + {{bquery.adj}} + </td> + <td>{{bquery.running_seconds + '(s)'}}</td> + <td>{{bquery.start_time |utcToConfigTimeZone}}</td> + <td> + {{bquery.last_modified |utcToConfigTimeZone}} + </td> + <td> + {{bquery.thread}} + </td> + </tr> + </tbody> + </table> +</div> http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/partials/jobs/jobList.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/jobs/jobList.html b/webapp/app/partials/jobs/jobList.html new file mode 100644 index 0000000..366a1bf --- /dev/null +++ b/webapp/app/partials/jobs/jobList.html @@ -0,0 +1,140 @@ +<!--Jobs Table--> +<div class="row" style="margin-top:15px;" ng-controller="JobCtrl"> + + <div ng-class="{'col-xs-8': state.showSteps, 'col-xs-12': !state.showSteps}"> + <div class="dataTables_wrapper form-inline no-footer" > + <!--Jobs Table Header--> + <div class="row"> + + <!--Cube Name: --> + <div class="col-xs-3"> + <form class="" ng-submit="jobList.removeAll();reload()" style="display: inline" > + <span class="input-icon input-icon-right nav-search" style="font-size:14px;"><b>Cube Name:</b> + <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="cubeName" /> + <i class="ace-icon fa fa-search blue" ng-click="jobList.removeAll();reload()"></i> + </span> + </form> + </div> + + <!--<div class="col-xs-2"><label class="table-header-text">Jobs</label></div>--> + <div class="col-xs-9"> + <!--STATUS--> + <div class="pull-right"> + <!--Job History Time Filter--> + <label>Jobs in: + <select data-ng-model="timeFilter" + data-ng-options="s.name for s in jobConfig.timeFilter"> + </select> + </label> + <label ng-repeat="s in jobConfig.allStatus" class="checkbox-inline" > + <input type="checkbox" + value="{{s.name}}" + ng-checked="status.indexOf(s) > -1" + ng-click="toggleSelection(s);" />{{s.name}} + </label> + <!--Refresh Jobs--> + <button class="btn btn-success btn-xs" style="margin-left: 10px" ng-click="jobList.removeAll();reload();"><i class="fa fa-refresh"></i></button> + </div> + </div> + </div> + <!--No Job--> + <div ng-if="!state.loading && getLength(jobList.jobs)==0"> + <div no-result text="No Job."></div> + </div> + <!--Loading Jobs--> + <div ng-if="state.loading"> + <loading text="Loading Jobs ..."></loading> + </div> + <!--Jobs Table Content--> + <table ng-if="getLength(jobList.jobs)>0" class="table table-striped table-bordered table-hover dataTable no-footer"> + <thead> + <tr style="cursor: pointer"> + <th ng-repeat="theaditem in jobConfig.theaditems" + ng-click="state.filterAttr= theaditem.attr;state.reverseColumn=theaditem.attr;state.filterReverse=!state.filterReverse; "> + {{theaditem.name}} + <i ng-if="state.reverseColumn!= theaditem.attr" + class="fa fa-unsorted"></i> + <i ng-if="state.reverseColumn== theaditem.attr && !state.filterReverse" + class="fa fa-sort-asc"></i> + <i ng-if="state.reverseColumn== theaditem.attr && state.filterReverse" + class="fa fa-sort-desc"></i> + </th> + <th>Actions</th> + <th></th> + </tr> + </thead> + <tbody class="odd table table-striped table-bordered table-hover dataTable no-footer"> + <tr + ng-repeat="(uuid,job) in jobList.jobs | orderObjectBy:state.filterAttr:state.filterReverse" + ng-class="{accordion:true}" ng-click="state.selectedJob = job" + ng-dblclick="state.showSteps= !state.showSteps; state.selectedJob = job" + style="cursor: pointer" + class="{{job==state.selectedJob? 'tr-highlight': ''}} table-bordered"> + <td style="max-width: 350px;word-wrap: break-word;word-break: normal;"> + {{ job.name}} + </td> + <td>{{ job.related_cube}}</td> + <td> + <div ng-switch on="job.job_status"> + <div ng-switch-when="ERROR" tooltip="ERROR"> + <progressbar class="progress-striped" value="job.progress" type="danger"> + {{job.job_status}} + </progressbar> + </div> + <div ng-switch-when="FINISHED" tooltip="FINISHED"> + <progressbar class="progress-striped" value="job.progress" type="success"> + {{job.progress}}% + </progressbar> + </div> + <div ng-switch-when="PENDING" tooltip="PENDING"> + <progressbar class="progress-striped active" value="job.progress" + type="pending">{{job.job_status}} + </progressbar> + </div> + <div ng-switch-when="RUNNING" tooltip="RUNNING"> + <progressbar class="progress-striped active" value="job.progress" + type="info">{{job.progress | number:2}}% + </progressbar> + </div> + <div ng-switch-when="DISCARDED" tooltip="DISCARDED"> + <progressbar class="progress-striped" value="job.progress" type="inverse"> + {{job.progress | number:2}}% + </progressbar> + </div> + </div> + </td> + <td>{{ job.last_modified == 0 ? '' : (job.last_modified |utcToConfigTimeZone)}}</td> + <td>{{(job.duration/60 | number:2) + ' mins'}}</td> + <td> + <div class="btn-group" + ng-if="job.job_status!='DISCARDED' && job.job_status!='FINISHED'"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" + data-toggle="dropdown"> + Action <span class="ace-icon fa fa-caret-down icon-on-right"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li ng-if="job.job_status=='ERROR'"><a ng-click="resume(job)">Resume</a></li> + <li ng-if="job.job_status=='RUNNING' || job.job_status=='NEW' || job.job_status=='PENDING' || job.job_status=='ERROR'"> + <a ng-click="cancel(job)">Discard</a> + <a ng-click="diagnosisJob(job)">Diagnosis</a> + </li> + </ul> + </div> + <span ng-if="job.job_status=='DISCARDED' || job.job_status=='FINISHED'">N/A</span> + </td> + <td> + <button class="btn btn-info btn-xs" ng-click="state.showSteps= !state.showSteps; state.selectedJob = job"> + <i class="fa fa-chevron-circle-right"></i> + </button> + </td> + </tr> + </tbody> + </table> + </div> + + <kylin-pagination data="jobList.jobs" load-func="list" action="action"/> + </div> + <div class="col-xs-4" ng-if="state.showSteps"> + <div ng-include src="'partials/jobs/job_steps.html'"></div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/kylin/blob/136a333d/webapp/app/partials/jobs/jobs.html ---------------------------------------------------------------------- diff --git a/webapp/app/partials/jobs/jobs.html b/webapp/app/partials/jobs/jobs.html index cc5840b..e2aa3f4 100644 --- a/webapp/app/partials/jobs/jobs.html +++ b/webapp/app/partials/jobs/jobs.html @@ -17,154 +17,33 @@ --> <div class="page-header row"> - <!--Project: --> - <div class="col-xs-3"> - <form ng-if="userService.isAuthorized()"> - <div class="form-group" ng-if="userService.hasRole('ROLE_MODELER')" > - <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a> - <a class="btn btn-xs btn-primary" ng-if="userService.hasRole('ROLE_MODELER')" style="width: 29px" tooltip="Add Project" ng-click="toCreateProj()"> - <i class="fa fa-plus"></i> - </a> - </div> - </form> - </div> - <!--Cube Name: --> - <div class="col-xs-3"> - <form class="" ng-submit="jobList.removeAll();reload()" style="display: inline" > - <span class="input-icon input-icon-right nav-search" style="font-size:14px;"><b>Cube Name:</b> - <input type="text" placeholder="Filter ..." class="nav-search-input" ng-model="cubeName" /> - <i class="ace-icon fa fa-search blue" ng-click="jobList.removeAll();reload()"></i> - </span> - </form> - </div> + <!--Project: --> + <div class="col-xs-3"> + <form ng-if="userService.isAuthorized()"> + <div class="form-group" ng-if="userService.hasRole('ROLE_MODELER')" > + <a class="btn btn-xs btn-info" href="projects" tooltip="Manage Project"><i class="fa fa-gears"></i></a> + <a class="btn btn-xs btn-primary" ng-if="userService.hasRole('ROLE_MODELER')" style="width: 29px" tooltip="Add Project" ng-click="toCreateProj()"> + <i class="fa fa-plus"></i> + </a> + </div> + </form> + </div> </div> -<!--Jobs Table--> -<div class="row"> - <div ng-class="{'col-xs-8': state.showSteps, 'col-xs-12': !state.showSteps}"> - <div class="dataTables_wrapper form-inline no-footer" > - <!--Jobs Table Header--> - <div class="row"> - <div class="col-xs-2"><label class="table-header-text">Jobs</label></div> - <div class="col-xs-10"> - <!--STATUS--> - <div class="pull-right"> - <!--Job History Time Filter--> - <label>Jobs in: - <select data-ng-model="timeFilter" - data-ng-options="s.name for s in jobConfig.timeFilter"> - </select> - </label> - <label ng-repeat="s in jobConfig.allStatus" class="checkbox-inline" > - <input type="checkbox" - value="{{s.name}}" - ng-checked="status.indexOf(s) > -1" - ng-click="toggleSelection(s);" />{{s.name}} - </label> - <!--Refresh Jobs--> - <button class="btn btn-success btn-xs" style="margin-left: 10px" ng-click="jobList.removeAll();reload();"><i class="fa fa-refresh"></i></button> - </div> - </div> - </div> - <!--No Job--> - <div ng-if="!state.loading && getLength(jobList.jobs)==0"> - <div no-result text="No Job."></div> - </div> - <!--Loading Jobs--> - <div ng-if="state.loading"> - <loading text="Loading Jobs ..."></loading> - </div> - <!--Jobs Table Content--> - <table ng-if="getLength(jobList.jobs)>0" class="table table-striped table-bordered table-hover dataTable no-footer"> - <thead> - <tr style="cursor: pointer"> - <th ng-repeat="theaditem in jobConfig.theaditems" - ng-click="state.filterAttr= theaditem.attr;state.reverseColumn=theaditem.attr;state.filterReverse=!state.filterReverse; "> - {{theaditem.name}} - <i ng-if="state.reverseColumn!= theaditem.attr" - class="fa fa-unsorted"></i> - <i ng-if="state.reverseColumn== theaditem.attr && !state.filterReverse" - class="fa fa-sort-asc"></i> - <i ng-if="state.reverseColumn== theaditem.attr && state.filterReverse" - class="fa fa-sort-desc"></i> - </th> - <th>Actions</th> - <th></th> - </tr> - </thead> - <tbody class="odd table table-striped table-bordered table-hover dataTable no-footer"> - <tr - ng-repeat="(uuid,job) in jobList.jobs | orderObjectBy:state.filterAttr:state.filterReverse" - ng-class="{accordion:true}" ng-click="state.selectedJob = job" - ng-dblclick="state.showSteps= !state.showSteps; state.selectedJob = job" - style="cursor: pointer" - class="{{job==state.selectedJob? 'tr-highlight': ''}} table-bordered"> - <td style="max-width: 350px;word-wrap: break-word;word-break: normal;"> - {{ job.name}} - </td> - <td>{{ job.related_cube}}</td> - <td> - <div ng-switch on="job.job_status"> - <div ng-switch-when="ERROR" tooltip="ERROR"> - <progressbar class="progress-striped" value="job.progress" type="danger"> - {{job.job_status}} - </progressbar> - </div> - <div ng-switch-when="FINISHED" tooltip="FINISHED"> - <progressbar class="progress-striped" value="job.progress" type="success"> - {{job.progress}}% - </progressbar> - </div> - <div ng-switch-when="PENDING" tooltip="PENDING"> - <progressbar class="progress-striped active" value="job.progress" - type="pending">{{job.job_status}} - </progressbar> - </div> - <div ng-switch-when="RUNNING" tooltip="RUNNING"> - <progressbar class="progress-striped active" value="job.progress" - type="info">{{job.progress | number:2}}% - </progressbar> - </div> - <div ng-switch-when="DISCARDED" tooltip="DISCARDED"> - <progressbar class="progress-striped" value="job.progress" type="inverse"> - {{job.progress | number:2}}% - </progressbar> - </div> - </div> - </td> - <td>{{ job.last_modified == 0 ? '' : (job.last_modified |utcToConfigTimeZone)}}</td> - <td>{{(job.duration/60 | number:2) + ' mins'}}</td> - <td> - <div class="btn-group" - ng-if="job.job_status!='DISCARDED' && job.job_status!='FINISHED'"> - <button type="button" class="btn btn-default btn-xs dropdown-toggle" - data-toggle="dropdown"> - Action <span class="ace-icon fa fa-caret-down icon-on-right"></span> - </button> - <ul class="dropdown-menu" role="menu"> - <li ng-if="job.job_status=='ERROR'"><a ng-click="resume(job)">Resume</a></li> - <li ng-if="job.job_status=='RUNNING' || job.job_status=='NEW' || job.job_status=='PENDING' || job.job_status=='ERROR'"> - <a ng-click="cancel(job)">Discard</a> - </li> - </ul> - </div> - <span ng-if="job.job_status=='DISCARDED' || job.job_status=='FINISHED'">N/A</span> - </td> - <td> - <button class="btn btn-info btn-xs" ng-click="state.showSteps= !state.showSteps; state.selectedJob = job"> - <i class="fa fa-chevron-circle-right"></i> - </button> - </td> - </tr> - </tbody> - </table> - </div> - <kylin-pagination data="jobList.jobs" load-func="list" action="action"/> - </div> - <div class="col-xs-4" ng-if="state.showSteps"> - <div ng-include src="'partials/jobs/job_steps.html'"></div> - </div> +<div class="row models-main dataTables_wrapper" style="padding-top:10px;padding-left: 5px;"> + <div ng-class="row"> + <tabset> + <tab heading="Jobs" select="jobTabSelected('jobs')" active="tabs[2].active"> + <div class="col-xs-12" ng-include src="'partials/jobs/jobList.html'"></div> + </tab> + <tab heading="Slow Queries" select="jobTabSelected('query')" active="tabs[1].active"> + <div class="col-xs-12" ng-include src="'partials/jobs/badQuery.html'"></div> + </tab> + </tabset> + </div> </div> + + <div ng-include="'partials/projects/project_create.html'"></div>