You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by vo...@apache.org on 2022/09/02 18:31:49 UTC

[druid] branch 24.0.0 updated: Web console: don't crash if cookies are totally disabled (#13013) (#13018)

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

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


The following commit(s) were added to refs/heads/24.0.0 by this push:
     new 0ddc9cd3f5 Web console: don't crash if cookies are totally disabled (#13013) (#13018)
0ddc9cd3f5 is described below

commit 0ddc9cd3f527adcd60aa3a62bcc50b0a2df47382
Author: Vadim Ogievetsky <va...@ogievetsky.com>
AuthorDate: Fri Sep 2 11:31:32 2022 -0700

    Web console: don't crash if cookies are totally disabled (#13013) (#13018)
    
    * fix local storage detection
    
    * fix numeric input dialog
---
 web-console/e2e-tests/util/playwright.ts           |  2 +-
 .../numeric-input-dialog/numeric-input-dialog.tsx  | 52 +++++++++++++++-------
 web-console/src/utils/local-storage-keys.tsx       | 14 ++++--
 .../max-tasks-button/max-tasks-button.tsx          |  1 +
 4 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/web-console/e2e-tests/util/playwright.ts b/web-console/e2e-tests/util/playwright.ts
index e2c9ed5d1d..6c838ca2a4 100644
--- a/web-console/e2e-tests/util/playwright.ts
+++ b/web-console/e2e-tests/util/playwright.ts
@@ -27,7 +27,7 @@ export async function createBrowser(): Promise<playwright.Browser> {
   const headless = process.env['DRUID_E2E_TEST_HEADLESS'] || TRUE;
   const debug = headless !== TRUE;
   const launchOptions: any = {
-    args: [`--window-size=${WIDTH},${HEIGHT + PADDING}`],
+    args: [`--window-size=${WIDTH},${HEIGHT + PADDING}`, `--disable-local-storage`],
   };
   if (debug) {
     launchOptions.headless = false;
diff --git a/web-console/src/dialogs/numeric-input-dialog/numeric-input-dialog.tsx b/web-console/src/dialogs/numeric-input-dialog/numeric-input-dialog.tsx
index b115e035b8..86abce9097 100644
--- a/web-console/src/dialogs/numeric-input-dialog/numeric-input-dialog.tsx
+++ b/web-console/src/dialogs/numeric-input-dialog/numeric-input-dialog.tsx
@@ -26,6 +26,7 @@ interface NumericInputDialogProps {
   message?: JSX.Element;
   minValue?: number;
   initValue: number;
+  integer?: boolean;
   onSubmit(value: number): void;
   onClose(): void;
 }
@@ -33,9 +34,19 @@ interface NumericInputDialogProps {
 export const NumericInputDialog = React.memo(function NumericInputDialog(
   props: NumericInputDialogProps,
 ) {
-  const { title, message, minValue, initValue, onSubmit, onClose } = props;
+  const { title, message, minValue, initValue, integer, onSubmit, onClose } = props;
+  const effectiveMinValue = minValue ?? DEFAULT_MIN_VALUE;
 
-  const [value, setValue] = useState<number>(initValue);
+  const [valueString, setValueString] = useState<string>(String(initValue));
+
+  function done() {
+    let value = Math.max(Number(valueString) || 0, effectiveMinValue);
+    if (integer) {
+      value = Math.round(value);
+    }
+    onSubmit(value);
+    onClose();
+  }
 
   return (
     <Dialog
@@ -48,30 +59,41 @@ export const NumericInputDialog = React.memo(function NumericInputDialog(
       <div className={Classes.DIALOG_BODY}>
         {message}
         <NumericInput
-          value={value}
-          onValueChange={(v: number) => {
-            if (isNaN(v)) return;
-            setValue(Math.max(v, DEFAULT_MIN_VALUE));
+          value={valueString}
+          onValueChange={(_, v) => {
+            // Constrain to only simple numeric characters
+            v = v.replace(/[^\d\-.]/, '');
+
+            if (integer) {
+              // If in integer mode throw away the decimal point
+              v = v.replace(/\./, '');
+            }
+
+            if (effectiveMinValue >= 0) {
+              // If in non-negative mode throw away the minus
+              v = v.replace(/-/, '');
+            }
+
+            setValueString(v);
+          }}
+          onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
+            if (e.key !== 'Enter') return;
+            done();
           }}
-          min={minValue ?? DEFAULT_MIN_VALUE}
+          min={effectiveMinValue}
           stepSize={1}
           minorStepSize={null}
           majorStepSize={10}
           fill
           autoFocus
+          selectAllOnFocus
+          allowNumericCharactersOnly
         />
       </div>
       <div className={Classes.DIALOG_FOOTER}>
         <div className={Classes.DIALOG_FOOTER_ACTIONS}>
           <Button text="Close" onClick={onClose} />
-          <Button
-            text="OK"
-            intent={Intent.PRIMARY}
-            onClick={() => {
-              onSubmit(value);
-              onClose();
-            }}
-          />
+          <Button text="OK" intent={Intent.PRIMARY} onClick={done} />
         </div>
       </div>
     </Dialog>
diff --git a/web-console/src/utils/local-storage-keys.tsx b/web-console/src/utils/local-storage-keys.tsx
index dcc5093887..d218d4b18a 100644
--- a/web-console/src/utils/local-storage-keys.tsx
+++ b/web-console/src/utils/local-storage-keys.tsx
@@ -18,6 +18,14 @@
 
 import * as JSONBig from 'json-bigint-native';
 
+function noLocalStorage(): boolean {
+  try {
+    return typeof localStorage === 'undefined';
+  } catch {
+    return true;
+  }
+}
+
 export const LocalStorageKeys = {
   CAPABILITIES_OVERRIDE: 'capabilities-override' as const,
   INGESTION_SPEC: 'ingestion-spec' as const,
@@ -65,7 +73,7 @@ function prependNamespace(key: string): string {
 }
 
 export function localStorageSet(key: LocalStorageKeys, value: string): void {
-  if (typeof localStorage === 'undefined') return;
+  if (noLocalStorage()) return;
   try {
     localStorage.setItem(prependNamespace(key), value);
   } catch (e) {
@@ -78,7 +86,7 @@ export function localStorageSetJson(key: LocalStorageKeys, value: any): void {
 }
 
 export function localStorageGet(key: LocalStorageKeys): string | undefined {
-  if (typeof localStorage === 'undefined') return;
+  if (noLocalStorage()) return;
   try {
     return localStorage.getItem(prependNamespace(key)) || localStorage.getItem(key) || undefined;
   } catch (e) {
@@ -98,7 +106,7 @@ export function localStorageGetJson(key: LocalStorageKeys): any {
 }
 
 export function localStorageRemove(key: LocalStorageKeys): void {
-  if (typeof localStorage === 'undefined') return;
+  if (noLocalStorage()) return;
   try {
     localStorage.removeItem(prependNamespace(key));
   } catch (e) {
diff --git a/web-console/src/views/workbench-view/max-tasks-button/max-tasks-button.tsx b/web-console/src/views/workbench-view/max-tasks-button/max-tasks-button.tsx
index 2830befa15..7391ebaf6e 100644
--- a/web-console/src/views/workbench-view/max-tasks-button/max-tasks-button.tsx
+++ b/web-console/src/views/workbench-view/max-tasks-button/max-tasks-button.tsx
@@ -103,6 +103,7 @@ export const MaxTasksButton = function MaxTasksButton(props: MaxTasksButtonProps
             </>
           }
           minValue={2}
+          integer
           initValue={maxNumTasks}
           onSubmit={p => {
             changeQueryContext(changeMaxNumTasks(queryContext, p));


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