IGNITE-10538 Web Console: Implemented "no-data" component for handling missing Web agent and/or cluster.
diff --git a/e2e/testcafe/components/no-data.js b/e2e/testcafe/components/no-data.js
new file mode 100644
index 0000000..12be3a6
--- /dev/null
+++ b/e2e/testcafe/components/no-data.js
@@ -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.
+ */
+
+import {Selector} from 'testcafe';
+
+export const noDataCmp = Selector('no-data');
diff --git a/frontend/app/app.js b/frontend/app/app.js
index 2c42c62..be4dc16 100644
--- a/frontend/app/app.js
+++ b/frontend/app/app.js
@@ -146,6 +146,7 @@
 import sidebar from './components/web-console-sidebar';
 import permanentNotifications from './components/permanent-notifications';
 import signupConfirmation from './components/page-signup-confirmation';
+import noDataCmp from './components/no-data';
 
 import igniteServices from './services';
 
@@ -247,7 +248,8 @@
         sidebar.name,
         permanentNotifications.name,
         timedRedirection.name,
-        signupConfirmation.name
+        signupConfirmation.name,
+        noDataCmp.name
     ])
     .service('$exceptionHandler', $exceptionHandler)
     // Directives.
@@ -306,11 +308,11 @@
 
             // Set up the states.
             $stateProvider
-            .state('base', {
-                url: '',
-                abstract: true,
-                template: baseTemplate
-            });
+                .state('base', {
+                    url: '',
+                    abstract: true,
+                    template: baseTemplate
+                });
 
             $urlRouterProvider.otherwise('/404');
             $locationProvider.html5Mode(true);
@@ -361,17 +363,17 @@
                         localStorage.setItem('lastStateChangeSuccess', JSON.stringify({name, params}));
                 }
                 catch (ignored) {
-                // No-op.
+                    // No-op.
                 }
             });
         }
     ])
     .run(['$rootScope', '$http', '$state', 'IgniteMessages', 'User', 'IgniteNotebookData',
-        /**
-         * @param {ng.IRootScopeService} $root
-         * @param {ng.IHttpService} $http
-         * @param {ReturnType<typeof import('./services/Messages.service').default>} Messages
-         */
+    /**
+    * @param {ng.IRootScopeService} $root
+    * @param {ng.IHttpService} $http
+    * @param {ReturnType<typeof import('./services/Messages.service').default>} Messages
+    */
         ($root, $http, $state, Messages, User, Notebook) => { // eslint-disable-line no-shadow
             $root.revertIdentity = () => {
                 $http.get('/api/v1/admin/revert/identity')
@@ -383,8 +385,8 @@
         }
     ])
     .run(['IgniteIcon',
-        /**
-         * @param {import('./components/ignite-icon/service').default} IgniteIcon
-         */
+    /**
+    * @param {import('./components/ignite-icon/service').default} IgniteIcon
+    */
         (IgniteIcon) => IgniteIcon.registerIcons(icons)
     ]);
diff --git a/frontend/app/components/ignite-chart/component.ts b/frontend/app/components/ignite-chart/component.ts
new file mode 100644
index 0000000..91a816e
--- /dev/null
+++ b/frontend/app/components/ignite-chart/component.ts
@@ -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 { IgniteChartController } from './controller';
+import templateUrl from './template.tpl.pug';
+
+export default {
+    controller: IgniteChartController,
+    templateUrl,
+    bindings: {
+        chartOptions: '<',
+        chartDataPoint: '<',
+        chartHistory: '<',
+        chartTitle: '<',
+        chartColors: '<',
+        chartHeaderText: '<',
+        refreshRate: '<',
+        resultDataStatus: '<?'
+    },
+    transclude: true
+};
diff --git a/frontend/app/components/ignite-chart/components/chart-no-data/component.ts b/frontend/app/components/ignite-chart/components/chart-no-data/component.ts
new file mode 100644
index 0000000..9627940
--- /dev/null
+++ b/frontend/app/components/ignite-chart/components/chart-no-data/component.ts
@@ -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 IgniteChartNoDataCtrl from './controller';
+import templateUrl from './template.tpl.pug';
+
+export default {
+    controller: IgniteChartNoDataCtrl,
+    templateUrl,
+    require: {
+        igniteChart: '^igniteChart'
+    },
+    bindings: {
+        resultDataStatus: '<',
+        handleClusterInactive: '<'
+    }
+} as ng.IComponentOptions;
diff --git a/frontend/app/components/ignite-chart/components/chart-no-data/controller.ts b/frontend/app/components/ignite-chart/components/chart-no-data/controller.ts
new file mode 100644
index 0000000..6acf8cf
--- /dev/null
+++ b/frontend/app/components/ignite-chart/components/chart-no-data/controller.ts
@@ -0,0 +1,80 @@
+/*
+ * 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 {merge} from 'rxjs';
+import {tap, pluck, distinctUntilChanged} from 'rxjs/operators';
+
+import {WellKnownOperationStatus} from 'app/types';
+import {IgniteChartController} from '../../controller';
+
+const BLANK_STATUS = new Set([WellKnownOperationStatus.ERROR, WellKnownOperationStatus.WAITING]);
+
+export default class IgniteChartNoDataCtrl implements ng.IOnChanges, ng.IOnDestroy {
+    static $inject = ['AgentManager'];
+
+    constructor(private AgentManager) {}
+
+    igniteChart: IgniteChartController;
+
+    handleClusterInactive: boolean;
+
+    connectionState$ = this.AgentManager.connectionSbj.pipe(
+        pluck('state'),
+        distinctUntilChanged(),
+        tap((state) => {
+            if (state === 'AGENT_DISCONNECTED')
+                this.destroyChart();
+        })
+    );
+
+    cluster$ = this.AgentManager.connectionSbj.pipe(
+        pluck('cluster'),
+        distinctUntilChanged(),
+        tap((cluster) => {
+            if (!cluster && !this.AgentManager.isDemoMode()) {
+                this.destroyChart();
+                return;
+            }
+
+            if (!!cluster && cluster.active === false && this.handleClusterInactive)
+                this.destroyChart();
+
+        })
+    );
+
+    subsribers$ = merge(
+        this.connectionState$,
+        this.cluster$
+    ).subscribe();
+
+    $onChanges(changes) {
+        if (changes.resultDataStatus && BLANK_STATUS.has(changes.resultDataStatus.currentValue))
+            this.destroyChart();
+    }
+
+    $onDestroy() {
+        this.subsribers$.unsubscribe();
+    }
+
+    destroyChart() {
+        if (this.igniteChart && this.igniteChart.chart) {
+            this.igniteChart.chart.destroy();
+            this.igniteChart.config = null;
+            this.igniteChart.chart = null;
+        }
+    }
+}
diff --git a/frontend/app/components/ignite-chart/components/chart-no-data/index.ts b/frontend/app/components/ignite-chart/components/chart-no-data/index.ts
new file mode 100644
index 0000000..d36668f
--- /dev/null
+++ b/frontend/app/components/ignite-chart/components/chart-no-data/index.ts
@@ -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 IgniteChartNoDataCmp from './component';
+
+export default angular.module('ignite-console.ignite-chart.chart-no-data', [])
+    .component('chartNoData', IgniteChartNoDataCmp);
diff --git a/frontend/app/components/ignite-chart/components/chart-no-data/template.tpl.pug b/frontend/app/components/ignite-chart/components/chart-no-data/template.tpl.pug
new file mode 100644
index 0000000..bbf2598
--- /dev/null
+++ b/frontend/app/components/ignite-chart/components/chart-no-data/template.tpl.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.
+
+no-data(result-data-status='$ctrl.resultDataStatus' handle-cluster-inactive='$ctrl.handleClusterInactive').no-data
+    div(ng-if='!$ctrl.igniteChart.config.data.datasets')
+        | No Data #[br]
+        | Make sure you are connected to the right grid.
diff --git a/frontend/app/components/ignite-chart/index.js b/frontend/app/components/ignite-chart/index.js
index 6900814..957a2ae 100644
--- a/frontend/app/components/ignite-chart/index.js
+++ b/frontend/app/components/ignite-chart/index.js
@@ -17,22 +17,10 @@
 
 import angular from 'angular';
 
-import { IgniteChartController } from './controller';
-import template from './template.pug';
+import chartNoData from './components/chart-no-data';
+import IgniteChartCmp from './component';
 import './style.scss';
 
 export default angular
-    .module('ignite-console.ignite-chart', [])
-    .component('igniteChart', {
-        controller: IgniteChartController,
-        template,
-        bindings: {
-            chartOptions: '<',
-            chartDataPoint: '<',
-            chartHistory: '<',
-            chartTitle: '<',
-            chartColors: '<',
-            chartHeaderText: '<',
-            refreshRate: '<'
-        }
-    });
+    .module('ignite-console.ignite-chart', [chartNoData.name])
+    .component('igniteChart', IgniteChartCmp);
diff --git a/frontend/app/components/ignite-chart/template.pug b/frontend/app/components/ignite-chart/template.tpl.pug
similarity index 91%
rename from frontend/app/components/ignite-chart/template.pug
rename to frontend/app/components/ignite-chart/template.tpl.pug
index 5108853..bfc4c69 100644
--- a/frontend/app/components/ignite-chart/template.pug
+++ b/frontend/app/components/ignite-chart/template.tpl.pug
@@ -32,6 +32,4 @@
 .ignite-chart-placeholder
     canvas
 
-.no-data(ng-if='!$ctrl.config.data.datasets')
-    | No Data #[br]
-    | Make sure you are connected to the right grid.
+ng-transclude
\ No newline at end of file
diff --git a/frontend/app/components/no-data/component.ts b/frontend/app/components/no-data/component.ts
new file mode 100644
index 0000000..67df1ed
--- /dev/null
+++ b/frontend/app/components/no-data/component.ts
@@ -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 templateUrl from './template.tpl.pug';
+import controller from './controller';
+
+import './style.scss';
+
+export default {
+    controller,
+    templateUrl,
+    transclude: true,
+    bindings: {
+        resultDataStatus: '<',
+        handleClusterInactive: '<'
+    }
+} as ng.IComponentOptions;
diff --git a/frontend/app/components/no-data/controller.ts b/frontend/app/components/no-data/controller.ts
new file mode 100644
index 0000000..fa2b540
--- /dev/null
+++ b/frontend/app/components/no-data/controller.ts
@@ -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 _ from 'lodash';
+import {of} from 'rxjs';
+import {distinctUntilChanged, switchMap} from 'rxjs/operators';
+
+export default class NoDataCmpCtrl {
+    static $inject = ['AgentManager', 'AgentModal'];
+
+    connectionState$ = this.AgentManager.connectionSbj.pipe(
+        switchMap((sbj) => {
+            if (!_.isNil(sbj.cluster) && sbj.cluster.active === false)
+                return of('CLUSTER_INACTIVE');
+
+            return of(sbj.state);
+        }),
+        distinctUntilChanged()
+    );
+
+    backText = 'Close';
+
+    constructor(private AgentManager, private AgentModal) {}
+
+    openAgentMissingDialog() {
+        this.AgentModal.agentDisconnected(this.backText, '.');
+    }
+
+    openNodeMissingDialog() {
+        this.AgentModal.clusterDisconnected(this.backText, '.');
+    }
+}
diff --git a/frontend/app/components/no-data/index.ts b/frontend/app/components/no-data/index.ts
new file mode 100644
index 0000000..8959ba5
--- /dev/null
+++ b/frontend/app/components/no-data/index.ts
@@ -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.
+ */
+
+import angular from 'angular';
+
+import noDataCmp from './component';
+import './style.scss';
+
+export default angular
+    .module('ignite-console.no-data', [])
+    .component('noData', noDataCmp);
diff --git a/frontend/app/components/no-data/style.scss b/frontend/app/components/no-data/style.scss
new file mode 100644
index 0000000..4f16bed
--- /dev/null
+++ b/frontend/app/components/no-data/style.scss
@@ -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.
+ */
+
+no-data{
+  .data-loading-wrapper {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    .spinner-circle {
+      margin-right: 5px;
+    }
+  }
+}
diff --git a/frontend/app/components/no-data/template.tpl.pug b/frontend/app/components/no-data/template.tpl.pug
new file mode 100644
index 0000000..cc3f96c
--- /dev/null
+++ b/frontend/app/components/no-data/template.tpl.pug
@@ -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.
+
+div(ng-switch='($ctrl.connectionState$ | async:this)')
+    div(ng-switch-when='AGENT_DISCONNECTED')
+        | Agent is disconnected. #[a(ng-click='$ctrl.openAgentMissingDialog()') Check] agent is up and running.
+
+    div(ng-switch-when='CLUSTER_DISCONNECTED')
+        | Cluster is not available. #[a(ng-click='$ctrl.openNodeMissingDialog()') Check] cluster is up and running and agent is appropriately #[a(href="https://apacheignite-tools.readme.io/docs/getting-started#section-configuration" target="_blank") configured].
+
+    div(ng-switch-when='CLUSTER_INACTIVE')
+        div(ng-if='$ctrl.handleClusterInactive') Cluster is inactive. Please activate cluster.
+        div(ng-if='!$ctrl.handleClusterInactive')
+            ng-transclude
+
+    div(ng-switch-default)
+        .data-loading-wrapper(ng-if='$ctrl.resultDataStatus === "WAITING"')
+            .spinner-circle
+            div Data is loading...
+
+        div(ng-if='$ctrl.resultDataStatus !== "WAITING"')
+            ng-transclude
diff --git a/frontend/app/components/page-queries/components/queries-notebook/components/ignite-information/information.directive.js b/frontend/app/components/page-queries/components/queries-notebook/components/ignite-information/information.directive.js
index 8e95791..d7f3529 100644
--- a/frontend/app/components/page-queries/components/queries-notebook/components/ignite-information/information.directive.js
+++ b/frontend/app/components/page-queries/components/queries-notebook/components/ignite-information/information.directive.js
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+import './information.scss';
 import template from './information.pug';
 
 export default function() {
diff --git a/frontend/app/components/page-queries/components/queries-notebook/controller.ts b/frontend/app/components/page-queries/components/queries-notebook/controller.ts
index 76aae1c..6d17aca 100644
--- a/frontend/app/components/page-queries/components/queries-notebook/controller.ts
+++ b/frontend/app/components/page-queries/components/queries-notebook/controller.ts
@@ -18,8 +18,8 @@
 import _ from 'lodash';
 import {nonEmpty, nonNil} from 'app/utils/lodashMixins';
 import id8 from 'app/utils/id8';
-import {timer, merge, defer, from, of} from 'rxjs';
-import {mergeMap, tap, switchMap, exhaustMap, take, filter, map, catchError} from 'rxjs/operators';
+import {timer, merge, defer, of} from 'rxjs';
+import {tap, switchMap, exhaustMap, take, pluck, distinctUntilChanged, filter, map, catchError} from 'rxjs/operators';
 
 import {CSV} from 'app/services/CSV';
 
@@ -923,9 +923,6 @@
         };
 
         const _startWatch = () => {
-            const awaitClusters$ = from(
-                agentMgr.startClusterWatch('Leave Queries', 'default-state'));
-
             const finishLoading$ = defer(() => {
                 if (!$root.IgniteDemoMode)
                     Loading.finish('sqlLoading');
@@ -935,17 +932,32 @@
                 return merge(timer(0, period).pipe(exhaustMap(() => _refreshCaches())), finishLoading$);
             };
 
-            this.refresh$ = awaitClusters$.pipe(
-                mergeMap(() => agentMgr.currentCluster$),
-                tap(() => Loading.start('sqlLoading')),
-                tap(() => {
-                    _.forEach($scope.notebook.paragraphs, (paragraph) => {
-                        paragraph.reset($interval);
-                    });
-                }),
-                switchMap(() => refreshCaches(5000))
-            )
-                .subscribe();
+            const cluster$ = agentMgr.connectionSbj.pipe(
+                pluck('cluster'),
+                distinctUntilChanged(),
+                tap((cluster) => {
+                    this.clusterIsAvailable = (!!cluster && cluster.active === true) || agentMgr.isDemoMode();
+                })
+            );
+
+            this.refresh$ = cluster$.pipe(
+                switchMap((cluster) => {
+                    if (!cluster && !agentMgr.isDemoMode())
+                        return of(null);
+
+                    return of(cluster).pipe(
+                        tap(() => Loading.start('sqlLoading')),
+                        tap(() => {
+                            _.forEach($scope.notebook.paragraphs, (paragraph) => {
+                                paragraph.reset($interval);
+                            });
+                        }),
+                        switchMap(() => refreshCaches(5000))
+                    );
+                })
+            );
+
+            this.subscribers$ = merge(this.refresh$).subscribe();
         };
 
         const _newParagraph = (paragraph) => {
@@ -1442,7 +1454,8 @@
                     }
 
                     return nids[_.random(0, nids.length - 1)];
-                });
+                })
+                .catch(Messages.showError);
         };
 
         const _executeRefresh = (paragraph) => {
@@ -1588,6 +1601,8 @@
                             _showLoading(paragraph, false);
 
                             $scope.stopRefresh(paragraph);
+
+                            Messages.showError(err);
                         })
                         .then(() => paragraph.ace.focus());
                 });
@@ -2168,7 +2183,7 @@
     $onDestroy() {
         this._closeOpenedQueries(this.$scope.notebook.paragraphs);
 
-        if (this.refresh$)
-            this.refresh$.unsubscribe();
+        if (this.subscribers$)
+            this.subscribers$.unsubscribe();
     }
 }
diff --git a/frontend/app/components/page-queries/components/queries-notebook/style.scss b/frontend/app/components/page-queries/components/queries-notebook/style.scss
index 4978701..e632cdb 100644
--- a/frontend/app/components/page-queries/components/queries-notebook/style.scss
+++ b/frontend/app/components/page-queries/components/queries-notebook/style.scss
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+@import "../../../../../public/stylesheets/variables.scss";
+
 queries-notebook {
     // TODO: Delete this breadcrumbs styles after template refactoring to new design.
     .notebooks-top {
@@ -104,6 +106,15 @@
         }
     }
 
+    .empty-caches {
+        color: $ignite-placeholder-color;
+        display: flex;
+        padding: 10px;
+        align-items: center;
+        justify-content: center;
+        text-align: center;
+    }
+
     .notebook-top-buttons {
         display: flex;
         align-items: center;
diff --git a/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug b/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
index c4033e6..e7334cb 100644
--- a/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
+++ b/frontend/app/components/page-queries/components/queries-notebook/template.tpl.pug
@@ -403,9 +403,11 @@
                                 tipOpts: { placement: 'top' }
                             })
                 .empty-caches(ng-show='displayedCaches.length == 0 && caches.length != 0')
-                    label Wrong caches filter
+                    no-data
+                        label Wrong caches filter
                 .empty-caches(ng-show='caches.length == 0')
-                    label No caches
+                    no-data
+                        label No caches
         .col-sm-12.sql-controls
             div
                 +query-actions
diff --git a/frontend/app/configuration/components/modal-import-models/component.js b/frontend/app/configuration/components/modal-import-models/component.js
index 098bb67..0dbf4f1 100644
--- a/frontend/app/configuration/components/modal-import-models/component.js
+++ b/frontend/app/configuration/components/modal-import-models/component.js
@@ -21,8 +21,8 @@
 import naturalCompare from 'natural-compare-lite';
 import find from 'lodash/fp/find';
 import get from 'lodash/fp/get';
-import {race, timer, merge, of, from, combineLatest} from 'rxjs';
-import {tap, filter, take, pluck, switchMap} from 'rxjs/operators';
+import {race, timer, merge, of, from, combineLatest, EMPTY} from 'rxjs';
+import {tap, filter, take, pluck, switchMap, map} from 'rxjs/operators';
 import ObjectID from 'bson-objectid';
 import {uniqueName} from 'app/utils/uniqueName';
 import {defaultNames} from '../../defaultNames';
@@ -94,14 +94,13 @@
     /** @type {ng.ICompiledExpression} */
     onHide;
 
-    static $inject = ['$uiRouter', 'ConfigSelectors', 'ConfigEffects', 'ConfigureState', '$http', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteFocus', 'SqlTypes', 'JavaTypes', 'IgniteMessages', '$scope', '$rootScope', 'AgentManager', 'IgniteActivitiesData', 'IgniteLoading', 'IgniteFormUtils', 'IgniteLegacyUtils'];
+    static $inject = ['$uiRouter', 'ConfigSelectors', 'ConfigEffects', 'ConfigureState', 'IgniteConfirm', 'IgniteConfirmBatch', 'IgniteFocus', 'SqlTypes', 'JavaTypes', '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
@@ -110,10 +109,9 @@
      * @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) {
+    constructor($uiRouter, ConfigSelectors, ConfigEffects, ConfigureState, 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;
@@ -259,14 +257,14 @@
     }
 
     $onDestroy() {
-        this.subscription.unsubscribe();
+        this.subscribers$.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;
+        const {Confirm, ConfirmBatch, Focus, SqlTypes, JavaTypes, Messages, $scope, $root, agentMgr, ActivitiesData, Loading, FormUtils, LegacyUtils} = this;
 
         /**
          * Convert some name to valid java package name.
@@ -317,7 +315,7 @@
             }
             this.$scope.$watch('importCommon.action', this._fillCommonCachesOrTemplates(this.$scope.importCommon), true);
             this.$scope.importCommon.action = IMPORT_DM_NEW_CACHE;
-        })).subscribe();
+        }));
 
         // New
         this.loadedCaches = {
@@ -1006,63 +1004,84 @@
 
         $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;
-
-                            $scope.importDomain.action = 'connect';
-                            $scope.importDomain.tables = [];
-                            this.selectedTables = [];
-                        }
-                        else {
-                            $scope.importDomain.jdbcDriversNotFound = true;
-                            $scope.importDomain.button = 'Cancel';
-                        }
-                    })
-                    .then(() => {
-                        $scope.importDomain.info = INFO_CONNECT_TO_DB;
-
-                        Loading.finish('importDomainFromDb');
+        const fetchDomainData = () => {
+            return agentMgr.awaitAgent()
+                .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;
+
+                                $scope.importDomain.action = 'connect';
+                                $scope.importDomain.tables = [];
+                                this.selectedTables = [];
+                            }
+                            else {
+                                $scope.importDomain.jdbcDriversNotFound = true;
+                                $scope.importDomain.button = 'Cancel';
+                            }
+                        })
+                        .then(() => {
+                            $scope.importDomain.info = INFO_CONNECT_TO_DB;
+
+                            Loading.finish('importDomainFromDb');
+                        });
+                });
+        };
+
+        this.agentIsAvailable$ = this.agentMgr.connectionSbj.pipe(
+            pluck('state'),
+            map((state) => state !== 'AGENT_DISCONNECTED')
+        );
+
+        this.domainData$ = this.agentIsAvailable$.pipe(
+            switchMap((agentIsAvailable) => {
+                if (!agentIsAvailable)
+                    return of(EMPTY);
+
+                return from(fetchDomainData());
+            })
+        );
+
+        this.subscribers$ = merge(
+            this.subscription,
+            this.domainData$
+        ).subscribe();
 
         $scope.$watch('ui.selectedJdbcDriverJar', function(val) {
             if (val && !$scope.importDomain.demo) {
diff --git a/frontend/app/configuration/components/modal-import-models/service.ts b/frontend/app/configuration/components/modal-import-models/service.ts
index 891b905..c440fe8 100644
--- a/frontend/app/configuration/components/modal-import-models/service.ts
+++ b/frontend/app/configuration/components/modal-import-models/service.ts
@@ -84,8 +84,7 @@
             show: false
         });
 
-        return this.AgentManager.startAgentWatch('Back', this.$uiRouter.globals.current.name)
-            .then(() => this._modal.$promise)
+        return this._modal.$promise
             .then(() => this._modal.show())
             .then(() => this.deferred.promise)
             .finally(() => this.deferred = null);
diff --git a/frontend/app/configuration/components/modal-import-models/style.scss b/frontend/app/configuration/components/modal-import-models/style.scss
index 5c109b4..b0a5877 100644
--- a/frontend/app/configuration/components/modal-import-models/style.scss
+++ b/frontend/app/configuration/components/modal-import-models/style.scss
@@ -50,4 +50,12 @@
     .#{&}__next-button {
         margin-left: auto !important;
     }
+
+    no-data {
+        margin: 30px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        height: 300px;
+    }
 }
\ No newline at end of file
diff --git a/frontend/app/configuration/components/modal-import-models/template.tpl.pug b/frontend/app/configuration/components/modal-import-models/template.tpl.pug
index ff3bafe..9b4c597 100644
--- a/frontend/app/configuration/components/modal-import-models/template.tpl.pug
+++ b/frontend/app/configuration/components/modal-import-models/template.tpl.pug
@@ -33,7 +33,7 @@
                 h4.modal-title()
                     span(ng-if='!importDomain.demo') Import domain models from database
                     span(ng-if='importDomain.demo') Import domain models from demo database
-            .modal-body
+            .modal-body(ng-if-start='$ctrl.agentIsAvailable$ | async: this')
                 modal-import-models-step-indicator(
                     steps='$ctrl.actions'
                     current-step='importDomain.action'
@@ -226,7 +226,7 @@
                                 tipOpts
                             })
 
-            .modal-footer
+            .modal-footer(ng-if-end)
                 button.btn-ignite.btn-ignite--success.modal-import-models__prev-button(
                     type='button'
                     ng-hide='importDomain.action == "drivers" || importDomain.action == "connect"'
@@ -255,3 +255,9 @@
                 )
                     svg.icon-left(ignite-icon='checkmark' ng-show='importDomain.button === "Save"')
                     | {{importDomain.button}}
+
+            .modal-body(ng-if-start='!($ctrl.agentIsAvailable$ | async: this)')
+                no-data
+
+            .modal-footer(ng-if-end)
+                button.btn-ignite.btn-ignite--success.modal-import-models__next-button(ng-click='$ctrl.onHide()') Cancel
diff --git a/frontend/app/modules/agent/AgentManager.service.js b/frontend/app/modules/agent/AgentManager.service.js
index 8e4dd2d..23953cb 100644
--- a/frontend/app/modules/agent/AgentManager.service.js
+++ b/frontend/app/modules/agent/AgentManager.service.js
@@ -193,6 +193,11 @@
             pluck('active')
         );
 
+        this.clusterIsAvailable$ = this.connectionSbj.pipe(
+            pluck('cluster'),
+            map((cluster) => !!cluster)
+        );
+
         if (!this.isDemoMode()) {
             this.connectionSbj.subscribe({
                 next: ({cluster}) => {
@@ -354,58 +359,6 @@
         return this.awaitAgent();
     }
 
-    /**
-     * @param {String} backText
-     * @param {String} [backState]
-     * @returns {ng.IPromise}
-     */
-    startClusterWatch(backText, backState) {
-        this.backText = backText;
-        this.backState = backState;
-
-        const conn = this.connectionSbj.getValue();
-
-        conn.useConnectedCluster();
-
-        this.connectionSbj.next(conn);
-
-        this.modalSubscription && this.modalSubscription.unsubscribe();
-
-        this.modalSubscription = this.connectionSbj.subscribe({
-            next: ({state}) => {
-                switch (state) {
-                    case State.CONNECTED:
-                        this.agentModal.hide();
-
-                        break;
-
-                    case State.AGENT_DISCONNECTED:
-                        this.agentModal.agentDisconnected(this.backText, this.backState);
-                        this.ClusterLoginSrv.cancel();
-
-                        break;
-
-                    case State.CLUSTER_DISCONNECTED:
-                        this.agentModal.clusterDisconnected(this.backText, this.backState);
-                        this.ClusterLoginSrv.cancel();
-
-                        break;
-
-                    default:
-                    // Connection to backend is not established yet.
-                }
-            }
-        });
-
-        const stopWatchUnsubscribe = this.$transitions.onExit({}, () => {
-            this.stopWatch();
-
-            stopWatchUnsubscribe();
-        });
-
-        return this.awaitCluster();
-    }
-
     stopWatch() {
         this.modalSubscription && this.modalSubscription.unsubscribe();
 
diff --git a/frontend/app/types/index.ts b/frontend/app/types/index.ts
index 89f495e..905558a 100644
--- a/frontend/app/types/index.ts
+++ b/frontend/app/types/index.ts
@@ -74,3 +74,9 @@
     notifyAboutError(): void
     hideError(): void
 }
+
+export enum WellKnownOperationStatus {
+    WAITING = 'WAITING',
+    ERROR = 'ERROR',
+    DONE = 'DONE'
+}
diff --git a/frontend/public/stylesheets/style.scss b/frontend/public/stylesheets/style.scss
index 52f6250..15cdb65 100644
--- a/frontend/public/stylesheets/style.scss
+++ b/frontend/public/stylesheets/style.scss
@@ -536,13 +536,6 @@
         line-height: 65px;
     }
 
-    .empty-caches {
-        text-align: center;
-        color: $ignite-placeholder-color;
-        height: 55px;
-        line-height: 55px;
-    }
-
     .panel-collapse {
         border-top: 1px solid $ignite-border-color;
     }