Browse Source

HUE-9028 [editor] Indicate execution status in the gutter

Johan Ahlen 6 năm trước cách đây
mục cha
commit
f96f0e57fd

+ 8 - 0
desktop/core/src/desktop/js/apps/notebook2/execution/executable.js

@@ -98,6 +98,14 @@ export default class Executable {
     );
   }
 
+  isRunning() {
+    return this.status === EXECUTION_STATUS.running;
+  }
+
+  isSuccess() {
+    return this.status === EXECUTION_STATUS.success || this.status === EXECUTION_STATUS.available;
+  }
+
   isPartOfRunningExecution() {
     if (!this.isReady()) {
       return true;

+ 1 - 1
desktop/core/src/desktop/js/apps/notebook2/snippet.js

@@ -39,7 +39,7 @@ import { EXECUTABLE_UPDATED_EVENT } from 'apps/notebook2/execution/executable';
 import {
   ACTIVE_STATEMENT_CHANGED_EVENT,
   REFRESH_STATEMENT_LOCATIONS_EVENT
-} from 'sql/aceLocationHandler';
+} from 'ko/bindings/ace/aceLocationHandler';
 import { EXECUTE_ACTIVE_EXECUTABLE_EVENT } from 'apps/notebook2/components/ko.executableActions';
 
 // TODO: Remove. Temporary here for debug

+ 114 - 0
desktop/core/src/desktop/js/ko/bindings/ace/aceGutterHandler.js

@@ -0,0 +1,114 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. 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 huePubSub from 'utils/huePubSub';
+import { EXECUTABLE_UPDATED_EVENT } from 'apps/notebook2/execution/executable';
+import { ACTIVE_STATEMENT_CHANGED_EVENT } from 'ko/bindings/ace/aceLocationHandler';
+
+// TODO: depends on Ace
+
+const LINE_BREAK_REGEX = /(\r\n)|(\n)|(\r)/g;
+const LEADING_WHITE_SPACE_REGEX = /^\s+/;
+
+const ACTIVE_CSS = 'ace-active-gutter-decoration';
+const EXECUTING_CSS = 'ace-executing-gutter-decoration';
+const COMPLETED_CSS = 'ace-completed-gutter-decoration';
+
+const getLeadingEmptyLineCount = parsedStatement => {
+  let leadingEmptyLineCount = 0;
+  const leadingWhiteSpace = parsedStatement.statement.match(LEADING_WHITE_SPACE_REGEX);
+  if (leadingWhiteSpace) {
+    const lineBreakMatch = leadingWhiteSpace[0].match(LINE_BREAK_REGEX);
+    if (lineBreakMatch) {
+      leadingEmptyLineCount = lineBreakMatch.length;
+    }
+  }
+  return leadingEmptyLineCount;
+};
+
+const forEachLine = (statement, callback) => {
+  const leadingEmptyLineCount = getLeadingEmptyLineCount(statement);
+  let line = statement.location.first_line - 1 + leadingEmptyLineCount;
+  for (line; line < statement.location.last_line; line++) {
+    callback(line);
+  }
+};
+
+export default class AceGutterHandler {
+  constructor(options) {
+    this.editor = options.editor;
+    this.editorId = options.editorId;
+    this.executor = options.executor;
+
+    this.disposals = [];
+
+    const previouslyMarkedActiveLines = [];
+
+    const changedSubscription = huePubSub.subscribe(
+      ACTIVE_STATEMENT_CHANGED_EVENT,
+      statementDetails => {
+        if (statementDetails.id !== this.editorId || !statementDetails.activeStatement) {
+          return;
+        }
+
+        const session = this.editor.getSession();
+        while (previouslyMarkedActiveLines.length) {
+          session.removeGutterDecoration(previouslyMarkedActiveLines.shift(), ACTIVE_CSS);
+        }
+
+        forEachLine(statementDetails.activeStatement, line => {
+          previouslyMarkedActiveLines.push(line);
+          session.addGutterDecoration(line, ACTIVE_CSS);
+        });
+      }
+    );
+
+    this.disposals.push(() => {
+      changedSubscription.remove();
+    });
+
+    if (this.executor) {
+      const executableSub = huePubSub.subscribe(EXECUTABLE_UPDATED_EVENT, executable => {
+        if (executable.executor === this.executor) {
+          const statement = executable.parsedStatement;
+          const session = this.editor.getSession();
+          forEachLine(statement, line => {
+            if (executable.isRunning()) {
+              session.removeGutterDecoration(line, COMPLETED_CSS);
+              session.addGutterDecoration(line, EXECUTING_CSS);
+            } else if (executable.isSuccess()) {
+              session.removeGutterDecoration(line, EXECUTING_CSS);
+              session.addGutterDecoration(line, COMPLETED_CSS);
+            } else {
+              session.removeGutterDecoration(line, EXECUTING_CSS);
+              session.removeGutterDecoration(line, COMPLETED_CSS);
+            }
+          });
+        }
+      });
+
+      this.disposals.push(() => {
+        executableSub.remove();
+      });
+    }
+  }
+
+  dispose() {
+    while (this.disposals.length) {
+      this.disposals.pop()();
+    }
+  }
+}

+ 2 - 42
desktop/core/src/desktop/js/sql/aceLocationHandler.js → desktop/core/src/desktop/js/ko/bindings/ace/aceLocationHandler.js

@@ -24,6 +24,7 @@ import I18n from 'utils/i18n';
 import sqlStatementsParser from 'parse/sqlStatementsParser';
 import sqlUtils from 'sql/sqlUtils';
 import stringDistance from 'sql/stringDistance';
+import { EXECUTABLE_UPDATED_EVENT } from 'apps/notebook2/execution/executable';
 
 // TODO: depends on Ace, sqlStatementsParser
 
@@ -41,6 +42,7 @@ class AceLocationHandler {
     self.editor = options.editor;
     self.editorId = options.editorId;
     self.snippet = options.snippet;
+    self.executor = options.executor;
     self.expandStar =
       (options.i18n && options.i18n.expandStar) || 'Right-click to expand with columns';
     self.contextTooltip =
@@ -52,7 +54,6 @@ class AceLocationHandler {
 
     self.attachStatementLocator();
     self.attachSqlWorker();
-    self.attachGutterHandler();
     self.attachMouseListeners();
 
     self.verifyThrottle = -1;
@@ -434,47 +435,6 @@ class AceLocationHandler {
     });
   }
 
-  attachGutterHandler() {
-    const self = this;
-    const lastMarkedGutterLines = [];
-
-    const changedSubscription = huePubSub.subscribe(
-      'editor.active.statement.changed',
-      statementDetails => {
-        if (statementDetails.id !== self.editorId || !statementDetails.activeStatement) {
-          return;
-        }
-        let leadingEmptyLineCount = 0;
-        const leadingWhiteSpace = statementDetails.activeStatement.statement.match(/^\s+/);
-        if (leadingWhiteSpace) {
-          const lineBreakMatch = leadingWhiteSpace[0].match(/(\r\n)|(\n)|(\r)/g);
-          if (lineBreakMatch) {
-            leadingEmptyLineCount = lineBreakMatch.length;
-          }
-        }
-
-        while (lastMarkedGutterLines.length) {
-          self.editor
-            .getSession()
-            .removeGutterDecoration(lastMarkedGutterLines.shift(), 'ace-active-gutter-decoration');
-        }
-        for (
-          let line =
-            statementDetails.activeStatement.location.first_line - 1 + leadingEmptyLineCount;
-          line < statementDetails.activeStatement.location.last_line;
-          line++
-        ) {
-          lastMarkedGutterLines.push(line);
-          self.editor.getSession().addGutterDecoration(line, 'ace-active-gutter-decoration');
-        }
-      }
-    );
-
-    self.disposeFunctions.push(() => {
-      changedSubscription.remove();
-    });
-  }
-
   attachStatementLocator() {
     const self = this;
     let lastKnownStatements = [];

+ 10 - 1
desktop/core/src/desktop/js/ko/bindings/ko.aceEditor.js → desktop/core/src/desktop/js/ko/bindings/ace/ko.aceEditor.js

@@ -18,9 +18,10 @@ import $ from 'jquery';
 import ko from 'knockout';
 
 import apiHelper from 'api/apiHelper';
-import AceLocationHandler from 'sql/aceLocationHandler';
+import AceLocationHandler from 'ko/bindings/ace/aceLocationHandler';
 import huePubSub from 'utils/huePubSub';
 import sqlUtils from 'sql/sqlUtils';
+import AceGutterHandler from 'ko/bindings/ace/aceGutterHandler';
 
 // TODO: Depends on Ace
 
@@ -67,10 +68,18 @@ ko.bindingHandlers.aceEditor = {
       editor: editor,
       editorId: $el.attr('id'),
       snippet: snippet,
+      executor: snippet.executor,
       i18n: { expandStar: options.expandStar, contextTooltip: options.contextTooltip }
     });
+
+    const aceGutterHandler = new AceGutterHandler({
+      editor: editor,
+      editorId: $el.attr('id'),
+      executor: snippet.executor
+    });
     disposeFunctions.push(() => {
       aceLocationHandler.dispose();
+      aceGutterHandler.dispose();
     });
 
     editor.session.setMode(snippet.getAceMode());

+ 0 - 0
desktop/core/src/desktop/js/ko/bindings/ko.aceResizer.js → desktop/core/src/desktop/js/ko/bindings/ace/ko.aceResizer.js


+ 8 - 1
desktop/core/src/desktop/js/ko/components/simpleAceEditor/ko.simpleAceEditor.js

@@ -17,13 +17,14 @@
 import $ from 'jquery';
 import ko from 'knockout';
 
-import AceLocationHandler from 'sql/aceLocationHandler';
+import AceLocationHandler from 'ko/bindings/ace/aceLocationHandler';
 import componentUtils from 'ko/components/componentUtils';
 import hueUtils from 'utils/hueUtils';
 import SolrFormulaAutocompleter from './solrFormulaAutocompleter';
 import SolrQueryAutocompleter from './solrQueryAutocompleter';
 import SqlAutocompleter from 'sql/sqlAutocompleter';
 import sqlWorkerHandler from 'sql/sqlWorkerHandler';
+import AceGutterHandler from 'ko/bindings/ace/aceGutterHandler';
 
 const SIMPLE_ACE_TEMPLATE = `
   <div class="simple-ace-single-line">
@@ -125,8 +126,14 @@ class SimpleAceEditor {
           editorId: $element.attr('id'),
           snippet: snippet
         });
+        const aceGutterHandler = new AceGutterHandler({
+          editor: editor,
+          editorId: $element.attr('id'),
+          executor: snippet.executor
+        });
         self.disposeFunctions.push(() => {
           aceLocationHandler.dispose();
+          aceGutterHandler.dispose();
         });
         aceLocationHandler.attachSqlSyntaxWorker();
       }

+ 2 - 2
desktop/core/src/desktop/js/ko/ko.all.js

@@ -34,8 +34,8 @@ import 'ko/bindings/charts/ko.pieChart';
 import 'ko/bindings/charts/ko.scatterChart';
 import 'ko/bindings/charts/ko.timelineChart';
 
-import 'ko/bindings/ko.aceEditor';
-import 'ko/bindings/ko.aceResizer';
+import 'ko/bindings/ace/ko.aceEditor';
+import 'ko/bindings/ace/ko.aceResizer';
 import 'ko/bindings/ko.appAwareTemplateContextMenu';
 import 'ko/bindings/ko.assistFileDraggable';
 import 'ko/bindings/ko.assistFileDroppable';

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue3-extra.css


+ 20 - 0
desktop/core/src/desktop/static/desktop/less/hue-cross-version.less

@@ -251,6 +251,26 @@ input[type='password']::-ms-reveal {
       border-right: 1px solid @hue-primary-color-dark;
     }
 
+    &.ace-executing-gutter-decoration {
+      background-color: @hue-primary-color-light;
+      border-right: 1px solid @hue-primary-color-dark;
+      .animation(execute-pulse 2s infinite ease-in-out);
+    }
+
+    .keyframes(execute-pulse, {
+      0% { background-color: rgba(0, 140, 255, 0.1); }
+      50% {
+        background-color: rgba(0, 140, 255, 0.4);
+        color: #505050;
+      }
+      100% { background-color: rgba(0, 140, 255, 0.1); }
+    });
+
+    &.ace-completed-gutter-decoration {
+      background-color: @cui-green-100;
+      border-right: 1px solid @cui-green-400;
+    }
+
     &.ace_error {
       background-color: @cui-pink-010;
       border-right: 1px solid @cui-red-700;

+ 33 - 7
desktop/core/src/desktop/static/desktop/less/hue-mixins.less

@@ -108,18 +108,44 @@
   box-shadow: none !important;
 }
 
-@keyframes fadein {
+.animation(@params) {
+  -webkit-animation: @params;
+  -moz-animation: @params;
+  -ms-animation: @params;
+  animation: @params;
+}
+
+.keyframes(@name,@rules) {
+  @-webkit-keyframes @name {
+    @rules();
+  }
+
+  @-moz-keyframes @name {
+    @rules();
+  }
+
+  @-ms-keyframes @name {
+    @rules();
+  }
+
+  @-o-keyframes @name {
+    @rules();
+  }
+
+  @keyframes @name {
+    @rules();
+  }
+}
+
+.keyframes(hue-fade-in-frames, {
   from { opacity: 0; }
   to { opacity: 1; }
-}
+});
 
 .hue-fade-in {
-  -webkit-animation: fadein 2s; /* Safari, Chrome and Opera > 12.1 */
-  -moz-animation: fadein 2s; /* Firefox < 16 */
-  -ms-animation: fadein 2s; /* Internet Explorer */
-  -o-animation: fadein 2s; /* Opera < 12.1 */
-  animation: fadein 2s;
+  .animation(hue-fade-in-frames 2s);
 }
+
 // Flexbox mixins
 
 .display-flex() {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác