http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade new file mode 100644 index 0000000..cb4687a --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/misc.jade @@ -0,0 +1,108 @@ +//- + 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 = 'misc' +-var model = 'backupItem' +-var pathModesForm = 'miscPathModes' +-var pathModes = model + '.pathModes' + +//- LEGACY mixin for LEGACY IGFS path modes table. +mixin table-igfs-path-mode-edit(prefix, focusId, index) + -var keyModel = 'tblPathModes.' + prefix + 'Key' + -var valModel = 'tblPathModes.' + prefix + 'Value' + + -var keyFocusId = prefix + 'Key' + focusId + -var valFocusId = prefix + 'Value' + focusId + + .col-xs-8.col-sm-8.col-md-8 + .fieldSep / + .input-tip + input.form-control(id=keyFocusId ignite-on-enter-focus-move=valFocusId type='text' ng-model=keyModel placeholder='Path' ignite-on-escape='tableReset()') + .col-xs-4.col-sm-4.col-md-4 + -var arg = keyModel + ', ' + valModel + -var btnVisible = 'tablePairSaveVisible(tblPathModes, ' + index + ')' + -var btnSave = 'tablePairSave(tablePairValid, backupItem, tblPathModes, ' + index + ')' + -var btnVisibleAndSave = btnVisible + ' && ' + btnSave + +btn-save(btnVisible, btnSave) + .input-tip + button.select-toggle.form-control(id=valFocusId bs-select ng-model=valModel data-placeholder='Mode' bs-options='item.value as item.label for item in igfsModes' tabindex='0' ignite-on-enter=btnVisibleAndSave ignite-on-escape='tableReset()') + +.panel.panel-default(ng-form=form novalidate) + .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') + ignite-form-panel-chevron + label Miscellaneous + ignite-form-field-tooltip.tipLabel + | Various miscellaneous IGFS settings + ignite-form-revert + .panel-collapse(role='tabpanel' bs-collapse-target id=form) + .panel-body(ng-if='ui.isPanelLoaded("#{form}")') + .col-sm-6 + .settings-row + +number('Block size:', model + '.blockSize', '"blockSize"', 'true', '65536', '0', 'File data block size in bytes') + .settings-row + +number('Stream buffer size:', model + '.streamBufferSize', '"streamBufferSize"', 'true', '65536', '0', 'Read/write buffer size for IGFS stream operations in bytes') + .settings-row + +number('Maximum space size:', model + '.maxSpaceSize', '"maxSpaceSize"', 'true', '0', '0', 'Maximum space available for data cache to store file system entries') + .settings-row + +number('Maximum task range length:', model + '.maximumTaskRangeLength', '"maximumTaskRangeLength"', 'true', '0', '0', 'Maximum default range size of a file being split during IGFS task execution') + .settings-row + +number-min-max('Management port:', model + '.managementPort', '"managementPort"', 'true', '11400', '0', '65535', 'Port number for management endpoint') + .settings-row + +number('Per node batch size:', model + '.perNodeBatchSize', '"perNodeBatchSize"', 'true', '100', '0', 'Number of file blocks collected on local node before sending batch to remote node') + .settings-row + +number('Per node parallel batch count:', model + '.perNodeParallelBatchCount', '"perNodeParallelBatchCount"', 'true', '8', '0', 'Number of file block batches that can be concurrently sent to remote node') + .settings-row + +number('Prefetch blocks:', model + '.prefetchBlocks', '"prefetchBlocks"', 'true', '0', '0', 'Number of pre-fetched blocks if specific file chunk is requested') + .settings-row + +number('Sequential reads before prefetch:', model + '.sequentialReadsBeforePrefetch', '"sequentialReadsBeforePrefetch"', 'true', '0', '0', 'Amount of sequential block reads before prefetch is triggered') + .settings-row + +number('Trash purge timeout:', model + '.trashPurgeTimeout', '"trashPurgeTimeout"', 'true', '1000', '0', 'Maximum timeout awaiting for trash purging in case data cache oversize is detected') + .settings-row + +checkbox('Colocate metadata', model + '.colocateMetadata', '"colocateMetadata"', 'Whether to co-locate metadata on a single node') + .settings-row + +checkbox('Relaxed consistency', model + '.relaxedConsistency', '"relaxedConsistency"', + 'If value of this flag is <b>true</b>, IGFS will skip expensive consistency checks<br/>\ + It is recommended to set this flag to <b>false</b> if your application has conflicting\ + operations, or you do not know how exactly users will use your system') + .settings-row + +ignite-form-group(ng-model=pathModes ng-form=pathModesForm) + ignite-form-field-label + | Path modes + ignite-form-group-tooltip + | Map of path prefixes to IGFS modes used for them + ignite-form-group-add(ng-click='tableNewItem(tblPathModes)') + | Add path mode + + .group-content-empty(ng-if='!((#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes))') Not defined + + .group-content(ng-show='(#{pathModes} && #{pathModes}.length > 0) || tableNewItemActive(tblPathModes)') + table.links-edit(id='pathModes' st-table=pathModes) + tbody + tr(ng-repeat='item in #{pathModes}') + td.col-sm-12(ng-show='!tableEditing(tblPathModes, $index)') + a.labelFormField(ng-click='tableStartEdit(backupItem, tblPathModes, $index)') {{item.path + " [" + item.mode + "]"}} + +btn-remove('tableRemove(backupItem, tblPathModes, $index)', '"Remove path"') + td.col-sm-12(ng-show='tableEditing(tblPathModes, $index)') + +table-igfs-path-mode-edit('cur', '{{::tblPathModes.focusId + $index}}', '$index') + tfoot(ng-show='tableNewItemActive(tblPathModes)') + tr + td.col-sm-12 + +table-igfs-path-mode-edit('new', 'PathMode', '-1') + + .col-sm-6 + +preview-xml-java(model, 'igfsMisc')
http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade new file mode 100644 index 0000000..0649527 --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/igfs/secondary.jade @@ -0,0 +1,44 @@ +//- + 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 = 'secondaryFileSystem' +-var model = 'backupItem' + +.panel.panel-default(ng-form=form novalidate) + .panel-heading(bs-collapse-toggle='' ng-click='ui.loadPanel("#{form}")') + ignite-form-panel-chevron + label(id="secondaryFileSystem-title") Secondary file system + ignite-form-field-tooltip.tipLabel + | Secondary file system is provided for pass-through, write-through, and read-through purposes + 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 + '.secondaryFileSystemEnabled' + -var secondaryFileSystem = model + '.secondaryFileSystem' + + .settings-row + +checkbox('Enabled', enabled, '"secondaryFileSystemEnabled"', 'Secondary file system enabled flag') + .settings-row + +text-enabled('URI:', secondaryFileSystem + '.uri', '"hadoopURI"', enabled, 'false', 'hdfs://[namenodehost]:[port]/[path]', 'URI of file system') + .settings-row + +text-enabled('Config path:', secondaryFileSystem + '.cfgPath', '"cfgPath"', enabled, 'false', 'Path to additional config', 'Additional path to Hadoop configuration') + .settings-row + +text-enabled('User name:', secondaryFileSystem + '.userName', '"userName"', enabled, 'false', 'Input user name', 'User name') + .col-sm-6 + +preview-xml-java(model, 'igfsSecondFS') http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js b/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js new file mode 100644 index 0000000..be7bf1e --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/preview-panel.directive.js @@ -0,0 +1,239 @@ +/* + * 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 ace from 'brace'; + +export default ['previewPanel', ['$interval', '$timeout', ($interval, $timeout) => { + let animation = {editor: null, stage: 0, start: 0, stop: 0}; + let prevContent = []; + + const Range = ace.acequire('ace/range').Range; + + const _clearSelection = (editor) => { + _.forEach(editor.session.getMarkers(false), (marker) => { + editor.session.removeMarker(marker.id); + }); + }; + + /** + * Switch to next stage of animation. + */ + const _animate = () => { + animation.stage += animation.step; + + const stage = animation.stage; + const editor = animation.editor; + + _clearSelection(editor); + + animation.selections.forEach((selection) => { + editor.session.addMarker(new Range(selection.start, 0, selection.stop, 0), + 'preview-highlight-' + stage, 'line', false); + }); + + if (stage === animation.finalStage) { + editor.animatePromise = null; + + if (animation.clearOnFinal) + _clearSelection(editor); + } + }; + + /** + * Selection with animation. + * + * @param editor Editor to show selection animation. + * @param selections Array of selection intervals. + * @param step Step of animation (1 or -1). + * @param stage Start stage of animation. + * @param finalStage Final stage of animation. + * @param clearOnFinal Boolean flat to clear selection on animation finish. + */ + const _fade = (editor, selections, step, stage, finalStage, clearOnFinal) => { + const promise = editor.animatePromise; + + if (promise) { + $interval.cancel(promise); + + _clearSelection(editor); + } + + animation = {editor, selections, step, stage, finalStage, clearOnFinal}; + + editor.animatePromise = $interval(_animate, 100, 10, false); + }; + + /** + * Show selections with animation. + * + * @param editor Editor to show selection. + * @param selections Array of selection intervals. + */ + const _fadeIn = (editor, selections) => { + _fade(editor, selections, 1, 0, 10, false); + }; + + /** + * Hide selections with animation. + * + * @param editor Editor to show selection. + * @param selections Array of selection intervals. + */ + const _fadeOut = (editor, selections) => { + _fade(editor, selections, -1, 10, 0, true); + }; + + const onChange = ([content, editor]) => { + const {clearPromise} = editor; + const {lines} = content; + + if (content.action === 'remove') + prevContent = lines; + else if (prevContent.length > 0 && lines.length > 0 && editor.attractAttention) { + if (clearPromise) { + $timeout.cancel(clearPromise); + + _clearSelection(editor); + } + + const selections = []; + + let newIx = 0; + let prevIx = 0; + + let prevLen = prevContent.length - (prevContent[prevContent.length - 1] === '' ? 1 : 0); + let newLen = lines.length - (lines[lines.length - 1] === '' ? 1 : 0); + + const removed = newLen < prevLen; + + let skipEnd = 0; + + let selected = false; + let scrollTo = -1; + + while (lines[newLen - 1] === prevContent[prevLen - 1] && newLen > 0 && prevLen > 0) { + prevLen -= 1; + newLen -= 1; + + skipEnd += 1; + } + + while (newIx < newLen || prevIx < prevLen) { + let start = -1; + let stop = -1; + + // Find an index of a first line with different text. + for (; (newIx < newLen || prevIx < prevLen) && start < 0; newIx++, prevIx++) { + if (newIx >= newLen || prevIx >= prevLen || lines[newIx] !== prevContent[prevIx]) { + start = newIx; + + break; + } + } + + if (start >= 0) { + // Find an index of a last line with different text by checking last string of old and new content in reverse order. + for (let i = start; i < newLen && stop < 0; i++) { + for (let j = prevIx; j < prevLen && stop < 0; j++) { + if (lines[i] === prevContent[j] && lines[i] !== '') { + stop = i; + + newIx = i; + prevIx = j; + + break; + } + } + } + + if (stop < 0) { + stop = newLen; + + newIx = newLen; + prevIx = prevLen; + } + + if (start === stop) { + if (removed) + start = Math.max(0, start - 1); + + stop = Math.min(newLen + skipEnd, stop + 1); + } + + if (start <= stop) { + selections.push({start, stop}); + + if (!selected) + scrollTo = start; + + selected = true; + } + } + } + + // Run clear selection one time. + if (selected) { + _fadeIn(editor, selections); + + editor.clearPromise = $timeout(() => { + _fadeOut(editor, selections); + + editor.clearPromise = null; + }, 2000); + + editor.scrollToRow(scrollTo); + } + + prevContent = []; + } + else + editor.attractAttention = true; + }; + + + const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => { + const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2; + + if (!igniteUiAceTabs) + return; + + igniteUiAceTabs.onLoad = (editor) => { + editor.setReadOnly(true); + editor.setOption('highlightActiveLine', false); + editor.setAutoScrollEditorIntoView(true); + editor.$blockScrolling = Infinity; + editor.attractAttention = false; + + const renderer = editor.renderer; + + renderer.setHighlightGutterLine(false); + renderer.setShowPrintMargin(false); + renderer.setOption('fontSize', '10px'); + renderer.setOption('maxLines', '50'); + + editor.setTheme('ace/theme/chrome'); + }; + + igniteUiAceTabs.onChange = onChange; + }; + + return { + restrict: 'C', + link, + require: ['?igniteUiAceTabs', '?^igniteUiAceTabs'] + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js new file mode 100644 index 0000000..f8094af --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary-tabs.directive.js @@ -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. + */ + +export default ['summaryTabs', [() => { + const link = (scope, $element, $attrs, [igniteUiAceTabs1, igniteUiAceTabs2]) => { + const igniteUiAceTabs = igniteUiAceTabs1 || igniteUiAceTabs2; + + if (!igniteUiAceTabs) + return; + + igniteUiAceTabs.onLoad = (editor) => { + editor.setReadOnly(true); + editor.setOption('highlightActiveLine', false); + editor.setAutoScrollEditorIntoView(true); + editor.$blockScrolling = Infinity; + + const renderer = editor.renderer; + + renderer.setHighlightGutterLine(false); + renderer.setShowPrintMargin(false); + renderer.setOption('fontFamily', 'monospace'); + renderer.setOption('fontSize', '12px'); + renderer.setOption('minLines', '25'); + renderer.setOption('maxLines', '25'); + + editor.setTheme('ace/theme/chrome'); + }; + }; + + return { + priority: 1000, + restrict: 'C', + link, + require: ['?igniteUiAceTabs', '?^igniteUiAceTabs'] + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js new file mode 100644 index 0000000..f0cb842 --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/configuration/summary/summary.controller.js @@ -0,0 +1,365 @@ +/* + * 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 _ from 'lodash'; +import JSZip from 'jszip'; +import saver from 'file-saver'; + +export default [ + '$rootScope', '$scope', '$http', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteLoading', '$filter', 'igniteConfigurationResource', 'JavaTypes', 'IgniteVersion', 'GeneratorDocker', 'GeneratorPom', 'IgniteFormUtils', + function($root, $scope, $http, LegacyUtils, Messages, Loading, $filter, Resource, JavaTypes, IgniteVersion, docker, pom, FormUtils) { + const ctrl = this; + + $scope.ui = { ready: false }; + + Loading.start('summaryPage'); + + Resource.read() + .then(Resource.populate) + .then(({clusters}) => { + $scope.clusters = clusters; + $scope.clustersMap = {}; + $scope.clustersView = _.map(clusters, (item) => { + const {_id, name} = item; + + $scope.clustersMap[_id] = item; + + return {_id, name}; + }); + + Loading.finish('summaryPage'); + + $scope.ui.ready = true; + + if (!_.isEmpty(clusters)) { + const idx = sessionStorage.summarySelectedId || 0; + + $scope.selectItem(clusters[idx]); + } + }) + .catch(Messages.showError); + + $scope.contentVisible = (rows, row) => { + return !row || !row._id || _.findIndex(rows, (item) => item._id === row._id) >= 0; + }; + + $scope.widthIsSufficient = FormUtils.widthIsSufficient; + $scope.dialects = {}; + + $scope.projectStructureOptions = { + nodeChildren: 'children', + dirSelectable: false, + injectClasses: { + iExpanded: 'fa fa-folder-open-o', + iCollapsed: 'fa fa-folder-o' + }, + equality: (node1, node2) => { + return node1 === node2; + } + }; + + const javaConfigFolder = { + type: 'folder', + name: 'config', + children: [ + { type: 'file', name: 'ClientConfigurationFactory.java' }, + { type: 'file', name: 'ServerConfigurationFactory.java' } + ] + }; + + const javaStartupFolder = { + type: 'folder', + name: 'startup', + children: [ + { type: 'file', name: 'ClientNodeCodeStartup.java' }, + { type: 'file', name: 'ClientNodeSpringStartup.java' }, + { type: 'file', name: 'ServerNodeCodeStartup.java' }, + { type: 'file', name: 'ServerNodeSpringStartup.java' } + ] + }; + + const demoFolder = { + type: 'folder', + name: 'demo', + children: [ + { type: 'file', name: 'DemoStartup.java' } + ] + }; + + const resourcesFolder = { + type: 'folder', + name: 'resources', + children: [ + { type: 'file', name: 'secret.properties' } + ] + }; + + const javaFolder = { + type: 'folder', + name: 'java', + children: [ + { + type: 'folder', + name: 'config', + children: [ + javaConfigFolder, + javaStartupFolder + ] + } + ] + }; + + const clnCfg = { type: 'file', name: 'client.xml' }; + + const srvCfg = { type: 'file', name: 'server.xml' }; + + const mainFolder = { + type: 'folder', + name: 'main', + children: [javaFolder] + }; + + const projectStructureRoot = { + type: 'folder', + name: 'project.zip', + children: [ + { + type: 'folder', + name: 'config', + children: [clnCfg, srvCfg] + }, + { + type: 'folder', + name: 'jdbc-drivers', + children: [ + { type: 'file', name: 'README.txt' } + ] + }, + { + type: 'folder', + name: 'src', + children: [mainFolder] + }, + { type: 'file', name: '.dockerignore' }, + { type: 'file', name: 'Dockerfile' }, + { type: 'file', name: 'pom.xml' }, + { type: 'file', name: 'README.txt' } + ] + }; + + $scope.projectStructure = [projectStructureRoot]; + + $scope.projectStructureExpanded = [projectStructureRoot]; + + $scope.tabsServer = { activeTab: 0 }; + $scope.tabsClient = { activeTab: 0 }; + + /** + * + * @param {Object} node - Tree node. + * @param {string[]} path - Path to find. + * @returns {Object} Tree node. + */ + function getOrCreateFolder(node, path) { + if (_.isEmpty(path)) + return node; + + const leaf = path.shift(); + + let children = null; + + if (!_.isEmpty(node.children)) { + children = _.find(node.children, {type: 'folder', name: leaf}); + + if (children) + return getOrCreateFolder(children, path); + } + + children = {type: 'folder', name: leaf, children: []}; + + node.children.push(children); + + node.children = _.orderBy(node.children, ['type', 'name'], ['desc', 'asc']); + + return getOrCreateFolder(children, path); + } + + function addClass(fullClsName) { + const path = fullClsName.split('.'); + const leaf = {type: 'file', name: path.pop() + '.java'}; + const folder = getOrCreateFolder(javaFolder, path); + + if (!_.find(folder.children, leaf)) + folder.children.push(leaf); + } + + $scope.selectItem = (cluster) => { + delete ctrl.cluster; + + if (!cluster) + return; + + cluster = $scope.clustersMap[cluster._id]; + + ctrl.cluster = cluster; + + $scope.cluster = cluster; + $scope.selectedItem = cluster; + $scope.dialects = {}; + + sessionStorage.summarySelectedId = $scope.clusters.indexOf(cluster); + + mainFolder.children = [javaFolder]; + javaFolder.children = [javaConfigFolder, javaStartupFolder]; + + if ($generatorCommon.secretPropertiesNeeded(cluster)) + mainFolder.children.push(resourcesFolder); + + if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode)) + javaFolder.children.push(demoFolder); + + if (cluster.discovery.kind === 'Jdbc' && cluster.discovery.Jdbc.dialect) + $scope.dialects[cluster.discovery.Jdbc.dialect] = true; + + _.forEach(cluster.caches, (cache) => { + if (cache.cacheStoreFactory) { + const store = cache.cacheStoreFactory[cache.cacheStoreFactory.kind]; + + if (store && store.dialect) + $scope.dialects[store.dialect] = true; + } + + _.forEach(cache.domains, (domain) => { + if (!_.isEmpty(domain.keyFields)) { + if (JavaTypes.nonBuiltInClass(domain.keyType)) + addClass(domain.keyType); + + addClass(domain.valueType); + } + }); + }); + + projectStructureRoot.name = cluster.name + '-project.zip'; + clnCfg.name = cluster.name + '-client.xml'; + srvCfg.name = cluster.name + '-server.xml'; + }; + + $scope.$watch('cluster', (cluster) => { + if (!cluster) + return; + + if (!$filter('hasPojo')(cluster) && $scope.tabsClient.activeTab === 3) + $scope.tabsClient.activeTab = 0; + }); + + $scope.$watch('cluster._id', () => { + $scope.tabsClient.init = []; + $scope.tabsServer.init = []; + }); + + // TODO IGNITE-2114: implemented as independent logic for download. + $scope.downloadConfiguration = function() { + const cluster = $scope.cluster; + const clientNearCfg = cluster.clientNearCfg; + + const zip = new JSZip(); + + if (!ctrl.data) + ctrl.data = {}; + + if (!ctrl.data.docker) + ctrl.data.docker = docker.generate(cluster, 'latest'); + + zip.file('Dockerfile', ctrl.data.docker); + zip.file('.dockerignore', docker.ignoreFile()); + + const builder = $generatorProperties.generateProperties(cluster); + + if (builder) + zip.file('src/main/resources/secret.properties', builder.asString()); + + const srcPath = 'src/main/java/'; + + const serverXml = 'config/' + cluster.name + '-server.xml'; + const clientXml = 'config/' + cluster.name + '-client.xml'; + + zip.file(serverXml, $generatorXml.cluster(cluster)); + zip.file(clientXml, $generatorXml.cluster(cluster, clientNearCfg)); + + zip.file(srcPath + 'config/ServerConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ServerConfigurationFactory', null)); + zip.file(srcPath + 'config/ClientConfigurationFactory.java', $generatorJava.cluster(cluster, 'config', 'ClientConfigurationFactory', clientNearCfg)); + + if ($generatorJava.isDemoConfigured(cluster, $root.IgniteDemoMode)) { + zip.file(srcPath + 'demo/DemoStartup.java', $generatorJava.nodeStartup(cluster, 'demo', 'DemoStartup', + 'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory')); + } + + zip.file(srcPath + 'startup/ServerNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeSpringStartup', '"' + serverXml + '"')); + zip.file(srcPath + 'startup/ClientNodeSpringStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeSpringStartup', '"' + clientXml + '"')); + + zip.file(srcPath + 'startup/ServerNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ServerNodeCodeStartup', + 'ServerConfigurationFactory.createConfiguration()', 'config.ServerConfigurationFactory')); + zip.file(srcPath + 'startup/ClientNodeCodeStartup.java', $generatorJava.nodeStartup(cluster, 'startup', 'ClientNodeCodeStartup', + 'ClientConfigurationFactory.createConfiguration()', 'config.ClientConfigurationFactory', clientNearCfg)); + + zip.file('pom.xml', pom.generate(cluster, IgniteVersion.version).asString()); + + zip.file('README.txt', $generatorReadme.readme().asString()); + zip.file('jdbc-drivers/README.txt', $generatorReadme.readmeJdbc().asString()); + + if (!ctrl.data.pojos) + ctrl.data.pojos = $generatorJava.pojos(cluster.caches); + + for (const pojo of ctrl.data.pojos) { + if (pojo.keyClass && JavaTypes.nonBuiltInClass(pojo.keyType)) + zip.file(srcPath + pojo.keyType.replace(/\./g, '/') + '.java', pojo.keyClass); + + zip.file(srcPath + pojo.valueType.replace(/\./g, '/') + '.java', pojo.valueClass); + } + + $generatorOptional.optionalContent(zip, cluster); + + zip.generateAsync({type: 'blob', compression: 'DEFLATE', mimeType: 'application/octet-stream'}) + .then((blob) => saver.saveAs(blob, cluster.name + '-project.zip')); + }; + + /** + * @returns {boolean} 'true' if at least one proprietary JDBC driver is configured for cache store. + */ + $scope.downloadJdbcDriversVisible = function() { + const dialects = $scope.dialects; + + return !!(dialects.Oracle || dialects.DB2 || dialects.SQLServer); + }; + + /** + * Open download proprietary JDBC driver pages. + */ + $scope.downloadJdbcDrivers = function() { + const dialects = $scope.dialects; + + if (dialects.Oracle) + window.open('http://www.oracle.com/technetwork/apps-tech/jdbc-112010-090769.html'); + + if (dialects.DB2) + window.open('http://www-01.ibm.com/support/docview.wss?uid=swg21363866'); + + if (dialects.SQLServer) + window.open('https://www.microsoft.com/en-us/download/details.aspx?id=11774'); + }; + } +]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/errors.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/errors.state.js b/modules/web-console/frontend/app/modules/states/errors.state.js new file mode 100644 index 0000000..2bdb80a --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/errors.state.js @@ -0,0 +1,43 @@ +/* + * 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 templateNotFoundPage from '../../../views/404.jade'; +import templateNotAuthorizedPage from '../../../views/403.jade'; + +angular + .module('ignite-console.states.errors', [ + 'ui.router' + ]) + .config(['$stateProvider', 'AclRouteProvider', function($stateProvider) { + // set up the states + $stateProvider + .state('404', { + url: '/404', + templateUrl: templateNotFoundPage, + metaTags: { + title: 'Page not found' + } + }) + .state('403', { + url: '/403', + templateUrl: templateNotAuthorizedPage, + metaTags: { + title: 'Not authorized' + } + }); + }]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/logout.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/logout.state.js b/modules/web-console/frontend/app/modules/states/logout.state.js new file mode 100644 index 0000000..42795ea --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/logout.state.js @@ -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. + */ + +import angular from 'angular'; + +angular +.module('ignite-console.states.logout', [ + 'ui.router' +]) +.config(['$stateProvider', 'AclRouteProvider', function($stateProvider, AclRoute) { + // set up the states + $stateProvider + .state('logout', { + url: '/logout', + onEnter: AclRoute.checkAccess('logout'), + controller: ['Auth', (Auth) => Auth.logout()], + metaTags: { + title: 'Logout' + } + }); +}]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/password.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/password.state.js b/modules/web-console/frontend/app/modules/states/password.state.js new file mode 100644 index 0000000..48d01df --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/password.state.js @@ -0,0 +1,46 @@ +/* + * 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'; + +angular +.module('ignite-console.states.password', [ + 'ui.router' +]) +.config(['$stateProvider', function($stateProvider) { + // set up the states + $stateProvider + .state('password', { + url: '/password', + abstract: true, + template: '<ui-view></ui-view>' + }) + .state('password.reset', { + url: '/reset?{token}', + templateUrl: '/reset.html', + metaTags: { + title: 'Reset password' + } + }) + .state('password.send', { + url: '/send', + templateUrl: '/reset.html', + metaTags: { + title: 'Password Send' + } + }); +}]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/profile.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/profile.state.js b/modules/web-console/frontend/app/modules/states/profile.state.js new file mode 100644 index 0000000..9c31340 --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/profile.state.js @@ -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. + */ + +import angular from 'angular'; + +angular +.module('ignite-console.states.profile', [ + 'ui.router' +]) +.config(['$stateProvider', 'AclRouteProvider', function($stateProvider, AclRoute) { + // set up the states + $stateProvider + .state('settings.profile', { + url: '/profile', + templateUrl: '/settings/profile.html', + onEnter: AclRoute.checkAccess('profile'), + metaTags: { + title: 'User profile' + } + }); +}]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/states/signin.state.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/states/signin.state.js b/modules/web-console/frontend/app/modules/states/signin.state.js new file mode 100644 index 0000000..14ebc1b --- /dev/null +++ b/modules/web-console/frontend/app/modules/states/signin.state.js @@ -0,0 +1,43 @@ +/* + * 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 templateUrl from 'views/signin.jade'; + +angular +.module('ignite-console.states.login', [ + 'ui.router', + // services + 'ignite-console.user' +]) +.config(['$stateProvider', 'AclRouteProvider', function($stateProvider) { + // set up the states + $stateProvider + .state('signin', { + url: '/', + templateUrl, + resolve: { + user: ['$state', 'User', ($state, User) => { + return User.read() + .then(() => $state.go('base.configuration.clusters')) + .catch(() => {}); + }] + }, + metaTags: { + } + }); +}]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/AclRoute.provider.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/user/AclRoute.provider.js b/modules/web-console/frontend/app/modules/user/AclRoute.provider.js new file mode 100644 index 0000000..40abea5 --- /dev/null +++ b/modules/web-console/frontend/app/modules/user/AclRoute.provider.js @@ -0,0 +1,47 @@ +/* + * 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. + */ + +export default [() => { + class AclRoute { + static checkAccess = (permissions, failState) => { + failState = failState || '403'; + + return ['$state', 'AclService', 'User', ($state, AclService, User) => { + User.read() + .then(() => { + if (AclService.can(permissions)) + return; + + return $state.go(failState); + }) + .catch(() => { + User.clean(); + + if ($state.current.name !== 'signin') + $state.go('signin'); + }); + }]; + } + } + + return { + checkAccess: AclRoute.checkAccess, + $get: () => { + return AclRoute; + } + }; +}]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/Auth.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/user/Auth.service.js b/modules/web-console/frontend/app/modules/user/Auth.service.js new file mode 100644 index 0000000..43e2f92 --- /dev/null +++ b/modules/web-console/frontend/app/modules/user/Auth.service.js @@ -0,0 +1,56 @@ +/* + * 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. + */ + +export default ['Auth', ['$http', '$rootScope', '$state', '$window', 'IgniteErrorPopover', 'IgniteMessages', 'gettingStarted', 'User', 'IgniteAgentMonitor', + ($http, $root, $state, $window, ErrorPopover, Messages, gettingStarted, User, agentMonitor) => { + return { + forgotPassword(userInfo) { + $http.post('/api/v1/password/forgot', userInfo) + .success(() => $state.go('password.send')) + .error((err) => ErrorPopover.show('forgot_email', Messages.errorMessage(null, err))); + }, + auth(action, userInfo) { + $http.post('/api/v1/' + action, userInfo) + .catch(({data}) => Promise.reject(data)) + .then(() => { + if (action === 'password/forgot') + return; + + User.read() + .then((user) => { + $root.$broadcast('user', user); + + $state.go('base.configuration.clusters'); + + agentMonitor.init(); + + $root.gettingStarted.tryShow(); + }); + }) + .catch((err) => ErrorPopover.show(action + '_email', Messages.errorMessage(null, err))); + }, + logout() { + $http.post('/api/v1/logout') + .success(() => { + User.clean(); + + $window.open($state.href('signin'), '_self'); + }) + .error(Messages.showError); + } + }; + }]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/User.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/user/User.service.js b/modules/web-console/frontend/app/modules/user/User.service.js new file mode 100644 index 0000000..8b9a1e7 --- /dev/null +++ b/modules/web-console/frontend/app/modules/user/User.service.js @@ -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. + */ + +export default ['User', ['$q', '$injector', '$rootScope', '$state', '$http', function($q, $injector, $root, $state, $http) { + let user; + + return { + load() { + return user = $http.post('/api/v1/user') + .then(({data}) => { + $root.user = data; + + $root.$broadcast('user', $root.user); + + return $root.user; + }) + .catch(({data}) => { + user = null; + + return $q.reject(data); + }); + }, + read() { + if (user) + return user; + + return this.load(); + }, + clean() { + delete $root.user; + + delete $root.IgniteDemoMode; + + sessionStorage.removeItem('IgniteDemoMode'); + } + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/permissions.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/user/permissions.js b/modules/web-console/frontend/app/modules/user/permissions.js new file mode 100644 index 0000000..e13509c --- /dev/null +++ b/modules/web-console/frontend/app/modules/user/permissions.js @@ -0,0 +1,28 @@ +/* + * 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 guest = ['login']; +const becomed = ['profile', 'configuration', 'query']; +const user = becomed.concat(['logout']); +const admin = user.concat(['admin_page']); + +export default { + guest, + user, + admin, + becomed +}; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/user/user.module.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/user/user.module.js b/modules/web-console/frontend/app/modules/user/user.module.js new file mode 100644 index 0000000..11798d0 --- /dev/null +++ b/modules/web-console/frontend/app/modules/user/user.module.js @@ -0,0 +1,73 @@ +/* + * 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 aclData from './permissions'; + +import Auth from './Auth.service'; +import User from './User.service'; +import AclRouteProvider from './AclRoute.provider'; + +angular +.module('ignite-console.user', [ + 'mm.acl', + 'ignite-console.config' +]) +.factory('sessionRecoverer', ['$injector', '$q', ($injector, $q) => { + return { + responseError: (response) => { + // Session has expired + if (response.status === 401) { + $injector.get('User').clean(); + + const $state = $injector.get('$state'); + + if ($state.current.name !== 'signin') + $state.go('signin'); + } + + return $q.reject(response); + } + }; +}]) +.config(['$httpProvider', ($httpProvider) => { + $httpProvider.interceptors.push('sessionRecoverer'); +}]) +.service(...Auth) +.service(...User) +.provider('AclRoute', AclRouteProvider) +.run(['$rootScope', 'AclService', ($root, AclService) => { + AclService.setAbilities(aclData); + AclService.attachRole('guest'); + + $root.$on('user', (event, user) => { + if (!user) + return; + + AclService.flushRoles(); + + let role = 'user'; + + if (user.admin) + role = 'admin'; + + if (user.becomeUsed) + role = 'becomed'; + + AclService.attachRole(role); + }); +}]); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/modules/version/Version.provider.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/version/Version.provider.js b/modules/web-console/frontend/app/modules/version/Version.provider.js new file mode 100644 index 0000000..fe503ab --- /dev/null +++ b/modules/web-console/frontend/app/modules/version/Version.provider.js @@ -0,0 +1,32 @@ +/* + * 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'; + +angular + .module('ignite-console.version', []) + .provider('IgniteVersion', function() { + const version = { + version: '1.6.0' + }; + + this.update = (newVersion) => { + version.version = newVersion; + }; + + this.$get = [() => version]; + }); http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ChartColors.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/ChartColors.service.js b/modules/web-console/frontend/app/services/ChartColors.service.js new file mode 100644 index 0000000..843aa5c --- /dev/null +++ b/modules/web-console/frontend/app/services/ChartColors.service.js @@ -0,0 +1,22 @@ +/* + * 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 COLORS from 'app/data/colors.json'; + +export default ['IgniteChartColors', function() { + return COLORS; +}]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Clone.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Clone.service.js b/modules/web-console/frontend/app/services/Clone.service.js new file mode 100644 index 0000000..52a4e4e --- /dev/null +++ b/modules/web-console/frontend/app/services/Clone.service.js @@ -0,0 +1,64 @@ +/* + * 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. + */ + +// Service for clone objects. +export default ['IgniteClone', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => { + const scope = $root.$new(); + + let _names = []; + let deferred; + let _validator; + + function _nextAvailableName(name) { + let num = 1; + let tmpName = name; + + while (_.includes(_names, tmpName)) { + tmpName = name + '_' + num.toString(); + + num++; + } + + return tmpName; + } + + const cloneModal = $modal({templateUrl: '/templates/clone.html', scope, placement: 'center', show: false}); + + scope.ok = function(newName) { + if (!_validator || _validator(newName)) { + deferred.resolve(_nextAvailableName(newName)); + + cloneModal.hide(); + } + }; + + cloneModal.confirm = function(oldName, names, validator) { + _names = names; + + scope.newName = _nextAvailableName(oldName); + + _validator = validator; + + deferred = $q.defer(); + + cloneModal.$promise.then(cloneModal.show); + + return deferred.promise; + }; + + return cloneModal; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Confirm.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Confirm.service.js b/modules/web-console/frontend/app/services/Confirm.service.js new file mode 100644 index 0000000..8208ea2 --- /dev/null +++ b/modules/web-console/frontend/app/services/Confirm.service.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. + */ + +// Confirm popup service. +export default ['IgniteConfirm', ['$rootScope', '$q', '$modal', '$animate', ($root, $q, $modal, $animate) => { + const scope = $root.$new(); + + const modal = $modal({templateUrl: '/templates/confirm.html', scope, placement: 'center', show: false, backdrop: true}); + + const _hide = () => { + $animate.enabled(modal.$element, false); + + modal.hide(); + }; + + let deferred; + + scope.confirmYes = () => { + _hide(); + + deferred.resolve(true); + }; + + scope.confirmNo = () => { + _hide(); + + deferred.resolve(false); + }; + + scope.confirmCancel = () => { + _hide(); + + deferred.reject('cancelled'); + }; + + /** + * + * @param {String } content + * @param {Boolean} [yesNo] + * @returns {Promise} + */ + modal.confirm = (content, yesNo) => { + scope.content = content || 'Confirm?'; + scope.yesNo = !!yesNo; + + deferred = $q.defer(); + + modal.$promise.then(modal.show); + + return deferred.promise; + }; + + return modal; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ConfirmBatch.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/ConfirmBatch.service.js b/modules/web-console/frontend/app/services/ConfirmBatch.service.js new file mode 100644 index 0000000..ef66335 --- /dev/null +++ b/modules/web-console/frontend/app/services/ConfirmBatch.service.js @@ -0,0 +1,92 @@ +/* + * 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. + */ + +// Service for confirm or skip several steps. +export default ['IgniteConfirmBatch', ['$rootScope', '$q', '$modal', ($root, $q, $modal) => { + const scope = $root.$new(); + + scope.confirmModal = $modal({ + templateUrl: '/templates/batch-confirm.html', + scope, + placement: 'center', + show: false, + backdrop: 'static', + keyboard: false + }); + + const _done = (cancel) => { + scope.confirmModal.hide(); + + if (cancel) + scope.deferred.reject('cancelled'); + else + scope.deferred.resolve(); + }; + + const _nextElement = (skip) => { + scope.items[scope.curIx++].skip = skip; + + if (scope.curIx < scope.items.length) + scope.content = scope.contentGenerator(scope.items[scope.curIx]); + else + _done(); + }; + + scope.cancel = () => { + _done(true); + }; + + scope.skip = (applyToAll) => { + if (applyToAll) { + for (let i = scope.curIx; i < scope.items.length; i++) + scope.items[i].skip = true; + + _done(); + } + else + _nextElement(true); + }; + + scope.overwrite = (applyToAll) => { + if (applyToAll) + _done(); + else + _nextElement(false); + }; + + return { + /** + * Show confirm all dialog. + * + * @param confirmMessageFn Function to generate a confirm message. + * @param itemsToConfirm Array of element to process by confirm. + */ + confirm(confirmMessageFn, itemsToConfirm) { + scope.deferred = $q.defer(); + + scope.contentGenerator = confirmMessageFn; + + scope.items = itemsToConfirm; + scope.curIx = 0; + scope.content = (scope.items && scope.items.length > 0) ? scope.contentGenerator(scope.items[0]) : null; + + scope.confirmModal.$promise.then(scope.confirmModal.show); + + return scope.deferred.promise; + } + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/CopyToClipboard.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/CopyToClipboard.service.js b/modules/web-console/frontend/app/services/CopyToClipboard.service.js new file mode 100644 index 0000000..74c4764 --- /dev/null +++ b/modules/web-console/frontend/app/services/CopyToClipboard.service.js @@ -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. + */ + +// Service to copy some value to OS clipboard. +export default ['IgniteCopyToClipboard', ['$window', 'IgniteMessages', ($window, Messages) => { + const body = angular.element($window.document.body); + + const textArea = angular.element('<textarea/>'); + + textArea.css({ + position: 'fixed', + opacity: '0' + }); + + return { + copy(toCopy) { + textArea.val(toCopy); + + body.append(textArea); + + textArea[0].select(); + + try { + if (document.execCommand('copy')) + Messages.showInfo('Value copied to clipboard'); + else + window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy); // eslint-disable-line no-alert + } + catch (err) { + window.prompt('Copy to clipboard: Ctrl+C, Enter', toCopy); // eslint-disable-line no-alert + } + + textArea.remove(); + } + }; +}]]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Countries.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Countries.service.js b/modules/web-console/frontend/app/services/Countries.service.js new file mode 100644 index 0000000..5ad3e6a --- /dev/null +++ b/modules/web-console/frontend/app/services/Countries.service.js @@ -0,0 +1,31 @@ +/* + * 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 COUNTRIES from 'app/data/countries.json'; + +export default ['IgniteCountries', function() { + const indexByName = _.keyBy(COUNTRIES, 'name'); + const UNDEFINED_COUNTRY = {name: '', code: ''}; + + const getByName = (name) => (indexByName[name] || UNDEFINED_COUNTRY); + const getAll = () => (COUNTRIES); + + return { + getByName, + getAll + }; +}]; http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/ErrorPopover.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/ErrorPopover.service.js b/modules/web-console/frontend/app/services/ErrorPopover.service.js new file mode 100644 index 0000000..85e4fda --- /dev/null +++ b/modules/web-console/frontend/app/services/ErrorPopover.service.js @@ -0,0 +1,126 @@ +/* + * 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. + */ + +export default class ErrorPopover { + static $inject = ['$popover', '$anchorScroll', '$location', '$timeout', 'IgniteFormUtils']; + + /** + * @param $popover + * @param $anchorScroll + * @param $location + * @param $timeout + * @param FormUtils + */ + constructor($popover, $anchorScroll, $location, $timeout, FormUtils) { + this.$popover = $popover; + this.$anchorScroll = $anchorScroll; + this.$location = $location; + this.$timeout = $timeout; + this.FormUtils = FormUtils; + + this.$anchorScroll.yOffset = 55; + + this._popover = null; + } + + /** + * Check that element is document area. + * + * @param el Element to check. + * @returns {boolean} True when element in document area. + */ + static _isElementInViewport(el) { + const rect = el.getBoundingClientRect(); + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); + } + + /** + * Internal show popover message with detected properties. + * + * @param id Id element to show popover message. + * @param message Message to show. + * @param showTime Time before popover will be hidden. + */ + _show(id, message, showTime = 5000) { + const body = $('body'); + + let el = body.find('#' + id); + + if (!el || el.length === 0) + el = body.find('[name="' + id + '"]'); + + if (el && el.length > 0) { + if (!ErrorPopover._isElementInViewport(el[0])) { + this.$location.hash(el[0].id); + + this.$anchorScroll(); + } + + const newPopover = this.$popover(el, {content: message}); + + this._popover = newPopover; + + this.$timeout(() => newPopover.$promise.then(() => { + newPopover.show(); + + // Workaround to fix popover location when content is longer than content template. + // https://github.com/mgcrea/angular-strap/issues/1497 + this.$timeout(newPopover.$applyPlacement); + }), 400); + this.$timeout(() => newPopover.hide(), showTime); + } + } + + /** + * Show popover message. + * + * @param {String} id ID of element to show popover. + * @param {String} message Message to show. + * @param {Object} [ui] Form UI object. When specified extend section with that name. + * @param {String} [panelId] ID of element owner panel. When specified focus element with that ID. + * @param {Number} [showTime] Time before popover will be hidden. 5 sec when not specified. + * @returns {boolean} False always. + */ + show(id, message, ui, panelId, showTime) { + if (this._popover) + this._popover.hide(); + + if (ui) { + this.FormUtils.ensureActivePanel(ui, panelId, id); + + this.$timeout(() => this._show(id, message, showTime), ui.isPanelLoaded(panelId) ? 200 : 500); + } + else + this._show(id, message); + + return false; + } + + /** + * Hide popover message. + */ + hide() { + if (this._popover) + this._popover.hide(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/6af6560a/modules/web-console/frontend/app/services/Focus.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Focus.service.js b/modules/web-console/frontend/app/services/Focus.service.js new file mode 100644 index 0000000..a07e181 --- /dev/null +++ b/modules/web-console/frontend/app/services/Focus.service.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// Service to transfer focus for specified element. +export default ['IgniteFocus', ['$timeout', ($timeout) => { + return { + move(id) { + // Timeout makes sure that is invoked after any other event has been triggered. + // E.g. click events that need to run before the focus or inputs elements that are + // in a disabled state but are enabled when those events are triggered. + $timeout(() => { + const elem = $('#' + id); + + if (elem.length > 0) + elem[0].focus(); + }, 100); + } + }; +}]];
