You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2018/04/02 12:24:42 UTC
[19/24] ignite git commit: IGNITE-5466 Web Console: Configuration
reworked to cluster centric model: 1. Reworked data model. 2. Implemented
migrations. 3. Reworked UI for all screens. 4. Reworked validation. 5. Many
refactorings to improve code base
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-download-project/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-download-project/index.js b/modules/web-console/frontend/app/components/page-configure/components/button-download-project/index.js
new file mode 100644
index 0000000..4a220db
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-download-project/index.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import {component} from './component';
+
+export default angular
+.module('configuration.button-download-project', [])
+.component(component.name, component);
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-download-project/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-download-project/template.pug b/modules/web-console/frontend/app/components/page-configure/components/button-download-project/template.pug
new file mode 100644
index 0000000..0264676
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-download-project/template.pug
@@ -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.
+
+button.btn-ignite.btn-ignite--success(
+ type='button'
+ ng-click='$ctrl.download()'
+)
+ svg(ignite-icon='download').icon-left
+ | Download project
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-import-models/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-import-models/component.js b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/component.js
new file mode 100644
index 0000000..28b7aa0
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/component.js
@@ -0,0 +1,37 @@
+/*
+ * 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 template from './template.pug';
+import './style.scss';
+
+export class ButtonImportModels {
+ static $inject = ['ModalImportModels'];
+ constructor(ModalImportModels) {
+ Object.assign(this, {ModalImportModels});
+ }
+ startImport() {
+ return this.ModalImportModels.open(this.clusterID);
+ }
+}
+export const component = {
+ name: 'buttonImportModels',
+ controller: ButtonImportModels,
+ template,
+ bindings: {
+ clusterID: '<clusterId'
+ }
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-import-models/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-import-models/index.js b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/index.js
new file mode 100644
index 0000000..b7ef527
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/index.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import {component} from './component';
+
+export default angular
+.module('configuration.button-import-models', [])
+.component(component.name, component);
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-import-models/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-import-models/style.scss b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/style.scss
new file mode 100644
index 0000000..4944626
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/style.scss
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+button-import-models {
+ display: inline-block;
+
+ button {
+ // Ensures same height for wrapper element and button
+ vertical-align: top;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-import-models/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-import-models/template.pug b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/template.pug
new file mode 100644
index 0000000..25c3531
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-import-models/template.pug
@@ -0,0 +1,20 @@
+//-
+ 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.
+
+button.btn-ignite.btn-ignite--primary(
+ ng-click='$ctrl.startImport()'
+ type='button'
+) Import from Database
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/component.js b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/component.js
new file mode 100644
index 0000000..095cb0f
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/component.js
@@ -0,0 +1,36 @@
+/*
+ * 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 template from './template.pug';
+
+export class ButtonPreviewProject {
+ static $inject = ['ModalPreviewProject'];
+ constructor(ModalPreviewProject) {
+ Object.assign(this, {ModalPreviewProject});
+ }
+ preview() {
+ return this.ModalPreviewProject.open(this.cluster);
+ }
+}
+export const component = {
+ name: 'buttonPreviewProject',
+ controller: ButtonPreviewProject,
+ template,
+ bindings: {
+ cluster: '<'
+ }
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/index.js b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/index.js
new file mode 100644
index 0000000..d5f6191
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/index.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import angular from 'angular';
+import {component} from './component';
+
+export default angular
+.module('configuration.button-preview-project', [])
+.component(component.name, component);
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/template.pug b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/template.pug
new file mode 100644
index 0000000..3c3ca38
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/button-preview-project/template.pug
@@ -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.
+
+button.btn-ignite.btn-ignite--link-dashed-success(
+ type='button'
+ ng-click='$ctrl.preview()'
+)
+ svg(ignite-icon='structure').icon-left
+ | See project structure
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/fakeUICanExit.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/fakeUICanExit.js b/modules/web-console/frontend/app/components/page-configure/components/fakeUICanExit.js
new file mode 100644
index 0000000..c0837ed
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/fakeUICanExit.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+class FakeUiCanExitController {
+ static $inject = ['$element', '$transitions'];
+ static CALLBACK_NAME = 'uiCanExit';
+ constructor($element, $transitions) {
+ Object.assign(this, {$element, $transitions});
+ }
+ $onInit() {
+ const data = this.$element.data();
+ const {CALLBACK_NAME} = this.constructor;
+ const controllerWithCallback = Object.keys(data)
+ .map((key) => data[key])
+ .find((controller) => controller[CALLBACK_NAME]);
+ if (!controllerWithCallback) return;
+ const off = this.$transitions.onBefore({from: this.fromState}, (...args) => {
+ return controllerWithCallback[CALLBACK_NAME](...args);
+ });
+ }
+ $onDestroy() {
+ if (this.off) this.off();
+ this.$element = null;
+ }
+}
+
+export default function fakeUiCanExit() {
+ return {
+ bindToController: {
+ fromState: '@fakeUiCanExit'
+ },
+ controller: FakeUiCanExitController
+ };
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js b/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js
new file mode 100644
index 0000000..0225c5f
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/formUICanExitGuard.js
@@ -0,0 +1,59 @@
+/*
+ * 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 {default as ConfigChangesGuard} from '../services/ConfigChangesGuard';
+
+class FormUICanExitGuardController {
+ static $inject = ['$element', ConfigChangesGuard.name];
+ /**
+ * @param {JQLite} $element
+ * @param {ConfigChangesGuard} ConfigChangesGuard
+ */
+ constructor($element, ConfigChangesGuard) {
+ this.$element = $element;
+ this.ConfigChangesGuard = ConfigChangesGuard;
+ }
+ $onDestroy() {
+ this.$element = null;
+ }
+ $onInit() {
+ const data = this.$element.data();
+ const controller = Object.keys(data)
+ .map((key) => data[key])
+ .find(this._itQuacks);
+
+ if (!controller) return;
+
+ controller.uiCanExit = ($transition$) => {
+ if ($transition$.options().custom.justIDUpdate) return true;
+ $transition$.onSuccess({}, controller.reset);
+ return this.ConfigChangesGuard.guard(...controller.getValuesToCompare());
+ };
+ }
+ _itQuacks(controller) {
+ return controller.reset instanceof Function &&
+ controller.getValuesToCompare instanceof Function &&
+ !controller.uiCanExit;
+ }
+}
+
+export default function formUiCanExitGuard() {
+ return {
+ priority: 10,
+ controller: FormUICanExitGuardController
+ };
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js
new file mode 100644
index 0000000..7f852b0
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/component.js
@@ -0,0 +1,1151 @@
+/*
+ * 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 templateUrl from './template.tpl.pug';
+import './style.scss';
+import _ from 'lodash';
+import naturalCompare from 'natural-compare-lite';
+import find from 'lodash/fp/find';
+import get from 'lodash/fp/get';
+import {Observable} from 'rxjs/Observable';
+import ObjectID from 'bson-objectid';
+import {uniqueName} from 'app/utils/uniqueName';
+import {defaultNames} from '../../defaultNames';
+
+// eslint-disable-next-line
+import {UIRouter} from '@uirouter/angularjs'
+import {default as IgniteConfirmBatch} from 'app/services/ConfirmBatch.service';
+import {default as ConfigSelectors} from 'app/components/page-configure/store/selectors';
+import {default as ConfigEffects} from 'app/components/page-configure/store/effects';
+import {default as ConfigureState} from 'app/components/page-configure/services/ConfigureState';
+// eslint-disable-next-line
+import {default as AgentManager} from 'app/modules/agent/AgentModal.service'
+import {default as SqlTypes} from 'app/services/SqlTypes.service';
+import {default as JavaTypes} from 'app/services/JavaTypes.service';
+// eslint-disable-next-line
+import {default as ActivitiesData} from 'app/core/activities/Activities.data';
+
+function _mapCaches(caches = []) {
+ return caches.map((cache) => {
+ return {label: cache.name, value: cache._id, cache};
+ });
+}
+
+const INFO_CONNECT_TO_DB = 'Configure connection to database';
+const INFO_SELECT_SCHEMAS = 'Select schemas to load tables from';
+const INFO_SELECT_TABLES = 'Select tables to import as domain model';
+const INFO_SELECT_OPTIONS = 'Select import domain model options';
+const LOADING_JDBC_DRIVERS = {text: 'Loading JDBC drivers...'};
+const LOADING_SCHEMAS = {text: 'Loading schemas...'};
+const LOADING_TABLES = {text: 'Loading tables...'};
+const SAVING_DOMAINS = {text: 'Saving domain model...'};
+
+const IMPORT_DM_NEW_CACHE = 1;
+const IMPORT_DM_ASSOCIATE_CACHE = 2;
+
+const DFLT_PARTITIONED_CACHE = {
+ label: 'PARTITIONED',
+ value: -1,
+ cache: {
+ name: 'PARTITIONED',
+ cacheMode: 'PARTITIONED',
+ atomicityMode: 'ATOMIC',
+ readThrough: true,
+ writeThrough: true
+ }
+};
+
+const DFLT_REPLICATED_CACHE = {
+ label: 'REPLICATED',
+ value: -2,
+ cache: {
+ name: 'REPLICATED',
+ cacheMode: 'REPLICATED',
+ atomicityMode: 'ATOMIC',
+ readThrough: true,
+ writeThrough: true
+ }
+};
+
+const CACHE_TEMPLATES = [DFLT_PARTITIONED_CACHE, DFLT_REPLICATED_CACHE];
+
+export class ModalImportModels {
+ /**
+ * Cluster ID to import models into
+ * @type {string}
+ */
+ clusterID;
+
+ /** @type {ng.ICompiledExpression} */
+ onHide;
+
+ static $inject = ['$uiRouter', ConfigSelectors.name, ConfigEffects.name, ConfigureState.name, '$http', 'IgniteConfirm', IgniteConfirmBatch.name, 'IgniteFocus', SqlTypes.name, JavaTypes.name, 'IgniteMessages', '$scope', '$rootScope', 'AgentManager', 'IgniteActivitiesData', 'IgniteLoading', 'IgniteFormUtils', 'IgniteLegacyUtils'];
+ /**
+ * @param {UIRouter} $uiRouter
+ * @param {ConfigSelectors} ConfigSelectors
+ * @param {ConfigEffects} ConfigEffects
+ * @param {ConfigureState} ConfigureState
+ * @param {ng.IHttpService} $http
+ * @param {IgniteConfirmBatch} ConfirmBatch
+ * @param {SqlTypes} SqlTypes
+ * @param {JavaTypes} JavaTypes
+ * @param {ng.IScope} $scope
+ * @param {ng.IRootScopeService} $root
+ * @param {AgentManager} agentMgr
+ * @param {ActivitiesData} ActivitiesData
+ */
+ constructor($uiRouter, ConfigSelectors, ConfigEffects, ConfigureState, $http, Confirm, ConfirmBatch, Focus, SqlTypes, JavaTypes, Messages, $scope, $root, agentMgr, ActivitiesData, Loading, FormUtils, LegacyUtils) {
+ this.$uiRouter = $uiRouter;
+ this.ConfirmBatch = ConfirmBatch;
+ this.$http = $http;
+ this.ConfigSelectors = ConfigSelectors;
+ this.ConfigEffects = ConfigEffects;
+ this.ConfigureState = ConfigureState;
+ this.$root = $root;
+ this.$scope = $scope;
+ this.agentMgr = agentMgr;
+ this.JavaTypes = JavaTypes;
+ this.SqlTypes = SqlTypes;
+ this.ActivitiesData = ActivitiesData;
+ Object.assign(this, {Confirm, Focus, Messages, Loading, FormUtils, LegacyUtils});
+ }
+ loadData() {
+ return Observable.of(this.clusterID)
+ .switchMap((id = 'new') => {
+ return this.ConfigureState.state$.let(this.ConfigSelectors.selectClusterToEdit(id, defaultNames.importedCluster));
+ })
+ .switchMap((cluster) => {
+ return (!(cluster.caches || []).length && !(cluster.models || []).length)
+ ? Observable.of({
+ cluster,
+ caches: [],
+ models: []
+ })
+ : Observable.fromPromise(Promise.all([
+ this.ConfigEffects.etp('LOAD_SHORT_CACHES', {ids: cluster.caches || [], clusterID: cluster._id}),
+ this.ConfigEffects.etp('LOAD_SHORT_MODELS', {ids: cluster.models || [], clusterID: cluster._id})
+ ]))
+ .switchMap(() => {
+ return Observable.combineLatest(
+ this.ConfigureState.state$.let(this.ConfigSelectors.selectShortCachesValue()),
+ this.ConfigureState.state$.let(this.ConfigSelectors.selectShortModelsValue()),
+ (caches, models) => ({
+ cluster,
+ caches,
+ models
+ })
+ ).take(1);
+ });
+ })
+ .take(1);
+ }
+ saveBatch(batch) {
+ if (!batch.length) return;
+ this.Loading.start('importDomainFromDb');
+ this.ConfigureState.dispatchAction({
+ type: 'ADVANCED_SAVE_COMPLETE_CONFIGURATION',
+ changedItems: this.batchActionsToRequestBody(batch),
+ prevActions: []
+ });
+ this.saveSubscription = Observable.race(
+ this.ConfigureState.actions$.filter((a) => a.type === 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_OK')
+ .do(() => this.onHide()),
+ this.ConfigureState.actions$.filter((a) => a.type === 'ADVANCED_SAVE_COMPLETE_CONFIGURATION_ERR')
+ )
+ .take(1)
+ .do(() => {
+ this.Loading.finish('importDomainFromDb');
+ })
+ .subscribe();
+ }
+ batchActionsToRequestBody(batch) {
+ const result = batch.reduce((req, action) => {
+ return {
+ ...req,
+ cluster: {
+ ...req.cluster,
+ models: [...req.cluster.models, action.newDomainModel._id],
+ caches: [...req.cluster.caches, ...action.newDomainModel.caches]
+ },
+ models: [...req.models, action.newDomainModel],
+ caches: action.newCache
+ ? [...req.caches, action.newCache]
+ : action.cacheStoreChanges
+ ? [...req.caches, {
+ ...this.loadedCaches[action.cacheStoreChanges[0].cacheId],
+ ...action.cacheStoreChanges[0].change
+ }]
+ : req.caches
+ };
+ }, {cluster: this.cluster, models: [], caches: [], igfss: []});
+ result.cluster.models = [...new Set(result.cluster.models)];
+ result.cluster.caches = [...new Set(result.cluster.caches)];
+ return result;
+ }
+ onTableSelectionChange(selected) {
+ this.$scope.$applyAsync(() => {
+ this.$scope.importDomain.tablesToUse = selected;
+ this.selectedTablesIDs = selected.map((t) => t.id);
+ });
+ }
+ onSchemaSelectionChange(selected) {
+ this.$scope.$applyAsync(() => {
+ this.$scope.importDomain.schemasToUse = selected;
+ this.selectedSchemasIDs = selected.map((i) => i.name);
+ });
+ }
+ onVisibleRowsChange(rows) {
+ return this.visibleTables = rows.map((r) => r.entity);
+ }
+ onCacheSelect(cacheID) {
+ if (cacheID < 0) return;
+ if (this.loadedCaches[cacheID]) return;
+ return this.onCacheSelectSubcription = Observable.merge(
+ Observable.timer(0, 1).take(1)
+ .do(() => this.ConfigureState.dispatchAction({type: 'LOAD_CACHE', cacheID})),
+ Observable.race(
+ this.ConfigureState.actions$
+ .filter((a) => a.type === 'LOAD_CACHE_OK' && a.cache._id === cacheID).pluck('cache')
+ .do((cache) => {
+ this.loadedCaches[cacheID] = cache;
+ }),
+ this.ConfigureState.actions$
+ .filter((a) => a.type === 'LOAD_CACHE_ERR' && a.action.cacheID === cacheID)
+ ).take(1)
+ )
+ .subscribe();
+ }
+ $onDestroy() {
+ this.subscription.unsubscribe();
+ if (this.onCacheSelectSubcription) this.onCacheSelectSubcription.unsubscribe();
+ if (this.saveSubscription) this.saveSubscription.unsubscribe();
+ }
+ $onInit() {
+ // Restores old behavior
+ const {$http, Confirm, ConfirmBatch, Focus, SqlTypes, JavaTypes, Messages, $scope, $root, agentMgr, ActivitiesData, Loading, FormUtils, LegacyUtils} = this;
+
+ /**
+ * Convert some name to valid java package name.
+ *
+ * @param name to convert.
+ * @returns {string} Valid java package name.
+ */
+ const _toJavaPackage = (name) => {
+ return name ? name.replace(/[^A-Za-z_0-9/.]+/g, '_') : 'org';
+ };
+
+ const importDomainModal = {
+ hide: () => {
+ agentMgr.stopWatch();
+ this.onHide();
+ }
+ };
+
+ const _makeDefaultPackageName = (user) => user
+ ? _toJavaPackage(`${user.email.replace('@', '.').split('.').reverse().join('.')}.model`)
+ : void 0;
+
+ this.$scope.ui = {
+ generatePojo: true,
+ builtinKeys: true,
+ generateKeyFields: true,
+ usePrimitives: true,
+ generateTypeAliases: true,
+ generateFieldAliases: true,
+ packageNameUserInput: _makeDefaultPackageName($root.user)
+ };
+ this.$scope.$hide = importDomainModal.hide;
+
+ this.$scope.importCommon = {};
+
+ this.subscription = this.loadData().do((data) => {
+ this.$scope.caches = _mapCaches(data.caches);
+ this.$scope.domains = data.models;
+ this.caches = data.caches;
+ this.cluster = data.cluster;
+
+ if (!_.isEmpty(this.$scope.caches)) {
+ this.$scope.importActions.push({
+ label: 'Associate with existing cache',
+ shortLabel: 'Associate',
+ value: IMPORT_DM_ASSOCIATE_CACHE
+ });
+ }
+ this.$scope.$watch('importCommon.action', this._fillCommonCachesOrTemplates(this.$scope.importCommon), true);
+ this.$scope.importCommon.action = IMPORT_DM_NEW_CACHE;
+ }).subscribe();
+
+ // New
+
+ this.loadedCaches = {
+ ...CACHE_TEMPLATES.reduce((a, c) => ({...a, [c.value]: c.cache}), {})
+ };
+ this.actions = [
+ {value: 'connect', label: this.$root.IgniteDemoMode ? 'Description' : 'Connection'},
+ {value: 'schemas', label: 'Schemas'},
+ {value: 'tables', label: 'Tables'},
+ {value: 'options', label: 'Options'}
+ ];
+
+ // Legacy
+
+ $scope.ui.invalidKeyFieldsTooltip = 'Found key types without configured key fields<br/>' +
+ 'It may be a result of import tables from database without primary keys<br/>' +
+ 'Key field for such key types should be configured manually';
+
+ $scope.indexType = LegacyUtils.mkOptions(['SORTED', 'FULLTEXT', 'GEOSPATIAL']);
+
+ $scope.importActions = [{
+ label: 'Create new cache by template',
+ shortLabel: 'Create',
+ value: IMPORT_DM_NEW_CACHE
+ }];
+
+
+ const _dbPresets = [
+ {
+ db: 'Oracle',
+ jdbcDriverClass: 'oracle.jdbc.OracleDriver',
+ jdbcUrl: 'jdbc:oracle:thin:@[host]:[port]:[database]',
+ user: 'system'
+ },
+ {
+ db: 'DB2',
+ jdbcDriverClass: 'com.ibm.db2.jcc.DB2Driver',
+ jdbcUrl: 'jdbc:db2://[host]:[port]/[database]',
+ user: 'db2admin'
+ },
+ {
+ db: 'SQLServer',
+ jdbcDriverClass: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
+ jdbcUrl: 'jdbc:sqlserver://[host]:[port][;databaseName=database]'
+ },
+ {
+ db: 'PostgreSQL',
+ jdbcDriverClass: 'org.postgresql.Driver',
+ jdbcUrl: 'jdbc:postgresql://[host]:[port]/[database]',
+ user: 'sa'
+ },
+ {
+ db: 'MySQL',
+ jdbcDriverClass: 'com.mysql.jdbc.Driver',
+ jdbcUrl: 'jdbc:mysql://[host]:[port]/[database]',
+ user: 'root'
+ },
+ {
+ db: 'MySQL',
+ jdbcDriverClass: 'org.mariadb.jdbc.Driver',
+ jdbcUrl: 'jdbc:mariadb://[host]:[port]/[database]',
+ user: 'root'
+ },
+ {
+ db: 'H2',
+ jdbcDriverClass: 'org.h2.Driver',
+ jdbcUrl: 'jdbc:h2:tcp://[host]/[database]',
+ user: 'sa'
+ }
+ ];
+
+ $scope.selectedPreset = {
+ db: 'Generic',
+ jdbcDriverJar: '',
+ jdbcDriverClass: '',
+ jdbcUrl: 'jdbc:[database]',
+ user: 'sa',
+ password: '',
+ tablesOnly: true
+ };
+
+ $scope.demoConnection = {
+ db: 'H2',
+ jdbcDriverClass: 'org.h2.Driver',
+ jdbcUrl: 'jdbc:h2:mem:demo-db',
+ user: 'sa',
+ password: '',
+ tablesOnly: true
+ };
+
+ function _loadPresets() {
+ try {
+ const restoredPresets = JSON.parse(localStorage.dbPresets);
+
+ _.forEach(restoredPresets, (restoredPreset) => {
+ const preset = _.find(_dbPresets, {jdbcDriverClass: restoredPreset.jdbcDriverClass});
+
+ if (preset) {
+ preset.jdbcUrl = restoredPreset.jdbcUrl;
+ preset.user = restoredPreset.user;
+ }
+ });
+ }
+ catch (ignore) {
+ // No-op.
+ }
+ }
+
+ _loadPresets();
+
+ function _savePreset(preset) {
+ try {
+ const oldPreset = _.find(_dbPresets, {jdbcDriverClass: preset.jdbcDriverClass});
+
+ if (oldPreset)
+ _.assign(oldPreset, preset);
+ else
+ _dbPresets.push(preset);
+
+ localStorage.dbPresets = JSON.stringify(_dbPresets);
+ }
+ catch (err) {
+ Messages.showError(err);
+ }
+ }
+
+ function _findPreset(selectedJdbcJar) {
+ let result = _.find(_dbPresets, function(preset) {
+ return preset.jdbcDriverClass === selectedJdbcJar.jdbcDriverClass;
+ });
+
+ if (!result)
+ result = {db: 'Generic', jdbcUrl: 'jdbc:[database]', user: 'admin'};
+
+ result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
+ result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
+
+ return result;
+ }
+
+ function isValidJavaIdentifier(s) {
+ return JavaTypes.validIdentifier(s) && !JavaTypes.isKeyword(s) && JavaTypes.nonBuiltInClass(s) &&
+ SqlTypes.validIdentifier(s) && !SqlTypes.isKeyword(s);
+ }
+
+ function toJavaIdentifier(name) {
+ if (_.isEmpty(name))
+ return 'DB';
+
+ const len = name.length;
+
+ let ident = '';
+
+ let capitalizeNext = true;
+
+ for (let i = 0; i < len; i++) {
+ const ch = name.charAt(i);
+
+ if (ch === ' ' || ch === '_')
+ capitalizeNext = true;
+ else if (ch === '-') {
+ ident += '_';
+ capitalizeNext = true;
+ }
+ else if (capitalizeNext) {
+ ident += ch.toLocaleUpperCase();
+
+ capitalizeNext = false;
+ }
+ else
+ ident += ch.toLocaleLowerCase();
+ }
+
+ return ident;
+ }
+
+ function toJavaClassName(name) {
+ const clazzName = toJavaIdentifier(name);
+
+ if (isValidJavaIdentifier(clazzName))
+ return clazzName;
+
+ return 'Class' + clazzName;
+ }
+
+ function toJavaFieldName(dbName) {
+ const javaName = toJavaIdentifier(dbName);
+
+ const fieldName = javaName.charAt(0).toLocaleLowerCase() + javaName.slice(1);
+
+ if (isValidJavaIdentifier(fieldName))
+ return fieldName;
+
+ return 'field' + javaName;
+ }
+
+ /**
+ * Load list of database schemas.
+ */
+ const _loadSchemas = () => {
+ agentMgr.awaitAgent()
+ .then(function() {
+ $scope.importDomain.loadingOptions = LOADING_SCHEMAS;
+ Loading.start('importDomainFromDb');
+
+ if ($root.IgniteDemoMode)
+ return agentMgr.schemas($scope.demoConnection);
+
+ const preset = $scope.selectedPreset;
+
+ _savePreset(preset);
+
+ return agentMgr.schemas(preset);
+ })
+ .then((schemaInfo) => {
+ $scope.importDomain.action = 'schemas';
+ $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+ $scope.importDomain.catalog = toJavaIdentifier(schemaInfo.catalog);
+ $scope.importDomain.schemas = _.map(schemaInfo.schemas, (schema) => ({name: schema}));
+ $scope.importDomain.schemasToUse = $scope.importDomain.schemas;
+ this.selectedSchemasIDs = $scope.importDomain.schemas.map((s) => s.name);
+
+ if ($scope.importDomain.schemas.length === 0)
+ $scope.importDomainNext();
+ })
+ .catch(Messages.showError)
+ .then(() => Loading.finish('importDomainFromDb'));
+ };
+
+
+ this._importCachesOrTemplates = [];
+
+ $scope.tableActionView = (tbl) => {
+ const cacheName = get('label')(find({value: tbl.cacheOrTemplate}));
+
+ if (tbl.action === IMPORT_DM_NEW_CACHE)
+ return 'Create ' + tbl.generatedCacheName + ' (' + cacheName + ')';
+
+ return 'Associate with ' + cacheName;
+ };
+
+ /**
+ * Load list of database tables.
+ */
+ const _loadTables = () => {
+ agentMgr.awaitAgent()
+ .then(() => {
+ $scope.importDomain.loadingOptions = LOADING_TABLES;
+ Loading.start('importDomainFromDb');
+
+ $scope.importDomain.allTablesSelected = false;
+ this.selectedTables = [];
+
+ const preset = $scope.importDomain.demo ? $scope.demoConnection : $scope.selectedPreset;
+
+ preset.schemas = $scope.importDomain.schemasToUse.map((s) => s.name);
+
+ return agentMgr.tables(preset);
+ })
+ .then((tables) => {
+ this._importCachesOrTemplates = CACHE_TEMPLATES.concat($scope.caches);
+
+ this._fillCommonCachesOrTemplates($scope.importCommon)($scope.importCommon.action);
+
+ _.forEach(tables, (tbl, idx) => {
+ tbl.id = idx;
+ tbl.action = IMPORT_DM_NEW_CACHE;
+ // tbl.generatedCacheName = toJavaClassName(tbl.table) + 'Cache';
+ tbl.generatedCacheName = uniqueName(toJavaClassName(tbl.table) + 'Cache', this.caches);
+ tbl.cacheOrTemplate = DFLT_PARTITIONED_CACHE.value;
+ tbl.label = tbl.schema + '.' + tbl.table;
+ tbl.edit = false;
+ });
+
+ $scope.importDomain.action = 'tables';
+ $scope.importDomain.tables = tables;
+ const tablesToUse = tables.filter((t) => LegacyUtils.isDefined(_.find(t.columns, (col) => col.key)));
+ this.selectedTablesIDs = tablesToUse.map((t) => t.id);
+ this.$scope.importDomain.tablesToUse = tablesToUse;
+
+ $scope.importDomain.info = INFO_SELECT_TABLES;
+ })
+ .catch(Messages.showError)
+ .then(() => Loading.finish('importDomainFromDb'));
+ };
+
+ $scope.applyDefaults = () => {
+ _.forEach(this.visibleTables, (table) => {
+ table.edit = false;
+ table.action = $scope.importCommon.action;
+ table.cacheOrTemplate = $scope.importCommon.cacheOrTemplate;
+ });
+ };
+
+ $scope._curDbTable = null;
+
+ $scope.startEditDbTableCache = (tbl) => {
+ if ($scope._curDbTable) {
+ $scope._curDbTable.edit = false;
+
+ if ($scope._curDbTable.actionWatch) {
+ $scope._curDbTable.actionWatch();
+
+ $scope._curDbTable.actionWatch = null;
+ }
+ }
+
+ $scope._curDbTable = tbl;
+
+ const _fillFn = this._fillCommonCachesOrTemplates($scope._curDbTable);
+
+ _fillFn($scope._curDbTable.action);
+
+ $scope._curDbTable.actionWatch = $scope.$watch('_curDbTable.action', _fillFn, true);
+
+ $scope._curDbTable.edit = true;
+ };
+
+ /**
+ * Show page with import domain models options.
+ */
+ function _selectOptions() {
+ $scope.importDomain.action = 'options';
+ $scope.importDomain.button = 'Save';
+ $scope.importDomain.info = INFO_SELECT_OPTIONS;
+
+ Focus.move('domainPackageName');
+ }
+
+ const _saveDomainModel = (optionsForm) => {
+ if (optionsForm.$invalid)
+ return this.FormUtils.triggerValidation(optionsForm, this.$scope);
+
+ const generatePojo = $scope.ui.generatePojo;
+ const packageName = $scope.ui.packageName;
+
+ const batch = [];
+ const checkedCaches = [];
+
+ let containKey = true;
+ let containDup = false;
+
+ function dbField(name, jdbcType, nullable, unsigned) {
+ const javaTypes = (unsigned && jdbcType.unsigned) ? jdbcType.unsigned : jdbcType.signed;
+ const javaFieldType = (!nullable && javaTypes.primitiveType && $scope.ui.usePrimitives) ? javaTypes.primitiveType : javaTypes.javaType;
+
+ return {
+ databaseFieldName: name,
+ databaseFieldType: jdbcType.dbName,
+ javaType: javaTypes.javaType,
+ javaFieldName: toJavaFieldName(name),
+ javaFieldType
+ };
+ }
+
+ _.forEach($scope.importDomain.tablesToUse, (table, curIx, tablesToUse) => {
+ const qryFields = [];
+ const indexes = [];
+ const keyFields = [];
+ const valFields = [];
+ const aliases = [];
+
+ const tableName = table.table;
+ let typeName = toJavaClassName(tableName);
+
+ if (_.find($scope.importDomain.tablesToUse,
+ (tbl, ix) => ix !== curIx && tableName === tbl.table)) {
+ typeName = typeName + '_' + toJavaClassName(table.schema);
+
+ containDup = true;
+ }
+
+ let valType = tableName;
+ let typeAlias;
+
+ if (generatePojo) {
+ if ($scope.ui.generateTypeAliases && tableName.toLowerCase() !== typeName.toLowerCase())
+ typeAlias = tableName;
+
+ valType = _toJavaPackage(packageName) + '.' + typeName;
+ }
+
+ let _containKey = false;
+
+ _.forEach(table.columns, function(col) {
+ const fld = dbField(col.name, SqlTypes.findJdbcType(col.type), col.nullable, col.unsigned);
+
+ qryFields.push({name: fld.javaFieldName, className: fld.javaType});
+
+ const dbName = fld.databaseFieldName;
+
+ if (generatePojo && $scope.ui.generateFieldAliases &&
+ SqlTypes.validIdentifier(dbName) && !SqlTypes.isKeyword(dbName) &&
+ !_.find(aliases, {field: fld.javaFieldName}) &&
+ fld.javaFieldName.toUpperCase() !== dbName.toUpperCase())
+ aliases.push({field: fld.javaFieldName, alias: dbName});
+
+ if (col.key) {
+ keyFields.push(fld);
+
+ _containKey = true;
+ }
+ else
+ valFields.push(fld);
+ });
+
+ containKey &= _containKey;
+ if (table.indexes) {
+ _.forEach(table.indexes, (idx) => {
+ const idxFields = _.map(idx.fields, (idxFld) => ({
+ name: toJavaFieldName(idxFld.name),
+ direction: idxFld.sortOrder
+ }));
+
+ indexes.push({
+ name: idx.name,
+ indexType: 'SORTED',
+ fields: idxFields
+ });
+ });
+ }
+
+ const domainFound = _.find($scope.domains, (domain) => domain.valueType === valType);
+
+ const batchAction = {
+ confirm: false,
+ skip: false,
+ table,
+ newDomainModel: {
+ _id: ObjectID.generate(),
+ caches: [],
+ generatePojo
+ }
+ };
+
+ if (LegacyUtils.isDefined(domainFound)) {
+ batchAction.newDomainModel._id = domainFound._id;
+ // Don't touch original caches value
+ delete batchAction.newDomainModel.caches;
+ batchAction.confirm = true;
+ }
+
+ Object.assign(batchAction.newDomainModel, {
+ tableName: typeAlias,
+ keyType: valType + 'Key',
+ valueType: valType,
+ queryMetadata: 'Configuration',
+ databaseSchema: table.schema,
+ databaseTable: tableName,
+ fields: qryFields,
+ queryKeyFields: _.map(keyFields, (field) => field.javaFieldName),
+ indexes,
+ keyFields,
+ aliases,
+ valueFields: _.isEmpty(valFields) ? keyFields.slice() : valFields
+ });
+
+ // Use Java built-in type for key.
+ if ($scope.ui.builtinKeys && batchAction.newDomainModel.keyFields.length === 1) {
+ const newDomain = batchAction.newDomainModel;
+ const keyField = newDomain.keyFields[0];
+
+ newDomain.keyType = keyField.javaType;
+ newDomain.keyFieldName = keyField.javaFieldName;
+
+ if (!$scope.ui.generateKeyFields) {
+ // Exclude key column from query fields.
+ newDomain.fields = _.filter(newDomain.fields, (field) => field.name !== keyField.javaFieldName);
+
+ newDomain.queryKeyFields = [];
+ }
+
+ // Exclude key column from indexes.
+ _.forEach(newDomain.indexes, (index) => {
+ index.fields = _.filter(index.fields, (field) => field.name !== keyField.javaFieldName);
+ });
+
+ newDomain.indexes = _.filter(newDomain.indexes, (index) => !_.isEmpty(index.fields));
+ }
+
+ // Prepare caches for generation.
+ if (table.action === IMPORT_DM_NEW_CACHE) {
+ const newCache = angular.copy(this.loadedCaches[table.cacheOrTemplate]);
+
+ batchAction.newCache = newCache;
+
+ // const siblingCaches = batch.filter((a) => a.newCache).map((a) => a.newCache);
+ const siblingCaches = [];
+ newCache._id = ObjectID.generate();
+ newCache.name = uniqueName(typeName + 'Cache', this.caches.concat(siblingCaches));
+ newCache.domains = [batchAction.newDomainModel._id];
+ batchAction.newDomainModel.caches = [newCache._id];
+
+ // POJO store factory is not defined in template.
+ if (!newCache.cacheStoreFactory || newCache.cacheStoreFactory.kind !== 'CacheJdbcPojoStoreFactory') {
+ const dialect = $scope.importDomain.demo ? 'H2' : $scope.selectedPreset.db;
+
+ const catalog = $scope.importDomain.catalog;
+
+ newCache.cacheStoreFactory = {
+ kind: 'CacheJdbcPojoStoreFactory',
+ CacheJdbcPojoStoreFactory: {
+ dataSourceBean: 'ds' + dialect + '_' + catalog,
+ dialect
+ },
+ CacheJdbcBlobStoreFactory: { connectVia: 'DataSource' }
+ };
+ }
+
+ if (!newCache.readThrough && !newCache.writeThrough) {
+ newCache.readThrough = true;
+ newCache.writeThrough = true;
+ }
+ }
+ else {
+ const newDomain = batchAction.newDomainModel;
+ const cacheId = table.cacheOrTemplate;
+
+ batchAction.newDomainModel.caches = [cacheId];
+
+ if (!_.includes(checkedCaches, cacheId)) {
+ const cache = _.find($scope.caches, {value: cacheId}).cache;
+
+ // TODO: move elsewhere, make sure it still works
+ const change = LegacyUtils.autoCacheStoreConfiguration(cache, [newDomain]);
+
+ if (change)
+ batchAction.cacheStoreChanges = [{cacheId, change}];
+
+ checkedCaches.push(cacheId);
+ }
+ }
+
+ batch.push(batchAction);
+ });
+
+ /**
+ * Generate message to show on confirm dialog.
+ *
+ * @param meta Object to confirm.
+ * @returns {string} Generated message.
+ */
+ function overwriteMessage(meta) {
+ return `
+ Domain model with name "${meta.newDomainModel.databaseTable}" already exists.
+ Are you sure you want to overwrite it?
+ `;
+ }
+
+ const itemsToConfirm = _.filter(batch, (item) => item.confirm);
+
+ const checkOverwrite = () => {
+ if (itemsToConfirm.length > 0) {
+ return ConfirmBatch.confirm(overwriteMessage, itemsToConfirm)
+ .then(() => this.saveBatch(_.filter(batch, (item) => !item.skip)))
+ .catch(() => Messages.showError('Importing of domain models interrupted by user.'));
+ }
+ return this.saveBatch(batch);
+ };
+
+ const checkDuplicate = () => {
+ if (containDup) {
+ Confirm.confirm('Some tables have the same name.<br/>' +
+ 'Name of types for that tables will contain schema name too.')
+ .then(() => checkOverwrite());
+ }
+ else
+ checkOverwrite();
+ };
+
+ if (containKey)
+ checkDuplicate();
+ else {
+ Confirm.confirm('Some tables have no primary key.<br/>' +
+ 'You will need to configure key type and key fields for such tables after import complete.')
+ .then(() => checkDuplicate());
+ }
+ };
+
+
+ $scope.importDomainNext = (form) => {
+ if (!$scope.importDomainNextAvailable())
+ return;
+
+ const act = $scope.importDomain.action;
+
+ if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+ importDomainModal.hide();
+ else if (act === 'connect')
+ _loadSchemas();
+ else if (act === 'schemas')
+ _loadTables();
+ else if (act === 'tables')
+ _selectOptions();
+ else if (act === 'options')
+ _saveDomainModel(form);
+ };
+
+ $scope.nextTooltipText = function() {
+ const importDomainNextAvailable = $scope.importDomainNextAvailable();
+
+ const act = $scope.importDomain.action;
+
+ if (act === 'drivers' && $scope.importDomain.jdbcDriversNotFound)
+ return 'Resolve issue with JDBC drivers<br>Close this dialog and try again';
+
+ if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcDriverClass))
+ return 'Input valid JDBC driver class name';
+
+ if (act === 'connect' && _.isNil($scope.selectedPreset.jdbcUrl))
+ return 'Input valid JDBC URL';
+
+ if (act === 'connect' || act === 'drivers')
+ return 'Click to load list of schemas from database';
+
+ if (act === 'schemas')
+ return importDomainNextAvailable ? 'Click to load list of tables from database' : 'Select schemas to continue';
+
+ if (act === 'tables')
+ return importDomainNextAvailable ? 'Click to show import options' : 'Select tables to continue';
+
+ if (act === 'options')
+ return 'Click to import domain model for selected tables';
+
+ return 'Click to continue';
+ };
+
+ $scope.prevTooltipText = function() {
+ const act = $scope.importDomain.action;
+
+ if (act === 'schemas')
+ return $scope.importDomain.demo ? 'Click to return on demo description step' : 'Click to return on connection configuration step';
+
+ if (act === 'tables')
+ return 'Click to return on schemas selection step';
+
+ if (act === 'options')
+ return 'Click to return on tables selection step';
+ };
+
+ $scope.importDomainNextAvailable = function() {
+ switch ($scope.importDomain.action) {
+ case 'connect':
+ return !_.isNil($scope.selectedPreset.jdbcDriverClass) && !_.isNil($scope.selectedPreset.jdbcUrl);
+
+ case 'schemas':
+ return _.isEmpty($scope.importDomain.schemas) || !!get('importDomain.schemasToUse.length')($scope);
+
+ case 'tables':
+ return !!$scope.importDomain.tablesToUse.length;
+
+ default:
+ return true;
+ }
+ };
+
+ $scope.importDomainPrev = function() {
+ $scope.importDomain.button = 'Next';
+
+ if ($scope.importDomain.action === 'options') {
+ $scope.importDomain.action = 'tables';
+ $scope.importDomain.info = INFO_SELECT_TABLES;
+ }
+ else if ($scope.importDomain.action === 'tables' && $scope.importDomain.schemas.length > 0) {
+ $scope.importDomain.action = 'schemas';
+ $scope.importDomain.info = INFO_SELECT_SCHEMAS;
+ }
+ else {
+ $scope.importDomain.action = 'connect';
+ $scope.importDomain.info = INFO_CONNECT_TO_DB;
+ }
+ };
+
+ const demo = $root.IgniteDemoMode;
+
+ $scope.importDomain = {
+ demo,
+ action: demo ? 'connect' : 'drivers',
+ jdbcDriversNotFound: demo,
+ schemas: [],
+ allSchemasSelected: false,
+ tables: [],
+ allTablesSelected: false,
+ button: 'Next',
+ info: ''
+ };
+
+ $scope.importDomain.loadingOptions = LOADING_JDBC_DRIVERS;
+
+ agentMgr.startAgentWatch('Back', this.$uiRouter.globals.current.name)
+ .then(() => {
+ ActivitiesData.post({
+ group: 'configuration',
+ action: 'configuration/import/model'
+ });
+
+ return true;
+ })
+ .then(() => {
+ if (demo) {
+ $scope.ui.packageNameUserInput = $scope.ui.packageName;
+ $scope.ui.packageName = 'model';
+
+ return;
+ }
+
+ // Get available JDBC drivers via agent.
+ Loading.start('importDomainFromDb');
+
+ $scope.jdbcDriverJars = [];
+ $scope.ui.selectedJdbcDriverJar = {};
+
+ return agentMgr.drivers()
+ .then((drivers) => {
+ $scope.ui.packageName = $scope.ui.packageNameUserInput;
+
+ if (drivers && drivers.length > 0) {
+ drivers = _.sortBy(drivers, 'jdbcDriverJar');
+
+ _.forEach(drivers, (drv) => {
+ $scope.jdbcDriverJars.push({
+ label: drv.jdbcDriverJar,
+ value: {
+ jdbcDriverJar: drv.jdbcDriverJar,
+ jdbcDriverClass: drv.jdbcDriverCls
+ }
+ });
+ });
+
+ $scope.ui.selectedJdbcDriverJar = $scope.jdbcDriverJars[0].value;
+
+ // FormUtils.confirmUnsavedChanges(dirty, () => {
+ $scope.importDomain.action = 'connect';
+ $scope.importDomain.tables = [];
+ this.selectedTables = [];
+
+ // Focus.move('jdbcUrl');
+ // });
+ }
+ else {
+ $scope.importDomain.jdbcDriversNotFound = true;
+ $scope.importDomain.button = 'Cancel';
+ }
+ })
+ .then(() => {
+ $scope.importDomain.info = INFO_CONNECT_TO_DB;
+
+ Loading.finish('importDomainFromDb');
+ });
+ });
+
+ $scope.$watch('ui.selectedJdbcDriverJar', function(val) {
+ if (val && !$scope.importDomain.demo) {
+ const foundPreset = _findPreset(val);
+
+ const selectedPreset = $scope.selectedPreset;
+
+ selectedPreset.db = foundPreset.db;
+ selectedPreset.jdbcDriverJar = foundPreset.jdbcDriverJar;
+ selectedPreset.jdbcDriverClass = foundPreset.jdbcDriverClass;
+ selectedPreset.jdbcUrl = foundPreset.jdbcUrl;
+ selectedPreset.user = foundPreset.user;
+ }
+ }, true);
+ }
+
+ _fillCommonCachesOrTemplates(item) {
+ return (action) => {
+ if (item.cachesOrTemplates)
+ item.cachesOrTemplates.length = 0;
+ else
+ item.cachesOrTemplates = [];
+
+ if (action === IMPORT_DM_NEW_CACHE)
+ item.cachesOrTemplates.push(...CACHE_TEMPLATES);
+
+ if (!_.isEmpty(this.$scope.caches)) {
+ item.cachesOrTemplates.push(...this.$scope.caches);
+ this.onCacheSelect(item.cachesOrTemplates[0].value);
+ }
+
+ if (
+ !_.find(item.cachesOrTemplates, {value: item.cacheOrTemplate}) &&
+ item.cachesOrTemplates.length
+ )
+ item.cacheOrTemplate = item.cachesOrTemplates[0].value;
+ };
+ }
+
+ schemasColumnDefs = [
+ {
+ name: 'name',
+ displayName: 'Name',
+ field: 'name',
+ enableHiding: false,
+ sort: {direction: 'asc', priority: 0},
+ filter: {
+ placeholder: 'Filter by Name…'
+ },
+ visible: true,
+ sortingAlgorithm: naturalCompare,
+ minWidth: 165
+ }
+ ];
+
+ tablesColumnDefs = [
+ {
+ name: 'schema',
+ displayName: 'Schema',
+ field: 'schema',
+ enableHiding: false,
+ enableFiltering: false,
+ sort: {direction: 'asc', priority: 0},
+ visible: true,
+ sortingAlgorithm: naturalCompare,
+ minWidth: 100
+ },
+ {
+ name: 'table',
+ displayName: 'Table',
+ field: 'table',
+ enableHiding: false,
+ enableFiltering: true,
+ filter: {
+ placeholder: 'Filter by Table…'
+ },
+ visible: true,
+ sortingAlgorithm: naturalCompare,
+ minWidth: 200
+ },
+ {
+ name: 'action',
+ displayName: 'Action',
+ field: 'action',
+ enableHiding: false,
+ enableFiltering: false,
+ cellTemplate: `
+ <tables-action-cell
+ table='row.entity'
+ on-edit-start='grid.appScope.$ctrl.$scope.startEditDbTableCache($event)'
+ on-cache-select='grid.appScope.$ctrl.onCacheSelect($event)'
+ caches='grid.appScope.$ctrl._importCachesOrTemplates'
+ import-actions='grid.appScope.$ctrl.$scope.importActions'
+ ></tables-action-cell>
+ `,
+ visible: true,
+ minWidth: 500
+ }
+ ];
+}
+
+export const component = {
+ name: 'modalImportModels',
+ controller: ModalImportModels,
+ templateUrl,
+ bindings: {
+ onHide: '&',
+ clusterID: '<clusterId'
+ }
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/index.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/index.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/index.js
new file mode 100644
index 0000000..b75c89a
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/index.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 angular from 'angular';
+import {component} from './component';
+import service from './service';
+import {component as stepIndicator} from './step-indicator/component';
+import {component as tablesActionCell} from './tables-action-cell/component';
+import {component as amountIndicator} from './selected-items-amount-indicator/component';
+
+export default angular
+.module('configuration.modal-import-models', [])
+.service(service.name, service)
+.component(tablesActionCell.name, tablesActionCell)
+.component(stepIndicator.name, stepIndicator)
+.component(amountIndicator.name, amountIndicator)
+.component(component.name, component);
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/component.js
new file mode 100644
index 0000000..26a6ea0
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/component.js
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import template from './template.pug';
+import './style.scss';
+export const component = {
+ name: 'selectedItemsAmountIndicator',
+ template,
+ bindings: {
+ selectedAmount: '<',
+ totalAmount: '<'
+ }
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/style.scss b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/style.scss
new file mode 100644
index 0000000..c5c2a05
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/style.scss
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+selected-items-amount-indicator {
+ font-family: Roboto;
+ font-size: 14px;
+ font-style: italic;
+ color: #757575;
+ display: inline-block;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/template.pug b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/template.pug
new file mode 100644
index 0000000..9a46a77
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/selected-items-amount-indicator/template.pug
@@ -0,0 +1,17 @@
+//-
+ 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.
+
+| {{ $ctrl.selectedAmount || 0}} of {{ $ctrl.totalAmount }} selected
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/service.js
new file mode 100644
index 0000000..3c0ecbb
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/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 class ModalImportModels {
+ static $inject = ['$modal', 'AgentManager', '$uiRouter'];
+ constructor($modal, AgentManager, $uiRouter) {
+ Object.assign(this, {$modal, AgentManager, $uiRouter});
+ }
+ _goToDynamicState() {
+ if (this._state) this.$uiRouter.stateRegistry.deregister(this._state);
+ this._state = this.$uiRouter.stateRegistry.register({
+ name: 'importModels',
+ parent: this.$uiRouter.stateService.current,
+ onEnter: () => {
+ this._open();
+ },
+ onExit: () => {
+ this._modal && this._modal.hide();
+ }
+ });
+ return this.$uiRouter.stateService.go(this._state, this.$uiRouter.stateService.params);
+ }
+ _open() {
+ this._modal = this.$modal({
+ template: `
+ <modal-import-models
+ on-hide='$ctrl.$state.go("^")'
+ cluster-id='$ctrl.$state.params.clusterID'
+ ></modal-import-models>
+ `,
+ controller: ['$state', function($state) {this.$state = $state;}],
+ controllerAs: '$ctrl',
+ show: false
+ });
+ return this.AgentManager.startAgentWatch('Back', this.$uiRouter.globals.current.name)
+ .then(() => this._modal.$promise)
+ .then(() => this._modal.show());
+ }
+ open() {
+ this._goToDynamicState();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/component.js
new file mode 100644
index 0000000..4f2b141
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/component.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 template from './template.pug';
+import './style.scss';
+
+export class ModalImportModelsStepIndicator {
+ isVisited(index) {
+ return index <= this.steps.findIndex((step) => step.value === this.currentStep);
+ }
+}
+
+export const component = {
+ name: 'modalImportModelsStepIndicator',
+ template,
+ controller: ModalImportModelsStepIndicator,
+ bindings: {
+ steps: '<',
+ currentStep: '<'
+ }
+};
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/style.scss b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/style.scss
new file mode 100644
index 0000000..e841272
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/style.scss
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+modal-import-models-step-indicator {
+ @import "public/stylesheets/variables.scss";
+
+ $text-color-default: #393939;
+ $text-color-active: $ignite-brand-success;
+ $indicator-color-default: #757575;
+ $indicator-color-active: $ignite-brand-success;
+ $indicator-size: 12px;
+ $indicator-border-radius: 2px;
+ $spline-height: 1px;
+
+ display: block;
+ font-family: Roboto;
+
+ .step-indicator__steps {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ .step-indicator__step {
+ color: $text-color-default;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ position: relative;
+
+ &:before {
+ content: '';
+ display: block;
+ background: $indicator-color-default;
+ width: 100%;
+ height: $spline-height;
+ bottom: $indicator-size / 2;
+ position: absolute;
+ }
+
+ &:after {
+ content: '';
+ display: block;
+ background: $indicator-color-default;
+ width: $indicator-size;
+ height: $indicator-size;
+ border-radius: $indicator-border-radius;
+ margin-top: 5px;
+ z-index: 1;
+ }
+ }
+ .step-indicator__step-first,
+ .step-indicator__step-last {
+ &:before {
+ width: calc(50% - #{$indicator-size} / 2);
+ }
+ }
+ .step-indicator__step-first:before {
+ right: 0;
+ }
+ .step-indicator__step-last:before {
+ left: 0;
+ }
+ .step-indicator__step-active {
+ color: $text-color-active;
+
+ &:after {
+ background: $indicator-color-active;
+ }
+ }
+ .step-indicator__spline {
+ background: $indicator-color-default;
+ height: $spline-height;
+ width: 100%;
+ margin-top: auto;
+ margin-bottom: $indicator-size / 2;
+ }
+ .step-indicator__step-visited {
+ &:before,
+ &+.step-indicator__spline {
+ background: $indicator-color-active;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/template.pug
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/template.pug b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/template.pug
new file mode 100644
index 0000000..c196604
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/step-indicator/template.pug
@@ -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.
+
+nav
+ .step-indicator__steps
+ .step-indicator__step(
+ ng-repeat-start='step in ::$ctrl.steps'
+ ng-class=`{
+ "step-indicator__step-active": $ctrl.currentStep === step.value,
+ "step-indicator__step-visited": $ctrl.isVisited($index),
+ "step-indicator__step-first": $first,
+ "step-indicator__step-last": $last
+ }`
+ ) {{::step.label}}
+ .step-indicator__spline(
+ ng-repeat-end
+ ng-if='!$last'
+ )
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/style.scss
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/style.scss b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/style.scss
new file mode 100644
index 0000000..5c109b4
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/style.scss
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+modal-import-models {
+ .modal-content {
+ min-height: 493px;
+ display: flex;
+ flex-direction: column;
+
+ .modal-body {
+ flex: 1 1 auto;
+ overflow-y: auto;
+ }
+ .modal-footer {
+ display: flex;
+ align-items: baseline;
+
+ selected-items-amount-indicator {
+ margin-left: auto;
+ margin-right: auto;
+ }
+ }
+ }
+
+ pc-items-table {
+ width: 100%;
+ }
+
+ modal-import-models-step-indicator {
+ margin-top: 15px;
+ margin-bottom: 30px;
+ }
+ .#{&}__prev-button {
+ margin-right: auto !important;
+ }
+ .#{&}__next-button {
+ margin-left: auto !important;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7ee1683e/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js
new file mode 100644
index 0000000..072a497
--- /dev/null
+++ b/modules/web-console/frontend/app/components/page-configure/components/modal-import-models/tables-action-cell/component.js
@@ -0,0 +1,62 @@
+/*
+ * 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 template from './template.pug';
+import './style.scss';
+
+const IMPORT_DM_NEW_CACHE = 1;
+
+export class TablesActionCell {
+ static $inject = ['$element'];
+ constructor($element) {
+ Object.assign(this, {$element});
+ }
+ onClick(e) {
+ e.stopPropagation();
+ }
+ $postLink() {
+ this.$element.on('click', this.onClick);
+ }
+ $onDestroy() {
+ this.$element.off('click', this.onClick);
+ this.$element = null;
+ }
+ tableActionView(table) {
+ if (!this.caches) return;
+ const cache = this.caches.find((c) => c.value === table.cacheOrTemplate);
+ if (!cache) return;
+ const cacheName = cache.label;
+
+ if (table.action === IMPORT_DM_NEW_CACHE)
+ return 'Create ' + table.generatedCacheName + ' (' + cacheName + ')';
+
+ return 'Associate with ' + cacheName;
+ }
+}
+
+export const component = {
+ name: 'tablesActionCell',
+ controller: TablesActionCell,
+ bindings: {
+ onEditStart: '&',
+ onCacheSelect: '&?',
+ table: '<',
+ caches: '<',
+ importActions: '<'
+ },
+ template
+};