You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/09/13 09:53:24 UTC
[32/69] [abbrv] ignite git commit: Web Console beta-3.
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);
+ }
+ };
+}]];