Skip to content

Commit

Permalink
Merge pull request marmelab#5152 from marmelab/fix-edit-refresh
Browse files Browse the repository at this point in the history
Disable Edit Automatic Refresh if Form is Dirty
  • Loading branch information
fzaninotto authored Aug 13, 2020
2 parents 492d18d + 448270b commit e8e2619
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 2 deletions.
12 changes: 12 additions & 0 deletions packages/ra-core/src/actions/uiActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,15 @@ export interface RefreshViewAction {
export const refreshView = (): RefreshViewAction => ({
type: REFRESH_VIEW,
});

export const SET_AUTOMATIC_REFRESH = 'RA/SET_AUTOMATIC_REFRESH';

export interface SetAutomaticRefreshAction {
readonly type: typeof SET_AUTOMATIC_REFRESH;
readonly payload: boolean;
}

export const setAutomaticRefresh = (enabled: boolean) => ({
type: SET_AUTOMATIC_REFRESH,
payload: enabled,
});
2 changes: 2 additions & 0 deletions packages/ra-core/src/dataProvider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import useCreate from './useCreate';
import useDelete from './useDelete';
import useDeleteMany from './useDeleteMany';
import useRefreshWhenVisible from './useRefreshWhenVisible';
import useIsAutomaticRefreshEnabled from './useIsAutomaticRefreshEnabled';

export {
cacheDataProviderProxy,
Expand All @@ -48,4 +49,5 @@ export {
useQueryWithStore,
useRefreshWhenVisible,
withDataProvider,
useIsAutomaticRefreshEnabled,
};
12 changes: 12 additions & 0 deletions packages/ra-core/src/dataProvider/useIsAutomaticRefreshEnabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useSelector } from 'react-redux';
import { ReduxState } from '../types';

const useIsAutomaticRefreshEnabled = () => {
const automaticRefreshEnabled = useSelector<ReduxState>(
state => state.admin.ui.automaticRefreshEnabled
);

return automaticRefreshEnabled;
};

export default useIsAutomaticRefreshEnabled;
8 changes: 7 additions & 1 deletion packages/ra-core/src/dataProvider/useRefreshWhenVisible.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect } from 'react';
import { useRefresh } from '../sideEffect';
import useIsAutomaticRefreshEnabled from './useIsAutomaticRefreshEnabled';

/**
* Trigger a refresh of the page when the page comes back from background after a certain delay
Expand All @@ -8,9 +9,14 @@ import { useRefresh } from '../sideEffect';
*/
const useRefreshWhenVisible = (delay = 1000 * 60 * 5) => {
const refresh = useRefresh();
const automaticRefreshEnabled = useIsAutomaticRefreshEnabled();

useEffect(() => {
let lastHiddenTime;
const handleVisibilityChange = () => {
if (!automaticRefreshEnabled) {
return;
}
if (document.hidden) {
// tab goes hidden
lastHiddenTime = Date.now();
Expand All @@ -30,7 +36,7 @@ const useRefreshWhenVisible = (delay = 1000 * 60 * 5) => {
'visibilitychange',
handleVisibilityChange
);
}, [delay, refresh]);
}, [automaticRefreshEnabled, delay, refresh]);
};

export default useRefreshWhenVisible;
9 changes: 8 additions & 1 deletion packages/ra-core/src/form/FormWithRedirect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { FC, useRef, useCallback, useMemo } from 'react';
import { FC, useRef, useCallback, useEffect, useMemo } from 'react';
import { Form, FormProps } from 'react-final-form';
import arrayMutators from 'final-form-arrays';

Expand All @@ -10,6 +10,8 @@ import getFormInitialValues from './getFormInitialValues';
import FormContext from './FormContext';
import { Record } from '../types';
import { RedirectionSideEffect } from '../sideEffect';
import { useDispatch } from 'react-redux';
import { setAutomaticRefresh } from '../actions';

/**
* Wrapper around react-final-form's Form to handle redirection on submit,
Expand Down Expand Up @@ -174,6 +176,11 @@ const FormView = ({ render, warnWhenUnsavedChanges, ...props }) => {
// if record changes (after a getOne success or a refresh), the form must be updated
useInitializeFormWithRecord(props.record);
useWarnWhenUnsavedChanges(warnWhenUnsavedChanges);
const dispatch = useDispatch();

useEffect(() => {
dispatch(setAutomaticRefresh(props.pristine));
}, [dispatch, props.pristine]);

const { redirect, setRedirect, handleSubmit } = props;

Expand Down
32 changes: 32 additions & 0 deletions packages/ra-core/src/reducer/admin/ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import {
toggleSidebar,
setSidebarVisibility,
refreshView,
setAutomaticRefresh,
} from '../../actions/uiActions';
import reducer from './ui';

describe('ui reducer', () => {
const defaultState = {
automaticRefreshEnabled: true,
sidebarOpen: false,
optimistic: false,
viewVersion: 0,
Expand Down Expand Up @@ -49,8 +51,38 @@ describe('ui reducer', () => {
)
);
});
it('should return activated autimatic refresh by default', () => {
expect(reducer(undefined, { type: 'foo' })).toEqual(defaultState);
});
it('should set sidebar visibility upon SET_AUTOMATIC_REFRESH', () => {
expect({ ...defaultState, automaticRefreshEnabled: false }).toEqual(
reducer(
{ ...defaultState, automaticRefreshEnabled: true },
setAutomaticRefresh(false)
)
);
expect({ ...defaultState, automaticRefreshEnabled: true }).toEqual(
reducer(
{ ...defaultState, automaticRefreshEnabled: true },
setAutomaticRefresh(true)
)
);
expect({ ...defaultState, automaticRefreshEnabled: false }).toEqual(
reducer(
{ ...defaultState, automaticRefreshEnabled: false },
setAutomaticRefresh(false)
)
);
expect({ ...defaultState, automaticRefreshEnabled: true }).toEqual(
reducer(
{ ...defaultState, automaticRefreshEnabled: false },
setAutomaticRefresh(true)
)
);
});
it('should increment the viewVersion upon REFRESH_VIEW', () => {
expect({
automaticRefreshEnabled: true,
optimistic: false,
sidebarOpen: false,
viewVersion: 1,
Expand Down
10 changes: 10 additions & 0 deletions packages/ra-core/src/reducer/admin/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
StartOptimisticModeAction,
STOP_OPTIMISTIC_MODE,
StopOptimisticModeAction,
SET_AUTOMATIC_REFRESH,
SetAutomaticRefreshAction,
} from '../../actions';

type ActionTypes =
Expand All @@ -18,9 +20,11 @@ type ActionTypes =
| RefreshViewAction
| StartOptimisticModeAction
| StopOptimisticModeAction
| SetAutomaticRefreshAction
| { type: 'OTHER_ACTION' };

export interface UIState {
readonly automaticRefreshEnabled: boolean;
readonly sidebarOpen: boolean;
readonly optimistic: boolean;
readonly viewVersion: number;
Expand All @@ -37,6 +41,7 @@ const isDesktop = (): boolean =>
: false;

const defaultState: UIState = {
automaticRefreshEnabled: true,
sidebarOpen: isDesktop(),
optimistic: false,
viewVersion: 0,
Expand All @@ -54,6 +59,11 @@ const uiReducer: Reducer<UIState> = (
};
case SET_SIDEBAR_VISIBILITY:
return { ...previousState, sidebarOpen: action.payload };
case SET_AUTOMATIC_REFRESH:
return {
...previousState,
automaticRefreshEnabled: action.payload,
};
case REFRESH_VIEW:
return {
...previousState,
Expand Down
1 change: 1 addition & 0 deletions packages/ra-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export type LegacyDataProvider = (
export interface ReduxState {
admin: {
ui: {
automaticRefreshEnabled: boolean;
optimistic: boolean;
sidebarOpen: boolean;
viewVersion: number;
Expand Down

0 comments on commit e8e2619

Please sign in to comment.