http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js index 5f24eb7..d3274ae 100644 --- a/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js +++ b/modules/web-console/frontend/app/modules/form/validator/java-package-specified.directive.js @@ -22,9 +22,13 @@ export default ['javaPackageSpecified', ['JavaTypes', (JavaTypes) => { const allowBuiltIn = attrs.javaPackageSpecified === 'allow-built-in'; - ngModel.$validators.javaPackageSpecified = (value) => _.isEmpty(value) || + ngModel.$validators.javaPackageSpecified = (value) => attrs.validationActive === 'false' || + _.isEmpty(value) || !JavaTypes.validClassName(value) || JavaTypes.packageSpecified(value) || (allowBuiltIn && !JavaTypes.nonBuiltInClass(value)); + + if (attrs.validationActive !== 'always') + attrs.$observe('validationActive', () => ngModel.$validate()); }; return {
http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/nodes/Nodes.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/nodes/Nodes.service.js b/modules/web-console/frontend/app/modules/nodes/Nodes.service.js new file mode 100644 index 0000000..b320ae4 --- /dev/null +++ b/modules/web-console/frontend/app/modules/nodes/Nodes.service.js @@ -0,0 +1,69 @@ +/* + * 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. + */ + +import nodesDialogTemplate from './nodes-dialog.jade'; + +const DEFAULT_OPTIONS = { + grid: { + multiSelect: false + } +}; + +class Nodes { + static $inject = ['$q', '$modal']; + + /** + * @param $q + * @param $modal + */ + constructor($q, $modal) { + this.$q = $q; + this.$modal = $modal; + } + + selectNode(nodes, cacheName, options = DEFAULT_OPTIONS) { + const { $q, $modal } = this; + const defer = $q.defer(); + options.target = cacheName; + + const modalInstance = $modal({ + templateUrl: nodesDialogTemplate, + show: true, + resolve: { + nodes: () => nodes || [], + options: () => options + }, + placement: 'center', + controller: 'nodesDialogController', + controllerAs: '$ctrl' + }); + + modalInstance.$scope.$ok = (data) => { + defer.resolve(data); + modalInstance.$scope.$hide(); + }; + + modalInstance.$scope.$cancel = () => { + defer.reject(); + modalInstance.$scope.$hide(); + }; + + return defer.promise; + } +} + +export default Nodes; http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/nodes/nodes-dialog.controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/nodes/nodes-dialog.controller.js b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.controller.js new file mode 100644 index 0000000..3e588ac --- /dev/null +++ b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.controller.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. + */ + +const NID_TEMPLATE = '<div class="ui-grid-cell-contents" title="{{ COL_FIELD }}">{{ COL_FIELD | limitTo:8 }}</div>'; + +const COLUMNS_DEFS = [ + {displayName: 'Node ID8', field: 'nid', headerTooltip: 'Node ID8', cellTemplate: NID_TEMPLATE, minWidth: 85, width: 85, pinnedLeft: true}, + {displayName: 'Node IP', field: 'ip', headerTooltip: 'Primary IP address of node', minWidth: 75, width: 120}, + {displayName: 'Grid name', field: 'gridName', headerTooltip: 'Name of node grid cluster', minWidth: 75, width: 120}, + {displayName: 'Version', field: 'version', headerTooltip: 'Node version', minWidth: 75, width: 140}, + {displayName: 'OS information', field: 'os', headerTooltip: 'OS information for node\'s host', minWidth: 125} +]; + +export default ['$scope', '$animate', 'uiGridConstants', 'nodes', 'options', function($scope, $animate, uiGridConstants, nodes, options) { + const $ctrl = this; + + const updateSelected = () => { + const nids = $ctrl.gridApi.selection.getSelectedRows().map((node) => node.nid).sort(); + + if (!_.isEqual(nids, $ctrl.selected)) + $ctrl.selected = nids; + }; + + $ctrl.nodes = nodes; + $ctrl.options = options; + $ctrl.selected = []; + + $ctrl.gridOptions = { + data: nodes, + columnVirtualizationThreshold: 30, + columnDefs: COLUMNS_DEFS, + enableRowSelection: true, + enableRowHeaderSelection: false, + enableColumnMenus: false, + multiSelect: true, + modifierKeysToMultiSelect: true, + noUnselect: false, + flatEntityAccess: true, + fastWatch: true, + onRegisterApi: (api) => { + $animate.enabled(api.grid.element, false); + + $ctrl.gridApi = api; + + api.selection.on.rowSelectionChanged($scope, updateSelected); + api.selection.on.rowSelectionChangedBatch($scope, updateSelected); + + $ctrl.gridApi.grid.element.css('height', '270px'); + + setTimeout(() => $ctrl.gridApi.core.notifyDataChange(uiGridConstants.dataChange.COLUMN), 300); + }, + ...options.grid + }; +}]; http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/nodes/nodes-dialog.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/nodes/nodes-dialog.jade b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.jade new file mode 100644 index 0000000..d9ea68c --- /dev/null +++ b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.jade @@ -0,0 +1,35 @@ +//- + 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. + +.modal.ignite-nodes-dialog(tabindex='-1' role='dialog') + .modal-dialog + .modal-content + .modal-header + button.close(ng-click='$cancel()' aria-hidden='true') × + h4.modal-title Select Node + .modal-body.modal-body-with-scroll + p Choose node to execute query for cache: #[strong {{ $ctrl.options.target }}] + + .panel.panel-default.nodes-grid + .panel-heading + label Cache Nodes: {{ $ctrl.nodes.length }} + + .panel-body.panel-body_collapse + .grid(ui-grid='$ctrl.gridOptions' ui-grid-resize-columns ui-grid-selection ui-grid-pinning) + + .modal-footer + button.btn.btn-primary(id='confirm-btn-confirm' ng-click='$ok($ctrl.selected)' ng-disabled='$ctrl.selected.length === 0') Select node + button.btn.btn-default(id='confirm-btn-close' ng-click='$cancel()') Cancel http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/nodes/nodes-dialog.scss ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/nodes/nodes-dialog.scss b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.scss new file mode 100644 index 0000000..0c65e54 --- /dev/null +++ b/modules/web-console/frontend/app/modules/nodes/nodes-dialog.scss @@ -0,0 +1,20 @@ +.ignite-nodes-dialog { + label { + font-size: 18px; + margin-right: 20px; + } + + .ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-cell:last-child, + .ui-grid-pinned-container.ui-grid-pinned-container-left .ui-grid-header-cell:last-child, + .ui-grid-header-cell:last-child .ui-grid-column-resizer.right { + //border-right: none; + } + + .nodes-grid { + height: 320px; + } + .panel-body_collapse { + padding: 0; + margin: 0; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/nodes/nodes.module.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/nodes/nodes.module.js b/modules/web-console/frontend/app/modules/nodes/nodes.module.js new file mode 100644 index 0000000..4e68b39 --- /dev/null +++ b/modules/web-console/frontend/app/modules/nodes/nodes.module.js @@ -0,0 +1,27 @@ +/* + * 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. + */ + +import angular from 'angular'; + +import './nodes-dialog.scss'; + +import Nodes from './Nodes.service'; +import nodesDialogController from './nodes-dialog.controller'; + +angular.module('ignite-console.nodes', []) + .service('IgniteNodes', Nodes) + .controller('nodesDialogController', nodesDialogController); http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/sql/sql.controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/sql/sql.controller.js b/modules/web-console/frontend/app/modules/sql/sql.controller.js index 92eb7be..0c2be01 100644 --- a/modules/web-console/frontend/app/modules/sql/sql.controller.js +++ b/modules/web-console/frontend/app/modules/sql/sql.controller.js @@ -27,6 +27,8 @@ const SCAN_CACHE_WITH_FILTER = 'VISOR_SCAN_CACHE_WITH_FILTER'; /** Prefix for node local key for SCAN near queries. */ const SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE = 'VISOR_SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE'; +const NON_COLLOCATED_JOINS_SINCE = '1.7.0'; + const _fullColName = (col) => { const res = []; @@ -51,6 +53,25 @@ class Paragraph { _.assign(this, paragraph); + const _enableColumns = (categories, visible) => { + _.forEach(categories, (cat) => { + cat.visible = visible; + + _.forEach(this.gridOptions.columnDefs, (col) => { + if (col.displayName === cat.name) + col.visible = visible; + }); + }); + + this.gridOptions.api.grid.refresh(); + }; + + const _selectableColumns = () => _.filter(this.gridOptions.categories, (cat) => cat.selectable); + + this.toggleColumns = (category, visible) => _enableColumns([category], visible); + this.selectAllColumns = () => _enableColumns(_selectableColumns(), true); + this.clearAllColumns = () => _enableColumns(_selectableColumns(), false); + Object.defineProperty(this, 'gridOptions', {value: { enableGridMenu: false, enableColumnMenus: false, @@ -60,6 +81,7 @@ class Paragraph { if (_.isNil(this.api)) return; + this.categories = []; this.columnDefs = _.reduce(self.meta, (cols, col, idx) => { if (self.columnFilter(col)) { cols.push({ @@ -69,6 +91,12 @@ class Paragraph { minWidth: 50, cellClass: 'cell-left' }); + + this.categories.push({ + name: col.fieldName, + visible: true, + selectable: true + }); } return cols; @@ -133,7 +161,7 @@ class Paragraph { } queryExecuted() { - return !_.isEmpty(this.meta); + return !_.isEmpty(this.meta) || !_.isEmpty(this.errMsg); } scanExplain() { @@ -154,8 +182,8 @@ class Paragraph { } // Controller for SQL notebook screen. -export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteAgentMonitor', 'IgniteChartColors', 'IgniteNotebook', 'IgniteScanFilterInput', 'uiGridExporterConstants', - function($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMonitor, IgniteChartColors, Notebook, ScanFilterInput, uiGridExporterConstants) { +export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'IgniteAgentMonitor', 'IgniteChartColors', 'IgniteNotebook', 'IgniteScanFilterInput', 'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', + function($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMonitor, IgniteChartColors, Notebook, ScanFilterInput, Nodes, uiGridExporterConstants, Version) { let stopTopology = null; const _tryStopRefresh = function(paragraph) { @@ -212,7 +240,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', } }; - $scope.maskCacheName = (cacheName) => _.isEmpty(cacheName) ? '<default>' : cacheName; + const maskCacheName = $filter('defaultName'); // We need max 1800 items to hold history for 30 mins in case of refresh every second. const HISTORY_LENGTH = 1800; @@ -781,24 +809,30 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', * @private */ const _refreshFn = () => - agentMonitor.topology() - .then((clusters) => { - $scope.caches = _.sortBy(_.reduce(clusters, (items, cluster) => { - _.forEach(cluster.caches, (cache) => { - let item = _.find(items, {name: cache.name}); + agentMonitor.topology(true) + .then((nodes) => { + $scope.caches = _.sortBy(_.reduce(nodes, (cachesAcc, node) => { + _.forEach(node.caches, (cache) => { + let item = _.find(cachesAcc, {name: cache.name}); if (_.isNil(item)) { - cache.label = $scope.maskCacheName(cache.name); + cache.label = maskCacheName(cache.name); - cache.nodeIds = []; + cache.nodes = []; - items.push(item = cache); + cachesAcc.push(item = cache); } - item.nodeIds.push(cluster.nodeId); + item.nodes.push({ + nid: node.nodeId.toUpperCase(), + ip: _.head(node.attributes['org.apache.ignite.ips'].split(', ')), + version: node.attributes['org.apache.ignite.build.ver'], + gridName: node.attributes['org.apache.ignite.ignite.name'], + os: `${node.attributes['os.name']} ${node.attributes['os.arch']} ${node.attributes['os.version']}` + }); }); - return items; + return cachesAcc; }, []), 'label'); if (_.isEmpty($scope.caches)) @@ -830,7 +864,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', .then(_refreshFn) .then(() => Loading.finish('sqlLoading')) .then(() => { - $root.IgniteDemoMode && _.forEach($scope.notebook.paragraphs, $scope.execute); + $root.IgniteDemoMode && _.forEach($scope.notebook.paragraphs, (paragraph) => $scope.execute(paragraph)); stopTopology = $interval(_refreshFn, 5000, 0, false); }); @@ -1072,7 +1106,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', paragraph.gridOptions.rebuildColumns(); paragraph.chartColumns = _.reduce(paragraph.meta, (acc, col, idx) => { - if (paragraph.columnFilter(col) && _notObjectType(col.fieldTypeName)) { + if (_notObjectType(col.fieldTypeName)) { acc.push({ label: col.fieldName, type: col.fieldTypeName, @@ -1100,8 +1134,6 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', if (paragraph.disabledSystemColumns) return; - paragraph.systemColumns = !paragraph.systemColumns; - paragraph.columnFilter = _columnFilter(paragraph); paragraph.chartColumns = []; @@ -1113,10 +1145,11 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', /** * @param {Object} paragraph Query + * @param {Boolean} clearChart Flag is need clear chart model. * @param {{columns: Array, rows: Array, responseNodeId: String, queryId: int, hasMore: Boolean}} res Query results. * @private */ - const _processQueryResult = (paragraph, res) => { + const _processQueryResult = (paragraph, clearChart, res) => { const prevKeyCols = paragraph.chartKeyCols; const prevValCols = paragraph.chartValCols; @@ -1131,11 +1164,12 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', if (!LegacyUtils.isDefined(paragraph.chartValCols)) paragraph.chartValCols = []; - if (res.columns.length <= 2) { + if (res.columns.length) { const _key = _.find(res.columns, {fieldName: '_KEY'}); const _val = _.find(res.columns, {fieldName: '_VAL'}); - paragraph.disabledSystemColumns = (res.columns.length === 2 && _key && _val) || + paragraph.disabledSystemColumns = !(_key && _val) || + (res.columns.length === 2 && _key && _val) || (res.columns.length === 1 && (_key || _val)); } @@ -1175,12 +1209,8 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', const chartHistory = paragraph.chartHistory; - // Clear history on query change. - const queryChanged = paragraph.prevQuery !== paragraph.query; - - if (queryChanged) { - paragraph.prevQuery = paragraph.query; - + // Clear history on query change. + if (clearChart) { chartHistory.length = 0; _.forEach(paragraph.charts, (chart) => chart.data.length = 0); @@ -1198,7 +1228,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', if (_.isNil(paragraph.result) || paragraph.result === 'none' || paragraph.scanExplain()) paragraph.result = 'table'; else if (paragraph.chart()) { - let resetCharts = queryChanged; + let resetCharts = clearChart; if (!resetCharts) { const curKeyCols = paragraph.chartKeyCols; @@ -1214,15 +1244,34 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', }; const _closeOldQuery = (paragraph) => { - const queryId = paragraph.queryArgs && paragraph.queryArgs.queryId; + if (paragraph.queryId) + return agentMonitor.queryClose(paragraph.resNodeId, paragraph.queryId); - return queryId ? agentMonitor.queryClose(queryId) : $q.when(); + return $q.when(); }; - const cacheNode = (name) => { - const cache = _.find($scope.caches, {name}); + /** + * @param {String} name Cache name. + * @return {Array.<String>} Nids + */ + const cacheNodes = (name) => { + return _.find($scope.caches, {name}).nodes; + }; + + /** + * @param {String} name Cache name. + * @param {Boolean} local Local query. + * @return {String} Nid + */ + const _chooseNode = (name, local) => { + const nodes = cacheNodes(name); + + if (local) { + return Nodes.selectNode(nodes, name) + .then((selectedNids) => _.head(selectedNids)); + } - return cache.nodeIds[_.random(0, cache.nodeIds.length - 1)]; + return Promise.resolve(nodes[_.random(0, nodes.length - 1)].nid); }; const _executeRefresh = (paragraph) => { @@ -1230,8 +1279,9 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', agentMonitor.awaitAgent() .then(() => _closeOldQuery(paragraph)) - .then(() => agentMonitor.query(cacheNode(args.cacheName), args.cacheName, args.query, false, args.pageSize)) - .then(_processQueryResult.bind(this, paragraph)) + .then(() => args.localNid || _chooseNode(args.cacheName, false)) + .then((nid) => agentMonitor.query(nid, args.cacheName, args.query, args.nonCollocatedJoins, !!args.localNid, args.pageSize)) + .then(_processQueryResult.bind(this, paragraph, false)) .catch((err) => paragraph.errMsg = err.message); }; @@ -1249,41 +1299,62 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', } }; - $scope.execute = (paragraph) => { - if (!$scope.actionAvailable(paragraph, true)) - return; + const addLimit = (query, limitSize) => + `SELECT * FROM ( + ${query} + ) LIMIT ${limitSize}`; - Notebook.save($scope.notebook) - .catch(Messages.showError); + $scope.nonCollocatedJoinsAvailable = (paragraph) => { + const cache = _.find($scope.caches, {name: paragraph.cacheName}); - paragraph.prevQuery = paragraph.queryArgs ? paragraph.queryArgs.query : paragraph.query; + if (cache) + return !!_.find(cache.nodes, (node) => Version.since(node.version, NON_COLLOCATED_JOINS_SINCE)); - _showLoading(paragraph, true); + return false; + }; - _closeOldQuery(paragraph) - .then(() => { - const args = paragraph.queryArgs = { - cacheName: paragraph.cacheName, - pageSize: paragraph.pageSize, - query: paragraph.query, - type: 'QUERY' - }; + $scope.execute = (paragraph, nonCollocatedJoins = false) => { + const local = !!paragraph.localQry; - return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, args.query, false, args.pageSize); - }) - .then((res) => { - _processQueryResult(paragraph, res); + $scope.actionAvailable(paragraph, true) && _chooseNode(paragraph.cacheName, local) + .then((nid) => { + Notebook.save($scope.notebook) + .catch(Messages.showError); - _tryStartRefresh(paragraph); - }) - .catch((err) => { - paragraph.errMsg = err.message; + paragraph.prevQuery = paragraph.queryArgs ? paragraph.queryArgs.query : paragraph.query; - _showLoading(paragraph, false); + _showLoading(paragraph, true); - $scope.stopRefresh(paragraph); - }) - .then(() => paragraph.ace.focus()); + return _closeOldQuery(paragraph) + .then(() => { + const args = paragraph.queryArgs = { + cacheName: paragraph.cacheName, + pageSize: paragraph.pageSize, + query: paragraph.query, + firstPageOnly: paragraph.firstPageOnly, + nonCollocatedJoins, + type: 'QUERY', + localNid: local ? nid : null + }; + + const qry = args.firstPageOnly ? addLimit(args.query, args.pageSize) : paragraph.query; + + return agentMonitor.query(nid, args.cacheName, qry, nonCollocatedJoins, local, args.pageSize); + }) + .then((res) => { + _processQueryResult(paragraph, true, res); + + _tryStartRefresh(paragraph); + }) + .catch((err) => { + paragraph.errMsg = err.message; + + _showLoading(paragraph, false); + + $scope.stopRefresh(paragraph); + }) + .then(() => paragraph.ace.focus()); + }); }; const _cancelRefresh = (paragraph) => { @@ -1310,7 +1381,8 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', _showLoading(paragraph, true); _closeOldQuery(paragraph) - .then(() => { + .then(() => _chooseNode(paragraph.cacheName, false)) + .then((nid) => { const args = paragraph.queryArgs = { cacheName: paragraph.cacheName, pageSize: paragraph.pageSize, @@ -1318,9 +1390,9 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', type: 'EXPLAIN' }; - return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, args.query, false, args.pageSize); + return agentMonitor.query(nid, args.cacheName, args.query, false, false, args.pageSize); }) - .then(_processQueryResult.bind(this, paragraph)) + .then(_processQueryResult.bind(this, paragraph, true)) .catch((err) => { paragraph.errMsg = err.message; @@ -1330,34 +1402,48 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', }; $scope.scan = (paragraph, query = null) => { - if (!$scope.actionAvailable(paragraph, false)) - return; + const local = !!paragraph.localQry; - Notebook.save($scope.notebook) - .catch(Messages.showError); + $scope.actionAvailable(paragraph, false) && _chooseNode(paragraph.cacheName, local) + .then((nid) => { + Notebook.save($scope.notebook) + .catch(Messages.showError); - _cancelRefresh(paragraph); + _cancelRefresh(paragraph); - _showLoading(paragraph, true); + _showLoading(paragraph, true); - _closeOldQuery(paragraph) - .then(() => { - const args = paragraph.queryArgs = { - cacheName: paragraph.cacheName, - pageSize: paragraph.pageSize, - query, - type: 'SCAN' - }; + _closeOldQuery(paragraph) + .then(() => { + const args = paragraph.queryArgs = { + cacheName: paragraph.cacheName, + pageSize: paragraph.pageSize, + firstPageOnly: paragraph.firstPageOnly, + query, + type: 'SCAN', + localNid: local ? nid : null + }; - return agentMonitor.query(cacheNode(paragraph.cacheName), args.cacheName, query, false, args.pageSize); - }) - .then(_processQueryResult.bind(this, paragraph)) - .catch((err) => { - paragraph.errMsg = err.message; + return agentMonitor.query(nid, args.cacheName, query, false, local, args.pageSize); + }) + .then((res) => { + if (paragraph.firstPageOnly) { + res.hasMore = false; - _showLoading(paragraph, false); - }) - .then(() => paragraph.ace.focus()); + _processQueryResult(paragraph, true, res); + + _closeOldQuery(paragraph); + } + else + _processQueryResult(paragraph, true, res); + }) + .catch((err) => { + paragraph.errMsg = err.message; + + _showLoading(paragraph, false); + }) + .then(() => paragraph.ace.focus()); + }); }; $scope.scanWithFilter = (paragraph) => { @@ -1480,10 +1566,11 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', paragraph.gridOptions.api.exporter.pdfExport(uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE); }; - $scope.exportCsvAll = function(paragraph) { + $scope.exportCsvAll = (paragraph) => { const args = paragraph.queryArgs; - agentMonitor.queryGetAll(cacheNode(args.cacheName), args.cacheName, args.query, false) + return Promise.resolve(args.localNid || _chooseNode(args.cacheName, false)) + .then((nid) => agentMonitor.queryGetAll(nid, args.cacheName, args.query, !!args.nonCollocatedJoins, !!args.localNid)) .then((res) => _export(paragraph.name + '-all.csv', paragraph.columnFilter, res.columns, res.rows)) .catch(Messages.showError) .then(() => paragraph.ace.focus()); @@ -1601,7 +1688,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', if (_.isNil(paragraph.queryArgs.query)) { scope.title = 'SCAN query'; - scope.content = [`SCAN query for cache: <b>${$scope.maskCacheName(paragraph.queryArgs.cacheName)}</b>`]; + scope.content = [`SCAN query for cache: <b>${maskCacheName(paragraph.queryArgs.cacheName, true)}</b>`]; } else if (paragraph.queryArgs.query.startsWith(SCAN_CACHE_WITH_FILTER)) { scope.title = 'SCAN query'; @@ -1613,7 +1700,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', else filter = paragraph.queryArgs.query.substr(SCAN_CACHE_WITH_FILTER.length); - scope.content = [`SCAN query for cache: <b>${$scope.maskCacheName(paragraph.queryArgs.cacheName)}</b> with filter: <b>${filter}</b>`]; + scope.content = [`SCAN query for cache: <b>${maskCacheName(paragraph.queryArgs.cacheName, true)}</b> with filter: <b>${filter}</b>`]; } else if (paragraph.queryArgs.query .startsWith('EXPLAIN ')) { scope.title = 'Explain query'; http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration.state.js b/modules/web-console/frontend/app/modules/states/configuration.state.js index 7fd7541..888c804 100644 --- a/modules/web-console/frontend/app/modules/states/configuration.state.js +++ b/modules/web-console/frontend/app/modules/states/configuration.state.js @@ -30,7 +30,7 @@ angular.module('ignite-console.states.configuration', ['ui.router']) // Summary screen .directive(...summaryTabs) // Services. - .service('igniteConfigurationResource', ConfigurationResource) + .service('IgniteConfigurationResource', ConfigurationResource) // Configure state provider. .config(['$stateProvider', 'AclRouteProvider', ($stateProvider, AclRoute) => { // Setup the states. http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/client-near-cache.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/client-near-cache.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/client-near-cache.jade new file mode 100644 index 0000000..9d8ccbe --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/client-near-cache.jade @@ -0,0 +1,50 @@ +//- + 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. + +include ../../../../../app/helpers/jade/mixins.jade + +-var form = 'clientNearCache' +-var model = 'backupItem.clientNearConfiguration' + +.panel.panel-default(ng-form=form novalidate ng-show='backupItem.cacheMode === "PARTITIONED"') + .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') + ignite-form-panel-chevron + label Client near cache + ignite-form-field-tooltip.tipLabel + | Near cache settings for client nodes#[br] + | Near cache is a small local cache that stores most recently or most frequently accessed data#[br] + | Should be used in case when it is impossible to send computations to remote nodes + ignite-form-revert + .panel-collapse(role='tabpanel' bs-collapse-target id=form) + .panel-body(ng-if='ui.isPanelLoaded("#{form}")') + .col-sm-6 + -var enabled = model + '.clientNearCacheEnabled' + + .settings-row + +checkbox('Enabled', enabled, '"clientNacheEnabled"', 'Flag indicating whether to configure near cache') + .settings-row + +number('Start size:', model + '.nearStartSize', '"clientNearStartSize"', enabled, '375000', '0', + 'Initial cache size for near cache which will be used to pre-create internal hash table after start') + .settings-row + +evictionPolicy(model + '.nearEvictionPolicy', '"clientNearCacheEvictionPolicy"', enabled, 'false', + 'Near cache eviction policy\ + <ul>\ + <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\ + <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\ + <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\ + </ul>') + .col-sm-6 + +preview-xml-java('backupItem', 'cacheClientNearCache') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade index e3147b1..e9ff143 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/general.jade @@ -23,6 +23,9 @@ include ../../../../../app/helpers/jade/mixins.jade .panel-heading(bs-collapse-toggle) ignite-form-panel-chevron label General + ignite-form-field-tooltip.tipLabel + | Common cache configuration#[br] + | #[a(href="https://apacheignite.readme.io/docs/data-grid" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id='general') .panel-body http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade index e9f29fd..724418f 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/memory.jade @@ -24,7 +24,8 @@ include ../../../../../app/helpers/jade/mixins.jade ignite-form-panel-chevron label Memory ignite-form-field-tooltip.tipLabel - | Cache memory settings + | Cache memory settings#[br] + | #[a(href="https://apacheignite.readme.io/docs/off-heap-memory" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') @@ -77,7 +78,7 @@ include ../../../../../app/helpers/jade/mixins.jade </ul>') .settings-row(data-ng-if=model + '.offHeapMode === 1 && ' + model + '.memoryMode !== "OFFHEAP_VALUES"') +number-required('Off-heap memory max size:', model + '.offHeapMaxMemory', '"offHeapMaxMemory"', 'true', - model + '.offHeapMode === 1', '', 1, + model + '.offHeapMode === 1', 'Enter off-heap memory size', '1', 'Maximum amount of memory available to off-heap storage in bytes') .settings-row -var onHeapTired = model + '.memoryMode === "ONHEAP_TIERED"' @@ -94,7 +95,14 @@ include ../../../../../app/helpers/jade/mixins.jade <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\ </ul>') .settings-row - +number('Start size:', model + '.startSize', '"startSize"', 'true', '1500000', '0', 'Initial cache size in entries number') + +number('Start size:', model + '.startSize', '"startSize"', 'true', '1500000', '0', + 'In terms of size and capacity, Ignite internal cache map acts exactly like a normal Java HashMap: it has some initial capacity\ + (which is pretty small by default), which doubles as data arrives. The process of internal cache map resizing is CPU-intensive\ + and time-consuming, and if you load a huge dataset into cache (which is a normal use case), the map will have to resize a lot of times.\ + To avoid that, you can specify the initial cache map capacity, comparable to the expected size of your dataset.\ + This will save a lot of CPU resources during the load time, because the map would not have to resize.\ + For example, if you expect to load 10 million entries into cache, you can set this property to 10 000 000.\ + This will save you from cache internal map resizes.') .settings-row +checkbox('Swap enabled', model + '.swapEnabled', '"swapEnabled"', 'Flag indicating whether swap storage is enabled or not for this cache') .col-sm-6 http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.jade new file mode 100644 index 0000000..ba538c2 --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-client.jade @@ -0,0 +1,51 @@ +//- + 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. + +include ../../../../../app/helpers/jade/mixins.jade + +-var form = 'clientNearCache' +-var model = 'backupItem' + +.panel.panel-default(ng-form=form novalidate ng-show='backupItem.cacheMode === "PARTITIONED"') + .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') + ignite-form-panel-chevron + label Near cache on client node + ignite-form-field-tooltip.tipLabel + | Near cache settings for client nodes#[br] + | Near cache is a small local cache that stores most recently or most frequently accessed data#[br] + | Should be used in case when it is impossible to send computations to remote nodes + ignite-form-revert + .panel-collapse(role='tabpanel' bs-collapse-target id=form) + .panel-body(ng-if='ui.isPanelLoaded("#{form}")') + .col-sm-6 + -var nearCfg = model + '.clientNearConfiguration' + -var enabled = nearCfg + '.enabled' + + .settings-row + +checkbox('Enabled', enabled, '"clientNearEnabled"', 'Flag indicating whether to configure near cache') + .settings-row + +number('Start size:', nearCfg + '.nearStartSize', '"clientNearStartSize"', enabled, '375000', '0', + 'Initial cache size for near cache which will be used to pre-create internal hash table after start') + .settings-row + +evictionPolicy(nearCfg + '.nearEvictionPolicy', '"clientNearCacheEvictionPolicy"', enabled, 'false', + 'Near cache eviction policy\ + <ul>\ + <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\ + <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\ + <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\ + </ul>') + .col-sm-6 + +preview-xml-java(model, 'cacheNearClient') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.jade new file mode 100644 index 0000000..a96b947 --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/near-cache-server.jade @@ -0,0 +1,52 @@ +//- + 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. + +include ../../../../../app/helpers/jade/mixins.jade + +-var form = 'serverNearCache' +-var model = 'backupItem' + +.panel.panel-default(ng-form=form novalidate ng-show='#{model}.cacheMode === "PARTITIONED"') + .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') + ignite-form-panel-chevron + label Near cache on server node + ignite-form-field-tooltip.tipLabel + | Near cache settings#[br] + | Near cache is a small local cache that stores most recently or most frequently accessed data#[br] + | Should be used in case when it is impossible to send computations to remote nodes#[br] + | #[a(href="https://apacheignite.readme.io/docs/near-caches" target="_blank") More info] + ignite-form-revert + .panel-collapse(role='tabpanel' bs-collapse-target id=form) + .panel-body(ng-if='ui.isPanelLoaded("#{form}")') + .col-sm-6 + -var nearCfg = model + '.nearConfiguration' + -var enabled = nearCfg + '.enabled' + + .settings-row + +checkbox('Enabled', enabled, '"nearCacheEnabled"', 'Flag indicating whether to configure near cache') + .settings-row + +number('Start size:', nearCfg + '.nearStartSize', '"nearStartSize"', enabled, '375000', '0', + 'Initial cache size for near cache which will be used to pre-create internal hash table after start') + .settings-row + +evictionPolicy(model + '.nearConfiguration.nearEvictionPolicy', '"nearCacheEvictionPolicy"', enabled, 'false', + 'Near cache eviction policy\ + <ul>\ + <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\ + <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\ + <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\ + </ul>') + .col-sm-6 + +preview-xml-java(model, 'cacheNearServer') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade index ee28c87..eb74736 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/node-filter.jade @@ -36,7 +36,6 @@ include ../../../../../app/helpers/jade/mixins.jade +dropdown('Node filter:', nodeFilterKind, '"nodeFilter"', 'true', 'Not set', '[\ {value: "IGFS", label: "IGFS nodes"},\ - {value: "OnNodes", label: "Specified nodes"},\ {value: "Custom", label: "Custom"},\ {value: undefined, label: "Not set"}\ ]', @@ -56,53 +55,5 @@ include ../../../../../app/helpers/jade/mixins.jade +java-class('Class name:', customNodeFilter + '.className', '"customNodeFilter"', 'true', required, 'Class name of custom node filter implementation') - div(ng-show='#{nodeFilterKind} === "OnNodes"') - -var nodeSetFilter = nodeFilter + '.OnNodes.nodeIds' - - +ignite-form-group(ng-form=form ng-model=nodeSetFilter) - -var uniqueTip = 'Such node ID already exists!' - - ignite-form-field-label - | Node IDs - ignite-form-group-tooltip - | Set of node IDs to deploy cache - ignite-form-group-add(ng-click='group.add = [{}]') - | Add new node ID - - .group-content(ng-if='#{nodeSetFilter}.length') - -var model = 'obj.model'; - -var name = '"edit" + $index' - -var valid = form + '[' + name + '].$valid' - -var save = nodeSetFilter + '[$index] = ' + model - - div(ng-repeat='model in #{nodeSetFilter} track by $index' ng-init='obj = {}') - label.col-xs-12.col-sm-12.col-md-12 - .indexField - | {{ $index+1 }}) - +table-remove-button(nodeSetFilter, 'Remove node ID') - - span(ng-hide='field.edit') - a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }} - span(ng-if='field.edit' ng-init='#{field} = model') - +table-uuid-field(name, model, nodeSetFilter, valid, save, false, true) - +table-save-button(valid, save, false) - +unique-feedback(name, uniqueTip) - +uuid-feedback(name) - - .group-content(ng-repeat='field in group.add') - -var model = 'new'; - -var name = '"new"' - -var valid = form + '[' + name + '].$valid' - -var save = nodeSetFilter + '.push(' + model + ')' - - div - label.col-xs-12.col-sm-12.col-md-12 - +table-uuid-field(name, model, nodeSetFilter, valid, save, true, true) - +table-save-button(valid, save, true) - +unique-feedback(name, uniqueTip) - +uuid-feedback(name) - .group-content-empty(id='nodeSetFilter' ng-if='!(#{nodeSetFilter}.length) && !group.add.length') - | Not defined - .col-sm-6 +preview-xml-java(model, 'cacheNodeFilter', 'igfss') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade index c709135..ae13166 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/query.jade @@ -24,21 +24,28 @@ include ../../../../../app/helpers/jade/mixins.jade ignite-form-panel-chevron label Queries & Indexing ignite-form-field-tooltip.tipLabel - | Cache queries settings + | Cache queries settings#[br] + | #[a(href="https://apacheignite.readme.io/docs/sql-queries" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') .col-sm-6 .settings-row +text('SQL schema name:', model + '.sqlSchema', '"sqlSchema"', 'false', 'Input schema name', - 'Schema name allow to use existing database queries in your application and according to SQL ANSI-99<br>\ - Cache is reffered by schema name in cross-cache queries<br/>\ - Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive<br/>\ - When SQL schema is not specified, quoted cache name should be used<br/>\ - Query example without schema name:<br>\ - SELECT .... FROM "cache1".Type1 JOIN "cache2".Type2 ...<br>\ - The same query using schema name:<br>\ - SELECT .... FROM cache1.Type1 JOIN cache2.Type2 ...') + 'Specify any custom name to be used as SQL schema for current cache. This name will correspond to SQL ANSI-99 standard.\ + Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive.\ + When SQL schema is not specified, quoted cache name should used instead.<br/>\ + For example:\ + <ul>\ + <li>\ + Query without schema names (quoted cache names will be used):\ + SELECT * FROM "PersonsCache".Person p INNER JOIN "OrganizationsCache".Organization o on p.org = o.id\ + </li>\ + <li>\ + The same query using schema names "Persons" and "Organizations":\ + SELECT * FROM Persons.Person p INNER JOIN Organizations.Organization o on p.org = o.id\ + </li>\ + </ul>') .settings-row +number('On-heap cache for off-heap indexes:', model + '.sqlOnheapRowCacheSize', '"sqlOnheapRowCacheSize"', 'true', '10240', '1', 'Number of SQL rows which will be cached onheap to avoid deserialization on each SQL index access') @@ -97,7 +104,8 @@ include ../../../../../app/helpers/jade/mixins.jade 'Flag indicating whether SQL indexes should support snapshots') .settings-row +checkbox('Escape table and filed names', model + '.sqlEscapeAll', '"sqlEscapeAll"', - 'If enabled than all the SQL table and field names will be escaped with double quotes like "tableName"."fieldName"<br/>\ - This enforces case sensitivity for field names and also allows having special characters in table and field names') + 'If enabled than all schema, table and field names will be escaped with double quotes (for example: "tableName"."fieldName").<br/>\ + This enforces case sensitivity for field names and also allows having special characters in table and field names.<br/>\ + Escaped names will be used for creation internal structures in Ignite SQL engine.') .col-sm-6 +preview-xml-java(model, 'cacheQuery', 'domains') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade index 6cf2d33..824442c 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/rebalance.jade @@ -24,7 +24,8 @@ include ../../../../../app/helpers/jade/mixins.jade ignite-form-panel-chevron label Rebalance ignite-form-field-tooltip.tipLabel - | Cache rebalance settings + | Cache rebalance settings#[br] + | #[a(href="https://apacheignite.readme.io/docs/rebalancing" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade deleted file mode 100644 index 74f500b..0000000 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/server-near-cache.jade +++ /dev/null @@ -1,51 +0,0 @@ -//- - 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. - -include ../../../../../app/helpers/jade/mixins.jade - --var form = 'serverNearCache' --var model = 'backupItem' - -.panel.panel-default(ng-form=form novalidate ng-show='#{model}.cacheMode === "PARTITIONED"') - .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') - ignite-form-panel-chevron - label Server near cache - ignite-form-field-tooltip.tipLabel - | Near cache settings#[br] - | Near cache is a small local cache that stores most recently or most frequently accessed data#[br] - | Should be used in case when it is impossible to send computations to remote nodes - ignite-form-revert - .panel-collapse(role='tabpanel' bs-collapse-target id=form) - .panel-body(ng-if='ui.isPanelLoaded("#{form}")') - .col-sm-6 - -var enabled = model + '.nearCacheEnabled' - -var nearCfg = model + '.nearConfiguration' - - .settings-row - +checkbox('Enabled', enabled, '"nearCacheEnabled"', 'Flag indicating whether to configure near cache') - .settings-row - +number('Start size:', nearCfg + '.nearStartSize', '"nearStartSize"', enabled, '375000', '0', - 'Initial cache size for near cache which will be used to pre-create internal hash table after start') - .settings-row - +evictionPolicy(model + '.nearConfiguration.nearEvictionPolicy', '"nearCacheEvictionPolicy"', enabled, 'false', - 'Near cache eviction policy\ - <ul>\ - <li>Least Recently Used (LRU) - Eviction policy based on LRU algorithm and supports batch eviction</li>\ - <li>First In First Out (FIFO) - Eviction policy based on FIFO algorithm and supports batch eviction</li>\ - <li>SORTED - Eviction policy which will select the minimum cache entry for eviction</li>\ - </ul>') - .col-sm-6 - +preview-xml-java(model, 'cacheServerNearCache') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade b/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade index 84752d6..a7d8f14 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/caches/store.jade @@ -20,34 +20,35 @@ include ../../../../../app/helpers/jade/mixins.jade -var model = 'backupItem' mixin hibernateField(name, model, items, valid, save, newItem) - -var reset = newItem ? 'group.add = []' : 'field.edit = false' - -var resetOnEnter = newItem ? '(stopblur = true) && (group.add = [{}])' : '(field.edit = false)' -var onEnter = valid + ' && (' + save + '); ' + valid + ' && ' + resetOnEnter + ';' + -var onEscape = newItem ? 'group.add = []' : 'field.edit = false' + -var resetOnBlur = newItem ? '!stopblur && (group.add = [])' : 'field.edit = false' -var onBlur = valid + ' && ( ' + save + '); ' + resetOnBlur + ';' - if block - block + div(ignite-on-focus-out=onBlur) + if block + block - .input-tip - +ignite-form-field-input(name, model, false, 'true', 'key=value')( - data-ignite-property-unique=items - data-ignite-property-value-specified - data-ignite-form-field-input-autofocus='true' + .input-tip + +ignite-form-field-input(name, model, false, 'true', 'key=value')( + data-ignite-property-unique=items + data-ignite-property-value-specified + data-ignite-form-field-input-autofocus='true' - ng-blur=onBlur - ignite-on-enter=onEnter - ignite-on-escape=onEscape - ) + ignite-on-enter=onEnter + ignite-on-escape=onEscape + ) .panel.panel-default(ng-form=form novalidate) .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') ignite-form-panel-chevron label Store ignite-form-field-tooltip.tipLabel - | Cache store settings + | Cache store settings#[br] + | #[a(href="https://apacheignite.readme.io/docs/persistent-store" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') @@ -86,6 +87,11 @@ mixin hibernateField(name, model, items, valid, save, newItem) +dialect('Dialect:', pojoStoreFactory + '.dialect', '"pojoDialect"', required, 'Dialect of SQL implemented by a particular RDBMS:', 'Generic JDBC dialect', 'Choose JDBC dialect') + .details-row + +checkbox('Escape table and filed names', pojoStoreFactory + '.sqlEscapeAll', '"sqlEscapeAll"', + 'If enabled than all schema, table and field names will be escaped with double quotes (for example: "tableName"."fieldName").<br/>\ + This enforces case sensitivity for field names and also allows having special characters in table and field names.<br/>\ + Escaped names will be used for CacheJdbcPojoStore internal SQL queries.') div(ng-show='#{storeFactoryKind} === "CacheJdbcBlobStoreFactory"') -var blobStoreFactory = storeFactory + '.CacheJdbcBlobStoreFactory' -var blobStoreFactoryVia = blobStoreFactory + '.connectVia' @@ -154,46 +160,28 @@ mixin hibernateField(name, model, items, valid, save, newItem) ignite-form-group-tooltip | List of Hibernate properties#[br] | For example: connection.url=jdbc:h2:mem:exampleDb - ignite-form-group-add(ng-click='group.add = [{}]') + ignite-form-group-add(ng-click='tableNewItem(hibernatePropsTbl)') | Add new Hibernate property -var tipUnique = 'Property with such key already exists!' -var tipPropertySpecified = 'Property should be present in format key=value!' - .group-content(ng-if='#{hibernateProperties}.length') - -var model = 'obj.model'; - -var name = '"edit" + $index' - -var valid = form + '[' + name + '].$valid' - -var save = hibernateProperties + '[$index] = ' + model - - div(ng-repeat='model in #{hibernateProperties} track by $index' ng-init='obj = {}') - label.col-xs-12.col-sm-12.col-md-12 - .indexField - | {{ $index+1 }}) - +table-remove-button(hibernateProperties, 'Remove Hibernate property') - - span(ng-hide='field.edit') - a.labelFormField(ng-click='field.edit = true; #{model} = model;') {{ model }} - span(ng-if='field.edit') - +hibernateField(name, model, hibernateProperties, valid, save, false) - +table-save-button(valid, save, false) - +form-field-feedback(name, 'ignitePropertyUnique', tipUnique) - +form-field-feedback(name, 'ignitePropertyValueSpecified', tipPropertySpecified) - - .group-content(ng-repeat='field in group.add') - -var model = 'new'; - -var name = '"new"' - -var valid = form + '[' + name + '].$valid' - -var save = hibernateProperties + '.push(' + model + ')' - - div - label.col-xs-12.col-sm-12.col-md-12 - +hibernateField(name, model, hibernateProperties, valid, save, true) - +table-save-button(valid, save, true) - +form-field-feedback(name, 'ignitePropertyUnique', tipUnique) - +form-field-feedback(name, 'ignitePropertyValueSpecified', tipPropertySpecified) - .group-content-empty(ng-if='!(#{hibernateProperties}.length) && !group.add.length') + .group-content-empty(ng-if='!((#{hibernateProperties} && #{hibernateProperties}.length > 0) || tableNewItemActive(hibernatePropsTbl))') | Not defined + .group-content(ng-show='(#{hibernateProperties} && #{hibernateProperties}.length > 0) || tableNewItemActive(hibernatePropsTbl)') + table.links-edit(id='hibernateProps' st-table=hibernateProperties) + tbody + tr(ng-repeat='item in #{hibernateProperties}') + td.col-sm-12(ng-hide='tableEditing(hibernatePropsTbl, $index)') + a.labelFormField(ng-click='tableStartEdit(backupItem, hibernatePropsTbl, $index)') {{item.name}} = {{item.value}} + +btn-remove('tableRemove(backupItem, hibernatePropsTbl, $index)', '"Remove Property"') + td.col-sm-12(ng-if='tableEditing(hibernatePropsTbl, $index)') + +table-pair-edit('hibernatePropsTbl', 'cur', 'Property name', 'Property value', false, false, '{{::hibernatePropsTbl.focusId + $index}}', '$index', '=') + tfoot(ng-show='tableNewItemActive(hibernatePropsTbl)') + tr + td.col-sm-12 + +table-pair-edit('hibernatePropsTbl', 'new', 'Property name', 'Property value', false, false, '{{::hibernatePropsTbl.focusId + $index}}', '-1', '=') + .settings-row +checkbox('Keep binary in store', model + '.storeKeepBinary', '"storeKeepBinary"', http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade index c4ef88e..ef83356 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/atomic.jade @@ -25,7 +25,8 @@ include ../../../../../app/helpers/jade/mixins.jade label Atomic configuration ignite-form-field-tooltip.tipLabel | Configuration for atomic data structures#[br] - | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value + | Atomics are distributed across the cluster, essentially enabling performing atomic operations (such as increment-and-get or compare-and-set) with the same globally-visible value#[br] + | #[a(href="https://apacheignite.readme.io/docs/atomic-types" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target='' id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade index 29e7a79..b41b97c 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/attributes.jade @@ -43,8 +43,8 @@ include ../../../../../app/helpers/jade/mixins.jade .group-content(ng-show='(#{userAttributes} && #{userAttributes}.length > 0) || tableNewItemActive(attributesTbl)') table.links-edit(id='attributes' st-table=userAttributes) tbody - tr(ng-repeat='item in #{userAttributes}') - td.col-sm-12(ng-show='!tableEditing(attributesTbl, $index)') + tr(ng-repeat='item in #{userAttributes} track by $index') + td.col-sm-12(ng-hide='tableEditing(attributesTbl, $index)') a.labelFormField(ng-click='tableStartEdit(backupItem, attributesTbl, $index)') {{item.name}} = {{item.value}} +btn-remove('tableRemove(backupItem, attributesTbl, $index)', '"Remove attribute"') td.col-sm-12(ng-show='tableEditing(attributesTbl, $index)') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade index c63e2d9..9994087 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/binary.jade @@ -20,18 +20,13 @@ include ../../../../../app/helpers/jade/mixins.jade -var model = 'backupItem.binaryConfiguration' -var types = model + '.typeConfigurations' -//- Mixin for java name field with enabled condition. -mixin binary-types-java-class(lbl, model, name, enabled, required, remove, autofocus, tip) - +java-class(lbl, model, name, enabled, required, tip) - if (remove) - +table-remove-button(types, 'Remove type configuration') - .panel.panel-default(ng-form=form novalidate) .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")') ignite-form-panel-chevron label Binary configuration ignite-form-field-tooltip.tipLabel - | Configuration of specific binary types + | Configuration of specific binary types#[br] + | #[a(href="https://apacheignite.readme.io/docs/binary-marshaller" target="_blank") More info] ignite-form-revert .panel-collapse(role='tabpanel' bs-collapse-target id=form) .panel-body(ng-if='ui.isPanelLoaded("#{form}")') @@ -45,8 +40,6 @@ mixin binary-types-java-class(lbl, model, name, enabled, required, remove, autof .settings-row +java-class('Serializer:', model + '.serializer', '"serializer"', 'true', 'false', 'Class with custom serialization logic for binary objects') .settings-row - -var form = 'binaryTypeConfigurations'; - +ignite-form-group() ignite-form-field-label | Type configurations @@ -59,15 +52,22 @@ mixin binary-types-java-class(lbl, model, name, enabled, required, remove, autof .group-content(ng-repeat='model in #{types} track by $index') hr(ng-if='$index !== 0') .settings-row - +binary-types-java-class('Type name:', 'model.typeName', '"typeName" + $index', 'true', 'true', true, 'true', 'Type name') + +java-class-autofocus('Type name:', 'model.typeName', '"typeName" + $index', 'true', 'true', 'true', 'Type name') + +table-remove-button(types, 'Remove type configuration') .settings-row - +binary-types-java-class('ID mapper:', 'model.idMapper', '"idMapper" + $index', 'true', 'false', false, 'false', + +java-class('ID mapper:', 'model.idMapper', '"idMapper" + $index', 'true', 'false', 'Maps given from BinaryNameMapper type and filed name to ID that will be used by Ignite in internals<br/>\ - Ignite never writes full strings for field or type/class names. Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names. It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and, to gain performance, it is safe to work with hash codes. For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names') + Ignite never writes full strings for field or type/class names.\ + Instead, for performance reasons, Ignite writes integer hash codes for type/class and field names.\ + It has been tested that hash code conflicts for the type/class names or the field names within the same type are virtually non - existent and,\ + to gain performance, it is safe to work with hash codes.\ + For the cases when hash codes for different types or fields actually do collide <b>BinaryIdMapper</b> allows to override the automatically generated hash code IDs for the type and field names') .settings-row - +binary-types-java-class('Name mapper:', 'model.nameMapper', '"nameMapper" + $index', 'true', 'false', false, 'false', 'Maps type/class and field names to different names') + +java-class('Name mapper:', 'model.nameMapper', '"nameMapper" + $index', 'true', 'false', + 'Maps type/class and field names to different names') .settings-row - +binary-types-java-class('Serializer:', 'model.serializer', '"serializer" + $index', 'true', 'false', false, 'false', 'Class with custom serialization logic for binary object') + +java-class('Serializer:', 'model.serializer', '"serializer" + $index', 'true', 'false', + 'Class with custom serialization logic for binary object') .settings-row +checkbox('Enum', 'model.enum', 'enum', 'Flag indicating that this type is the enum') http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade index 3531c77..45ccc13 100644 --- a/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade +++ b/modules/web-console/frontend/app/modules/states/configuration/clusters/cache-key-cfg.jade @@ -18,7 +18,6 @@ include ../../../../../app/helpers/jade/mixins.jade -var form = 'cacheKeyCfg' -var model = 'backupItem.cacheKeyConfiguration' --var items = model; .panel.panel-default(ng-form=form novalidate) .panel-heading(bs-collapse-toggle ng-click='ui.loadPanel("#{form}")') @@ -31,9 +30,7 @@ include ../../../../../app/helpers/jade/mixins.jade .panel-body(ng-if='ui.isPanelLoaded("#{form}")') .col-sm-6 .settings-row - -var form = form + 'TypeConfigurations' - - +ignite-form-group(ng-form=form ng-model=model) + +ignite-form-group() ignite-form-field-label | Cache key configuration ignite-form-group-tooltip @@ -45,8 +42,8 @@ include ../../../../../app/helpers/jade/mixins.jade .group-content(ng-repeat='model in #{model} track by $index') hr(ng-if='$index !== 0') .settings-row - +java-class('Type name:', 'model.typeName', '"cacheKeyTypeName" + $index', 'true', 'true', 'Type name') - +table-remove-button(items, 'Remove cache key configuration') + +java-class-autofocus('Type name:', 'model.typeName', '"cacheKeyTypeName" + $index', 'true', 'true', 'true', 'Type name') + +table-remove-button(model, 'Remove cache key configuration') .settings-row +text('Affinity key field name:', 'model.affinityKeyFieldName', '"affinityKeyFieldName" + $index', true, 'Enter field name', 'Affinity key field name') .col-sm-6
