This is an automated email from the ASF dual-hosted git repository.

cwylie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 8773d619a2 Web console: tidy up stage UI (#13615)
8773d619a2 is described below

commit 8773d619a2c8be49f52d22483242e0c9a653f200
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Thu Dec 22 12:52:16 2022 -0800

    Web console: tidy up stage UI (#13615)
    
    * show the right info
    
    * sort indicator
    
    * nicer marker
    
    * move error icon
---
 .../workbench-query/workbench-query-part.ts        |  6 ++-
 .../workbench-query/workbench-query.spec.ts        | 13 ++++++
 .../src/views/segments-view/segments-view.tsx      |  6 +--
 .../workbench-view/column-tree/column-tree.tsx     | 16 ++++++++
 .../execution-stages-pane.scss                     | 11 ++++++
 .../execution-stages-pane.tsx                      | 46 +++++++++++-----------
 6 files changed, 69 insertions(+), 29 deletions(-)

diff --git 
a/web-console/src/druid-models/workbench-query/workbench-query-part.ts 
b/web-console/src/druid-models/workbench-query/workbench-query-part.ts
index 5e4afb453f..8c5d2c9446 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query-part.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query-part.ts
@@ -65,9 +65,11 @@ export class WorkbenchQueryPart {
     const matchInsertReplaceIndex = 
queryFragment.match(/(?:INSERT|REPLACE)\s+INTO/i)?.index;
     if (typeof matchInsertReplaceIndex !== 'number') return;
 
-    const matchEnd = queryFragment.match(/\b(?:SELECT|WITH)\b|$/i);
+    const queryStartingWithInsertOrReplace = 
queryFragment.substring(matchInsertReplaceIndex);
+
+    const matchEnd = 
queryStartingWithInsertOrReplace.match(/\b(?:SELECT|WITH)\b|$/i);
     const fragmentQuery = SqlQuery.maybeParse(
-      queryFragment.substring(matchInsertReplaceIndex, matchEnd?.index) + ' 
SELECT * FROM t',
+      queryStartingWithInsertOrReplace.substring(0, matchEnd?.index) + ' 
SELECT * FROM t',
     );
     if (!fragmentQuery) return;
 
diff --git 
a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts 
b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
index c1af666aad..91626668e3 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.spec.ts
@@ -507,6 +507,19 @@ describe('WorkbenchQuery', () => {
       expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
       
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
     });
+
+    it('works with REPLACE (unparsable with comment at start)', () => {
+      const sql = sane`
+        -- Hello world SELECT
+
+        REPLACE INTO trips2 OVERWRITE ALL
+        WITH kttm_data AS (SELECT *
+      `;
+
+      const workbenchQuery = WorkbenchQuery.blank().changeQueryString(sql);
+      expect(workbenchQuery.getIngestDatasource()).toEqual('trips2');
+      
expect(workbenchQuery.changeEngine('sql-native').getIngestDatasource()).toBeUndefined();
+    });
   });
 
   describe('#extractCteHelpers', () => {
diff --git a/web-console/src/views/segments-view/segments-view.tsx 
b/web-console/src/views/segments-view/segments-view.tsx
index f9917c63c3..4f437a4004 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -666,11 +666,9 @@ END AS "time_span"`,
 
               switch (v?.type) {
                 case 'range': {
-                  const dimensions = v.dimensions || [];
+                  const dimensions: string[] = v.dimensions || [];
                   const formatEdge = (values: string[]) =>
-                    values
-                      .map((x, i) => formatRangeDimensionValue(dimensions[i] 
|| `d${i}`, x))
-                      .join('; ');
+                    dimensions.map((d, i) => formatRangeDimensionValue(d, 
values[i])).join('; ');
 
                   return (
                     <TableClickableCell
diff --git a/web-console/src/views/workbench-view/column-tree/column-tree.tsx 
b/web-console/src/views/workbench-view/column-tree/column-tree.tsx
index 3611630d76..d72f53d1b7 100644
--- a/web-console/src/views/workbench-view/column-tree/column-tree.tsx
+++ b/web-console/src/views/workbench-view/column-tree/column-tree.tsx
@@ -268,6 +268,22 @@ export class ColumnTree extends 
React.PureComponent<ColumnTreeProps, ColumnTreeS
                                 );
                               }}
                             />
+                            <MenuItem
+                              icon={IconNames.FULLSCREEN}
+                              text={`SELECT MIN(__time), MAX(__time) FROM 
${tableName}`}
+                              onClick={() => {
+                                onQueryChange(
+                                  getQueryOnTable()
+                                    .changeSelectExpressions([
+                                      F.min(C('__time')).as('min_time'),
+                                      F.max(C('__time')).as('max_time'),
+                                    ])
+                                    .changeGroupByExpressions([])
+                                    .changeWhereExpression(getWhere(true)),
+                                  true,
+                                );
+                              }}
+                            />
                             {parsedQuery && parsedQuery.getFirstTableName() 
!== tableName && (
                               <MenuItem
                                 icon={IconNames.EXCHANGE}
diff --git 
a/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.scss
 
b/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.scss
index ae49b736d1..35ca404e4f 100644
--- 
a/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.scss
+++ 
b/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.scss
@@ -41,6 +41,17 @@
     opacity: 0.6;
   }
 
+  .sort-marker {
+    font-style: italic;
+    opacity: 0.6;
+  }
+
+  .error-warning {
+    position: absolute;
+    top: 7px;
+    right: 3px;
+  }
+
   .counter-spacer {
     position: relative;
     height: 5px;
diff --git 
a/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.tsx
 
b/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.tsx
index 3732dff785..7c5a593424 100644
--- 
a/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.tsx
+++ 
b/web-console/src/views/workbench-view/execution-stages-pane/execution-stages-pane.tsx
@@ -402,6 +402,7 @@ ${title} uncompressed size: ${formatBytesCompact(
 
     const shuffleRows = stages.getTotalCounterForStage(stage, 'shuffle', 
'rows');
     const sortProgress = stages.getSortProgressForStage(stage);
+    const showSortedPercent = 0 < sortProgress && sortProgress < 1;
     const title = stages.getStageCounterTitle(stage, 'shuffle');
     return (
       <div
@@ -413,10 +414,9 @@ ${title} uncompressed size: ${formatBytesCompact(
           stages.getTotalCounterForStage(stage, 'shuffle', 'bytes'),
         )} ${NOT_SIZE_ON_DISK}`}
       >
-        <BracedText text={shuffleRows ? formatRows(shuffleRows) : ''} 
braces={rowsValues} /> &nbsp;{' '}
-        {0 < sortProgress && sortProgress < 1 && (
-          <> &nbsp;{` ${formatPercent(sortProgress)} sorted`}</>
-        )}
+        {Boolean(shuffleRows) && <BracedText text={formatRows(shuffleRows)} 
braces={rowsValues} />}
+        {Boolean(shuffleRows && showSortedPercent) && <>&nbsp; : &nbsp;</>}
+        {showSortedPercent && `${formatPercent(sortProgress)} sorted`}
       </div>
     );
   }
@@ -449,28 +449,28 @@ ${title} uncompressed size: ${formatBytesCompact(
                   <span className="stage">{`Stage${stage.stageNumber}`}</span>
                 </div>
                 <div>{stage.definition.processor.type}</div>
+                {stage.sort && <div className="sort-marker">(with sort)</div>}
                 {(myError || warnings > 0) && (
-                  <div>
+                  <div className="error-warning">
                     {myError && (
-                      <>
-                        <Tooltip2
-                          content={
-                            <div>
-                              {(error.error.errorCode ? 
`${error.error.errorCode}: ` : '') +
-                                error.error.errorMessage}
-                            </div>
-                          }
-                        >
-                          <Button
-                            minimal
-                            small
-                            icon={IconNames.ERROR}
-                            intent={Intent.DANGER}
-                            onClick={onErrorClick}
-                          />
-                        </Tooltip2>{' '}
-                      </>
+                      <Tooltip2
+                        content={
+                          <div>
+                            {(error.error.errorCode ? 
`${error.error.errorCode}: ` : '') +
+                              error.error.errorMessage}
+                          </div>
+                        }
+                      >
+                        <Button
+                          minimal
+                          small
+                          icon={IconNames.ERROR}
+                          intent={Intent.DANGER}
+                          onClick={onErrorClick}
+                        />
+                      </Tooltip2>
                     )}
+                    {myError && warnings > 0 && ' '}
                     {warnings > 0 && (
                       <Tooltip2
                         content={


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to