You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by fj...@apache.org on 2019/06/28 22:50:29 UTC

[incubator-druid] branch master updated: Web-Console: add clipboard modal (#7964)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new f1270c1  Web-Console: add clipboard modal (#7964)
f1270c1 is described below

commit f1270c14f8680fd0f69872acb05b9b97680bd4a3
Author: mcbrewster <37...@users.noreply.github.com>
AuthorDate: Fri Jun 28 15:50:18 2019 -0700

    Web-Console: add clipboard modal (#7964)
    
    * add clipboard modal
    
    * rename button
    
    * remove console.log
    
    * fix off by one
    
    * update tests
    
    * update snapshot
    
    * fix casing
    
    * update snapshot
---
 .../__snapshots__/table-cell.spec.tsx.snap         |  28 +++---
 .../src/components/table-cell/table-cell.scss      |   1 +
 .../src/components/table-cell/table-cell.tsx       |  21 ++--
 .../__snapshots__/show-value-dialog.spec.tsx.snap  | 107 +++++++++++++++++++++
 .../show-value-dialog/show-value-dialog.scss}      |  35 ++-----
 .../show-value-dialog/show-value-dialog.spec.tsx}  |  31 ++----
 .../show-value-dialog/show-value-dialog.tsx        |  61 ++++++++++++
 .../src/views/load-data-view/load-data-view.tsx    |  16 +++
 .../parse-data-table/parse-data-table.spec.tsx     |   1 +
 .../parse-data-table/parse-data-table.tsx          |   3 +-
 10 files changed, 227 insertions(+), 77 deletions(-)

diff --git a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
index d1cf2ff..cfba9f0 100644
--- a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
+++ b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
@@ -4,28 +4,28 @@ exports[`table cell matches snapshot array long 1`] = `
 <span
   class="table-cell truncated"
 >
-  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+  [0, 1, 2, 3, 4, 5, 6, 7
   <span
     class="omitted"
   >
-    ...323 omitted...
+    ...357 omitted...
   </span>
   7, 98, 99]
   <span
-    class="bp3-icon bp3-icon-clipboard action-icon"
-    icon="clipboard"
+    class="bp3-icon bp3-icon-more action-icon"
+    icon="more"
   >
     <svg
-      data-icon="clipboard"
+      data-icon="more"
       height="16"
       viewBox="0 0 16 16"
       width="16"
     >
       <desc>
-        clipboard
+        more
       </desc>
       <path
-        d="M11 2c0-.55-.45-1-1-1h.22C9.88.4 9.24 0 8.5 0S7.12.4 6.78 1H7c-.55 0-1 .45-1 1v1h5V2zm2 0h-1v2H5V2H4c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h9c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1z"
+        d="M2 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4zM14 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4zM8 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4z"
         fill-rule="evenodd"
       />
     </svg>
@@ -57,28 +57,28 @@ exports[`table cell matches snapshot truncate 1`] = `
 <span
   class="table-cell truncated"
 >
-  testtesttesttesttesttesttesttesttesttesttesttesttesttestt
+  testtesttesttesttesttes
   <span
     class="omitted"
   >
-    ...329 omitted...
+    ...363 omitted...
   </span>
   sttesttest
   <span
-    class="bp3-icon bp3-icon-clipboard action-icon"
-    icon="clipboard"
+    class="bp3-icon bp3-icon-more action-icon"
+    icon="more"
   >
     <svg
-      data-icon="clipboard"
+      data-icon="more"
       height="16"
       viewBox="0 0 16 16"
       width="16"
     >
       <desc>
-        clipboard
+        more
       </desc>
       <path
-        d="M11 2c0-.55-.45-1-1-1h.22C9.88.4 9.24 0 8.5 0S7.12.4 6.78 1H7c-.55 0-1 .45-1 1v1h5V2zm2 0h-1v2H5V2H4c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h9c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1z"
+        d="M2 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4zM14 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4zM8 6.03a2 2 0 1 0 0 4 2 2 0 1 0 0-4z"
         fill-rule="evenodd"
       />
     </svg>
diff --git a/web-console/src/components/table-cell/table-cell.scss b/web-console/src/components/table-cell/table-cell.scss
index 6be6b71..3671b7d 100644
--- a/web-console/src/components/table-cell/table-cell.scss
+++ b/web-console/src/components/table-cell/table-cell.scss
@@ -47,6 +47,7 @@
       position: absolute;
       top: 0;
       right: 0;
+      color: #f5f8fa;
     }
   }
 }
diff --git a/web-console/src/components/table-cell/table-cell.tsx b/web-console/src/components/table-cell/table-cell.tsx
index 88f6b84..92cfa39 100644
--- a/web-console/src/components/table-cell/table-cell.tsx
+++ b/web-console/src/components/table-cell/table-cell.tsx
@@ -30,6 +30,7 @@ export interface NullTableCellProps extends React.Props<any> {
   value?: any;
   timestamp?: boolean;
   unparseable?: boolean;
+  openModal?: (str: string) => void;
 }
 
 interface ShortParts {
@@ -41,8 +42,8 @@ interface ShortParts {
 export class TableCell extends React.PureComponent<NullTableCellProps> {
   static MAX_CHARS_TO_SHOW = 50;
 
-  static possiblyTruncate(str: string): React.ReactNode {
-    if (str.length < TableCell.MAX_CHARS_TO_SHOW) return str;
+  possiblyTruncate(str: string): React.ReactNode {
+    if (str.length <= TableCell.MAX_CHARS_TO_SHOW) return str;
 
     const { prefix, omitted, suffix } = TableCell.shortenString(str);
     return (
@@ -51,14 +52,8 @@ export class TableCell extends React.PureComponent<NullTableCellProps> {
         <span className="omitted">{omitted}</span>
         {suffix}
         <ActionIcon
-          icon={IconNames.CLIPBOARD}
-          onClick={() => {
-            copy(str, { format: 'text/plain' });
-            AppToaster.show({
-              message: 'Value copied to clipboard',
-              intent: Intent.SUCCESS,
-            });
-          }}
+          icon={IconNames.MORE}
+          onClick={() => (this.props.openModal ? this.props.openModal(str) : null)}
         />
       </span>
     );
@@ -67,7 +62,7 @@ export class TableCell extends React.PureComponent<NullTableCellProps> {
   static shortenString(str: string): ShortParts {
     // Print something like:
     // BAAAArAAEiQKpDAEAACwZCBAGSBgiSEAAAAQpAIDwAg...23 omitted...gwiRoQBJIC
-    const omit = str.length - (TableCell.MAX_CHARS_TO_SHOW + 17);
+    const omit = str.length - (TableCell.MAX_CHARS_TO_SHOW - 17);
     const prefix = str.substr(0, str.length - (omit + 10));
     const suffix = str.substr(str.length - 10);
     return {
@@ -89,9 +84,9 @@ export class TableCell extends React.PureComponent<NullTableCellProps> {
           </span>
         );
       } else if (Array.isArray(value)) {
-        return TableCell.possiblyTruncate(`[${value.join(', ')}]`);
+        return this.possiblyTruncate(`[${value.join(', ')}]`);
       } else {
-        return TableCell.possiblyTruncate(String(value));
+        return this.possiblyTruncate(String(value));
       }
     } else {
       if (timestamp) {
diff --git a/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap b/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap
new file mode 100644
index 0000000..144f880
--- /dev/null
+++ b/web-console/src/dialogs/show-value-dialog/__snapshots__/show-value-dialog.spec.tsx.snap
@@ -0,0 +1,107 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`clipboard dialog matches snapshot 1`] = `
+<div
+  class="bp3-portal"
+>
+  <div
+    class="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
+  >
+    <div
+      class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
+      tabindex="0"
+    />
+    <div
+      class="bp3-dialog-container bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
+      tabindex="0"
+    >
+      <div
+        class="bp3-dialog show-value-dialog"
+      >
+        <div
+          class="bp3-dialog-header"
+        >
+          <h4
+            class="bp3-heading"
+          >
+            Show value
+          </h4>
+          <button
+            aria-label="Close"
+            class="bp3-button bp3-minimal bp3-dialog-close-button"
+            type="button"
+          >
+            <span
+              class="bp3-icon bp3-icon-small-cross"
+              icon="small-cross"
+            >
+              <svg
+                data-icon="small-cross"
+                height="20"
+                viewBox="0 0 20 20"
+                width="20"
+              >
+                <desc>
+                  small-cross
+                </desc>
+                <path
+                  d="M11.41 10l3.29-3.29c.19-.18.3-.43.3-.71a1.003 1.003 0 0 0-1.71-.71L10 8.59l-3.29-3.3a1.003 1.003 0 0 0-1.42 1.42L8.59 10 5.3 13.29c-.19.18-.3.43-.3.71a1.003 1.003 0 0 0 1.71.71l3.29-3.3 3.29 3.29c.18.19.43.3.71.3a1.003 1.003 0 0 0 .71-1.71L11.41 10z"
+                  fill-rule="evenodd"
+                />
+              </svg>
+            </span>
+          </button>
+        </div>
+        <textarea
+          class="bp3-input"
+        >
+          Bot: Automatska zamjena teksta  (-[[Administrativna podjela Meksika|Admin]] +[[Administrativna podjela Meksika|Admi]])
+        </textarea>
+        <div
+          class="bp3-dialog-footer-actions"
+        >
+          <button
+            class="bp3-button"
+            type="button"
+          >
+            <span
+              class="bp3-icon bp3-icon-duplicate"
+              icon="duplicate"
+            >
+              <svg
+                data-icon="duplicate"
+                height="16"
+                viewBox="0 0 16 16"
+                width="16"
+              >
+                <desc>
+                  duplicate
+                </desc>
+                <path
+                  d="M15 0H5c-.55 0-1 .45-1 1v2h2V2h8v7h-1v2h2c.55 0 1-.45 1-1V1c0-.55-.45-1-1-1zm-4 4H1c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h10c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1zm-1 10H2V6h8v8z"
+                  fill-rule="evenodd"
+                />
+              </svg>
+            </span>
+            <span
+              class="bp3-button-text"
+            >
+              Copy
+            </span>
+          </button>
+          <button
+            class="bp3-button bp3-intent-primary"
+            type="button"
+          >
+            <span
+              class="bp3-button-text"
+            >
+              Close
+            </span>
+          </button>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/table-cell/table-cell.scss b/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss
similarity index 63%
copy from web-console/src/components/table-cell/table-cell.scss
copy to web-console/src/dialogs/show-value-dialog/show-value-dialog.scss
index 6be6b71..1ef9e94 100644
--- a/web-console/src/components/table-cell/table-cell.scss
+++ b/web-console/src/dialogs/show-value-dialog/show-value-dialog.scss
@@ -16,37 +16,18 @@
  * limitations under the License.
  */
 
-.table-cell {
-  &.null {
-    font-style: italic;
+.show-value-dialog{
+  &.bp3-dialog{
+    padding-bottom: 10px;
   }
 
-  &.unparseable {
-    color: #9e2b0e;
+  .bp3-input{
+    margin: 10px;
+    height: 400px;
   }
 
-  &.timestamp {
-    font-weight: bold;
-  }
-
-  &.truncated {
-    position: relative;
-    width: 100%;
-    display: inline-block;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    padding-right: 16px;
-
-    .omitted {
-      margin: 0 0.2em;
-      font-style: italic;
-    }
+  .bp3-dialog-footer-actions{
+    padding-right: 10px;
 
-    .action-icon {
-      position: absolute;
-      top: 0;
-      right: 0;
-    }
   }
 }
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx b/web-console/src/dialogs/show-value-dialog/show-value-dialog.spec.tsx
similarity index 64%
copy from web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
copy to web-console/src/dialogs/show-value-dialog/show-value-dialog.spec.tsx
index c3267f1..d8dc72d 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
+++ b/web-console/src/dialogs/show-value-dialog/show-value-dialog.spec.tsx
@@ -19,32 +19,19 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { ParseDataTable } from './parse-data-table';
+import { ShowValueDialog } from './show-value-dialog';
 
-describe('parse data table', () => {
+describe('clipboard dialog', () => {
   it('matches snapshot', () => {
-    const sampleData = {
-      header: ['c1'],
-      rows: [
-        {
-          raw: `{"c1":"hello"}`,
-          parsed: { c1: 'hello' },
-        },
-      ],
-    };
-
-    const parseDataTable = (
-      <ParseDataTable
-        sampleData={sampleData}
-        columnFilter=""
-        canFlatten={false}
-        flattenedColumnsOnly={false}
-        flattenFields={[]}
-        onFlattenFieldSelect={() => null}
+    const compactionDialog = (
+      <ShowValueDialog
+        onClose={() => null}
+        str={
+          'Bot: Automatska zamjena teksta  (-[[Administrativna podjela Meksika|Admin]] +[[Administrativna podjela Meksika|Admi]])'
+        }
       />
     );
-
-    const { container } = render(parseDataTable);
+    const { container } = render(compactionDialog, { container: document.body });
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx b/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx
new file mode 100644
index 0000000..4a92aa8
--- /dev/null
+++ b/web-console/src/dialogs/show-value-dialog/show-value-dialog.tsx
@@ -0,0 +1,61 @@
+/*
+ * 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 { Button, Classes, Dialog, IconName, Intent, TextArea } from '@blueprintjs/core';
+import { IconNames } from '@blueprintjs/icons';
+import copy = require('copy-to-clipboard');
+import React from 'react';
+
+import { AppToaster } from '../../singletons/toaster';
+
+import './show-value-dialog.scss';
+
+export interface ShowValueDialogProps extends React.Props<any> {
+  onClose: () => void;
+  str: string;
+}
+
+export class ShowValueDialog extends React.PureComponent<ShowValueDialogProps> {
+  constructor(props: ShowValueDialogProps) {
+    super(props);
+    this.state = {};
+  }
+
+  render() {
+    const { onClose, str } = this.props;
+
+    return (
+      <Dialog className="show-value-dialog" isOpen onClose={onClose} title={'Show value'}>
+        <TextArea value={str} />
+        <div className={Classes.DIALOG_FOOTER_ACTIONS}>
+          <Button
+            icon={IconNames.DUPLICATE}
+            text={'Copy'}
+            onClick={() => {
+              copy(str, { format: 'text/plain' });
+              AppToaster.show({
+                message: 'Value copied to clipboard',
+                intent: Intent.SUCCESS,
+              });
+            }}
+          />
+          <Button text={'Close'} intent={'primary'} onClick={onClose} />
+        </div>
+      </Dialog>
+    );
+  }
+}
diff --git a/web-console/src/views/load-data-view/load-data-view.tsx b/web-console/src/views/load-data-view/load-data-view.tsx
index efc853d..38f24e6 100644
--- a/web-console/src/views/load-data-view/load-data-view.tsx
+++ b/web-console/src/views/load-data-view/load-data-view.tsx
@@ -25,6 +25,7 @@ import {
   Card,
   Classes,
   Code,
+  Dialog,
   Elevation,
   FormGroup,
   H5,
@@ -50,6 +51,7 @@ import {
   Loader,
 } from '../../components';
 import { AsyncActionDialog } from '../../dialogs';
+import { ShowValueDialog } from '../../dialogs/show-value-dialog/show-value-dialog';
 import { AppToaster } from '../../singletons/toaster';
 import { UrlBaser } from '../../singletons/url-baser';
 import {
@@ -233,6 +235,8 @@ export interface LoadDataViewState {
   showResetConfirm: boolean;
   newRollup: boolean | null;
   newDimensionMode: DimensionMode | null;
+  showViewValueModal: boolean;
+  str: string;
 
   // welcome
   overlordModules: string[] | null;
@@ -296,8 +300,10 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
       // dialogs / modals
       showResetConfirm: false,
+      showViewValueModal: false,
       newRollup: null,
       newDimensionMode: null,
+      str: '',
 
       // welcome
       overlordModules: null,
@@ -426,6 +432,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
         {step === 'loading' && this.renderLoading()}
 
         {this.renderResetConfirm()}
+        {this.renderViewValueModal()}
       </div>
     );
   }
@@ -539,6 +546,14 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     );
   }
 
+  renderViewValueModal() {
+    const { showViewValueModal, str } = this.state;
+    if (!showViewValueModal) return null;
+    return (
+      <ShowValueDialog onClose={() => this.setState({ showViewValueModal: false })} str={str} />
+    );
+  }
+
   renderWelcomeStepMessage() {
     const { selectedComboType } = this.state;
 
@@ -970,6 +985,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             )}
           </div>
           <ParseDataTable
+            openModal={str => this.setState({ showViewValueModal: true, str: str })}
             sampleData={parserQueryState.data}
             columnFilter={columnFilter}
             canFlatten={canFlatten}
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
index c3267f1..4977955 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
@@ -35,6 +35,7 @@ describe('parse data table', () => {
 
     const parseDataTable = (
       <ParseDataTable
+        openModal={() => null}
         sampleData={sampleData}
         columnFilter=""
         canFlatten={false}
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
index 0045d29..0cee551 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
@@ -34,6 +34,7 @@ export interface ParseDataTableProps extends React.Props<any> {
   flattenedColumnsOnly: boolean;
   flattenFields: FlattenField[];
   onFlattenFieldSelect: (field: FlattenField, index: number) => void;
+  openModal: (str: string) => void;
 }
 
 export class ParseDataTable extends React.PureComponent<ParseDataTableProps> {
@@ -77,7 +78,7 @@ export class ParseDataTable extends React.PureComponent<ParseDataTableProps> {
               if (row.original.unparseable) {
                 return <TableCell unparseable />;
               }
-              return <TableCell value={row.value} />;
+              return <TableCell value={row.value} openModal={str => this.props.openModal(str)} />;
             },
             headerClassName: classNames({
               flattened: flattenField,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org