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>
</>
}
/>