From b0c78ff295533df80391109c9038a499271ab2a0 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Fri, 11 Aug 2023 09:43:00 -0700 Subject: [PATCH] Web console: make retention dialog clearer (#14793) * make retention dialog clearer * tweak * another tweak * Update web-console/src/dialogs/retention-dialog/retention-dialog.tsx Co-authored-by: Suneet Saldanha * update snapshot for copy --------- Co-authored-by: Suneet Saldanha --- .../src/components/json-input/json-input.tsx | 5 +- .../components/rule-editor/rule-editor.tsx | 41 ++- .../retention-dialog.spec.tsx.snap | 326 +++++++++++++++++- .../retention-dialog/retention-dialog.scss | 4 - .../retention-dialog/retention-dialog.tsx | 55 ++- 5 files changed, 363 insertions(+), 68 deletions(-) diff --git a/web-console/src/components/json-input/json-input.tsx b/web-console/src/components/json-input/json-input.tsx index b206db77e995..f4ffddc11142 100644 --- a/web-console/src/components/json-input/json-input.tsx +++ b/web-console/src/components/json-input/json-input.tsx @@ -66,7 +66,7 @@ interface InternalValue { interface JsonInputProps { value: any; - onChange: (value: any) => void; + onChange?: (value: any) => void; setError?: (error: Error | undefined) => void; placeholder?: string; focus?: boolean; @@ -123,7 +123,7 @@ export const JsonInput = React.memo(function JsonInput(props: JsonInputProps) { setError?.(error); if (!error) { - onChange(value); + onChange?.(value); } if (showErrorIfNeeded) { @@ -131,6 +131,7 @@ export const JsonInput = React.memo(function JsonInput(props: JsonInputProps) { } }} onBlur={() => setShowErrorIfNeeded(true)} + readOnly={!onChange} focus={focus} fontSize={12} width={width || '100%'} diff --git a/web-console/src/components/rule-editor/rule-editor.tsx b/web-console/src/components/rule-editor/rule-editor.tsx index 52eb5b805c94..3f72a8ca4119 100644 --- a/web-console/src/components/rule-editor/rule-editor.tsx +++ b/web-console/src/components/rule-editor/rule-editor.tsx @@ -42,22 +42,23 @@ const PERIOD_SUGGESTIONS: string[] = ['P1D', 'P7D', 'P1M', 'P1Y', 'P1000Y']; export interface RuleEditorProps { rule: Rule; tiers: string[]; - onChange(newRule: Rule): void; - onDelete(): void; - moveUp: (() => void) | undefined; - moveDown: (() => void) | undefined; + onChange?: (newRule: Rule) => void; + onDelete?: () => void; + moveUp?: () => void; + moveDown?: () => void; } export const RuleEditor = React.memo(function RuleEditor(props: RuleEditorProps) { const { rule, onChange, tiers, onDelete, moveUp, moveDown } = props; const [isOpen, setIsOpen] = useState(true); + const disabled = !onChange; function removeTier(key: string) { const newTierReplicants = { ...rule.tieredReplicants }; delete newTierReplicants[key]; const newRule = { ...rule, tieredReplicants: newTierReplicants }; - onChange(newRule); + onChange?.(newRule); } function addTier() { @@ -72,7 +73,7 @@ export const RuleEditor = React.memo(function RuleEditor(props: RuleEditorProps) } } - onChange(RuleUtil.addTieredReplicant(rule, newTierName, 1)); + onChange?.(RuleUtil.addTieredReplicant(rule, newTierName, 1)); } function renderTiers() { @@ -90,14 +91,15 @@ export const RuleEditor = React.memo(function RuleEditor(props: RuleEditorProps) {tieredReplicantsList.map(([tier, replication]) => ( - - onChange(RuleUtil.renameTieredReplicants(rule, tier, e.target.value)) + onChange?.(RuleUtil.renameTieredReplicants(rule, tier, e.target.value)) } > ))} - { if (isNaN(v)) return; - onChange(RuleUtil.addTieredReplicant(rule, tier, v)); + onChange?.(RuleUtil.addTieredReplicant(rule, tier, v)); }} min={0} max={256} /> - + + loadForever(2x) + + + +
+
+
+
+
+
+
+
+
+ + + + + Open dropdown + + + + +
+
+
+
+
+
+
+ +
+ + + + + Open dropdown + + + + +
+ +
+
+ +
+
+ + +
+
+
+
+
+
+
+
diff --git a/web-console/src/dialogs/retention-dialog/retention-dialog.scss b/web-console/src/dialogs/retention-dialog/retention-dialog.scss index df521abbd11b..fb55a8d44556 100644 --- a/web-console/src/dialogs/retention-dialog/retention-dialog.scss +++ b/web-console/src/dialogs/retention-dialog/retention-dialog.scss @@ -45,9 +45,5 @@ padding: 0 15px; } } - - .default-rule { - margin-top: 10px; - } } } diff --git a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx index 64204137067e..677173cc6d3f 100644 --- a/web-console/src/dialogs/retention-dialog/retention-dialog.tsx +++ b/web-console/src/dialogs/retention-dialog/retention-dialog.tsx @@ -28,7 +28,6 @@ import { getLink } from '../../links'; import { Api } from '../../singletons'; import { filterMap, queryDruidSql, swapElements } from '../../utils'; import type { Rule } from '../../utils/load-rule'; -import { RuleUtil } from '../../utils/load-rule'; import { SnitchDialog } from '..'; import './retention-dialog.scss'; @@ -115,28 +114,6 @@ ORDER BY 1`, setCurrentRules(swapElements(currentRules, index, index + direction)); } - function renderRule(rule: Rule, index: number) { - return ( - changeRule(r, index)} - onDelete={() => deleteRule(index)} - moveUp={index > 0 ? () => moveRule(index, -1) : undefined} - moveDown={index < currentRules.length - 1 ? () => moveRule(index, 1) : undefined} - /> - ); - } - - function renderDefaultRule(rule: Rule, index: number) { - return ( -
- -
- ); - } - return ( {currentRules.length ? ( - currentRules.map(renderRule) + currentRules.map((rule, index) => ( + changeRule(r, index)} + onDelete={() => deleteRule(index)} + moveUp={index > 0 ? () => moveRule(index, -1) : undefined} + moveDown={index < currentRules.length - 1 ? () => moveRule(index, 1) : undefined} + /> + )) ) : datasource !== CLUSTER_DEFAULT_FAKE_DATASOURCE ? (

This datasource currently has no rules, it will use the cluster defaults. @@ -194,11 +181,21 @@ ORDER BY 1`, {datasource !== CLUSTER_DEFAULT_FAKE_DATASOURCE && ( <> - -

- Cluster defaults (edit): -

- {defaultRules.map(renderDefaultRule)} + + Cluster defaults (edit) + + } + > +

The cluster default rules are evaluated if none of the above rules match.

+ {currentTab === 'form' ? ( + defaultRules.map((rule, index) => ( + + )) + ) : ( + + )}
)}