You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2024/04/24 14:38:59 UTC

(superset) branch master updated: feat: custom refresh frequency (#24449)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new cf90def462 feat: custom refresh frequency (#24449)
cf90def462 is described below

commit cf90def462aac77b60811b98c580330947714aa3
Author: Abhishek-kumar-samsung <a....@samsung.com>
AuthorDate: Wed Apr 24 20:08:52 2024 +0530

    feat: custom refresh frequency (#24449)
    
    Co-authored-by: Nitesh Kumar Dubey Samsung <13...@users.noreply.github.com>
---
 .../components/RefreshIntervalModal.test.tsx       |  17 ++
 .../dashboard/components/RefreshIntervalModal.tsx  | 200 +++++++++++++++++++--
 2 files changed, 201 insertions(+), 16 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx b/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx
index 17c08e0701..961c9cacb5 100644
--- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx
+++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.test.tsx
@@ -171,6 +171,23 @@ test('should change selected value', async () => {
   expect(selectedValue.title).not.toMatch(/don't refresh/i);
 });
 
+test('should change selected value to custom value', async () => {
+  render(setup(editModeOnProps));
+  await openRefreshIntervalModal();
+
+  // Initial selected value should be "Don't refresh"
+  const selectedValue = screen.getByText(/don't refresh/i);
+  expect(selectedValue.title).toMatch(/don't refresh/i);
+
+  // Display options and select "Custom interval"
+  await displayOptions();
+  userEvent.click(screen.getByText(/Custom interval/i));
+
+  // Selected value should now be "Custom interval"
+  expect(selectedValue.title).toMatch(/Custom interval/i);
+  expect(selectedValue.title).not.toMatch(/don't refresh/i);
+});
+
 test('should save a newly-selected value', async () => {
   render(setup(editModeOnProps));
   await openRefreshIntervalModal();
diff --git a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
index 6299b09c53..b20c8484a6 100644
--- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
+++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.tsx
@@ -21,6 +21,7 @@ import Select from 'src/components/Select/Select';
 import { t, styled } from '@superset-ui/core';
 import Alert from 'src/components/Alert';
 import Button from 'src/components/Button';
+import { Input } from 'src/components/Input';
 
 import ModalTrigger, { ModalTriggerRef } from 'src/components/ModalTrigger';
 import { FormLabel } from 'src/components/Form';
@@ -36,6 +37,16 @@ const RefreshWarningContainer = styled.div`
   margin-top: ${({ theme }) => theme.gridUnit * 6}px;
 `;
 
+const StyledDiv = styled.div`
+  display: flex;
+  margin-top: ${({ theme }) => theme.gridUnit * 3}px;
+`;
+
+const InnerStyledDiv = styled.div`
+  width: 30%;
+  margin: auto;
+`;
+
 type RefreshIntervalModalProps = {
   addSuccessToast: (msg: string) => void;
   triggerNode: JSX.Element;
@@ -49,6 +60,10 @@ type RefreshIntervalModalProps = {
 
 type RefreshIntervalModalState = {
   refreshFrequency: number;
+  custom_hour: number;
+  custom_min: number;
+  custom_sec: number;
+  custom_block: boolean;
 };
 
 class RefreshIntervalModal extends React.PureComponent<
@@ -67,6 +82,10 @@ class RefreshIntervalModal extends React.PureComponent<
     this.modalRef = React.createRef() as ModalTriggerRef;
     this.state = {
       refreshFrequency: props.refreshFrequency,
+      custom_hour: 0,
+      custom_min: 0,
+      custom_sec: 0,
+      custom_block: false,
     };
     this.handleFrequencyChange = this.handleFrequencyChange.bind(this);
     this.onSave = this.onSave.bind(this);
@@ -91,6 +110,85 @@ class RefreshIntervalModal extends React.PureComponent<
     this.setState({
       refreshFrequency: value || refreshIntervalOptions[0][0],
     });
+
+    this.setState({
+      custom_block: value === -1,
+    });
+
+    if (value === -1) {
+      this.setState({
+        custom_hour: 0,
+        custom_min: 0,
+        custom_sec: 0,
+      });
+    }
+  }
+
+  onSaveValue(value: number) {
+    this.props.onChange(value, this.props.editMode);
+    this.modalRef?.current?.close();
+    this.props.addSuccessToast(t('Refresh interval saved'));
+  }
+
+  createIntervalOptions(refreshIntervalOptions: [number, string][]) {
+    const refresh_options = [];
+
+    refresh_options.push({ value: -1, label: t('Custom interval') });
+    refresh_options.push(
+      ...refreshIntervalOptions.map(option => ({
+        value: option[0],
+        label: t(option[1]),
+      })),
+    );
+
+    return refresh_options;
+  }
+
+  min_sec_options(min_or_sec: string) {
+    return Array.from({ length: 60 }, (_, i) => ({
+      value: i,
+      label: `${i} ${min_or_sec}`,
+    }));
+  }
+
+  refresh_custom_val(
+    custom_block: boolean,
+    custom_hour: number,
+    custom_min: number,
+    custom_sec: number,
+  ) {
+    if (custom_block === true) {
+      // Get hour value
+      const hour_value = custom_hour;
+
+      // Get minutes value
+      const minute_value = custom_min;
+
+      // Get seconds value
+      const second_value = custom_sec;
+
+      if (
+        hour_value < 0 ||
+        minute_value < 0 ||
+        second_value < 0 ||
+        minute_value >= 60 ||
+        second_value >= 60
+      ) {
+        this.props.addSuccessToast(
+          t(
+            'Put positive values and valid minute and second value less than 60',
+          ),
+        );
+      }
+      // Convert given input to seconds
+      const value = hour_value * 60 * 60 + minute_value * 60 + second_value;
+      if (value === 0) {
+        this.props.addSuccessToast(t('Put some positive value greater than 0'));
+        return;
+      }
+      this.handleFrequencyChange(value);
+      this.onSaveValue(value);
+    } else this.onSave();
   }
 
   render() {
@@ -100,7 +198,13 @@ class RefreshIntervalModal extends React.PureComponent<
       editMode,
       refreshIntervalOptions,
     } = this.props;
-    const { refreshFrequency = 0 } = this.state;
+    const {
+      refreshFrequency = 0,
+      custom_hour = 0,
+      custom_min = 0,
+      custom_sec = 0,
+      custom_block = false,
+    } = this.state;
     const showRefreshWarning =
       !!refreshFrequency && !!refreshWarning && refreshFrequency < refreshLimit;
 
@@ -111,17 +215,74 @@ class RefreshIntervalModal extends React.PureComponent<
         modalTitle={t('Refresh interval')}
         modalBody={
           <div>
-            <FormLabel>{t('Refresh frequency')}</FormLabel>
-            <Select
-              ariaLabel={t('Refresh interval')}
-              options={refreshIntervalOptions.map(option => ({
-                value: option[0],
-                label: t(option[1]),
-              }))}
-              value={refreshFrequency}
-              onChange={this.handleFrequencyChange}
-              sortComparator={propertyComparator('value')}
-            />
+            <div id="refresh_from_dropdown">
+              <FormLabel>
+                <b>{t('Refresh frequency')}</b>
+              </FormLabel>
+              <Select
+                ariaLabel={t('Refresh interval')}
+                options={this.createIntervalOptions(refreshIntervalOptions)}
+                value={refreshFrequency}
+                onChange={this.handleFrequencyChange}
+                sortComparator={propertyComparator('value')}
+              />
+            </div>
+            {custom_block && (
+              <StyledDiv>
+                <InnerStyledDiv>
+                  <FormLabel>
+                    <b>{t('HOUR')}</b>
+                  </FormLabel>{' '}
+                  <br />
+                  <Input
+                    type="number"
+                    min="0"
+                    className="form-control input-sm"
+                    placeholder={t('Type a number')}
+                    onChange={event => {
+                      this.setState({
+                        custom_hour: Number(event.target.value),
+                      });
+                    }}
+                    value={custom_hour}
+                  />
+                </InnerStyledDiv>
+                <InnerStyledDiv>
+                  <FormLabel>
+                    <b>{t('MINUTE')}</b>
+                  </FormLabel>{' '}
+                  <br />
+                  <Select
+                    ariaLabel={t('Minutes value')}
+                    options={this.min_sec_options('minutes')}
+                    value={custom_min}
+                    onChange={(value: number) => {
+                      this.setState({
+                        custom_min: value,
+                      });
+                    }}
+                    sortComparator={propertyComparator('value')}
+                  />
+                </InnerStyledDiv>
+                <InnerStyledDiv>
+                  <FormLabel>
+                    <b>{t('SECOND')}</b>
+                  </FormLabel>{' '}
+                  <br />
+                  <Select
+                    ariaLabel={t('Seconds value')}
+                    options={this.min_sec_options('seconds')}
+                    value={custom_sec}
+                    onChange={(value: number) => {
+                      this.setState({
+                        custom_sec: value,
+                      });
+                    }}
+                    sortComparator={propertyComparator('value')}
+                  />
+                </InnerStyledDiv>
+              </StyledDiv>
+            )}
             {showRefreshWarning && (
               <RefreshWarningContainer>
                 <Alert
@@ -140,16 +301,23 @@ class RefreshIntervalModal extends React.PureComponent<
         }
         modalFooter={
           <>
+            <Button onClick={this.onCancel} buttonSize="small">
+              {t('Cancel')}
+            </Button>
             <Button
               buttonStyle="primary"
               buttonSize="small"
-              onClick={this.onSave}
+              onClick={() =>
+                this.refresh_custom_val(
+                  custom_block,
+                  custom_hour,
+                  custom_min,
+                  custom_sec,
+                )
+              }
             >
               {editMode ? t('Save') : t('Save for this session')}
             </Button>
-            <Button onClick={this.onCancel} buttonSize="small">
-              {t('Cancel')}
-            </Button>
           </>
         }
       />