From f4996a9d47a490317a765f279a8b17fb2a623544 Mon Sep 17 00:00:00 2001 From: Xavier Hans Date: Thu, 8 Nov 2018 17:55:08 +0100 Subject: [PATCH 1/5] [WIP] Migrate ra-core actions to Typescript --- ...umulateActions.js => accumulateActions.ts} | 35 +++++++++++---- .../{authActions.js => authActions.ts} | 27 ++++++++++-- .../{fetchActions.js => fetchActions.ts} | 8 ++-- packages/ra-core/src/actions/filterActions.js | 21 --------- packages/ra-core/src/actions/filterActions.ts | 43 +++++++++++++++++++ .../{formActions.js => formActions.ts} | 14 ++++-- .../src/actions/{index.js => index.ts} | 0 .../{listActions.js => listActions.ts} | 15 +++++-- 8 files changed, 121 insertions(+), 42 deletions(-) rename packages/ra-core/src/actions/{accumulateActions.js => accumulateActions.ts} (62%) rename packages/ra-core/src/actions/{authActions.js => authActions.ts} (65%) rename packages/ra-core/src/actions/{fetchActions.js => fetchActions.ts} (57%) delete mode 100644 packages/ra-core/src/actions/filterActions.js create mode 100644 packages/ra-core/src/actions/filterActions.ts rename packages/ra-core/src/actions/{formActions.js => formActions.ts} (51%) rename packages/ra-core/src/actions/{index.js => index.ts} (100%) rename packages/ra-core/src/actions/{listActions.js => listActions.ts} (51%) diff --git a/packages/ra-core/src/actions/accumulateActions.js b/packages/ra-core/src/actions/accumulateActions.ts similarity index 62% rename from packages/ra-core/src/actions/accumulateActions.js rename to packages/ra-core/src/actions/accumulateActions.ts index 4774040f836..90aca6da751 100644 --- a/packages/ra-core/src/actions/accumulateActions.js +++ b/packages/ra-core/src/actions/accumulateActions.ts @@ -2,7 +2,19 @@ import { crudGetMany, crudGetMatching } from './dataActions'; export const CRUD_GET_MANY_ACCUMULATE = 'RA/CRUD_GET_MANY_ACCUMULATE'; -export const crudGetManyAccumulate = (resource, ids) => ({ +export const crudGetManyAccumulate = ( + resource: string, + ids: [] +): { + type: string; + payload: { + resource: string; + ids: []; + }; + meta: { + accumulate: any; + }; +} => ({ type: CRUD_GET_MANY_ACCUMULATE, payload: { resource, ids }, meta: { accumulate: crudGetMany }, @@ -11,12 +23,19 @@ export const crudGetManyAccumulate = (resource, ids) => ({ export const CRUD_GET_MATCHING_ACCUMULATE = 'RA/CRUD_GET_MATCHING_ACCUMULATE'; export const crudGetMatchingAccumulate = ( - reference, - relatedTo, - pagination, - sort, - filter -) => { + reference: string, + relatedTo: string, + pagination: object, + sort: object, + filter: object +): { + type: string; + meta: { + accumulate: any; + accumulateValues: () => boolean; + accumulateKey: string; + }; +} => { const action = crudGetMatching( reference, relatedTo, @@ -32,7 +51,7 @@ export const crudGetMatchingAccumulate = ( accumulateValues: () => true, accumulateKey: JSON.stringify({ resource: reference, - relatedTo: relatedTo, + relatedTo, ...action.payload, }), }, diff --git a/packages/ra-core/src/actions/authActions.js b/packages/ra-core/src/actions/authActions.ts similarity index 65% rename from packages/ra-core/src/actions/authActions.js rename to packages/ra-core/src/actions/authActions.ts index 39ca9ddc74c..bae47c3f7a5 100644 --- a/packages/ra-core/src/actions/authActions.js +++ b/packages/ra-core/src/actions/authActions.ts @@ -4,7 +4,14 @@ export const USER_LOGIN_LOADING = 'RA/USER_LOGIN_LOADING'; export const USER_LOGIN_FAILURE = 'RA/USER_LOGIN_FAILURE'; export const USER_LOGIN_SUCCESS = 'RA/USER_LOGIN_SUCCESS'; -export const userLogin = (payload, pathName) => ({ +export const userLogin = ( + payload: object, + pathName: string +): { + type: string; + payload: object; + meta: { auth: boolean; pathName: string }; +} => ({ type: USER_LOGIN, payload, meta: { auth: true, pathName }, @@ -12,7 +19,15 @@ export const userLogin = (payload, pathName) => ({ export const USER_CHECK = 'RA/USER_CHECK'; -export const userCheck = (payload, pathName, routeParams) => ({ +export const userCheck = ( + payload: object, + pathName: string, + routeParams +): { + type: string; + payload: object; + meta: { auth: boolean; pathName: string }; +} => ({ type: USER_CHECK, payload: { ...payload, @@ -30,7 +45,13 @@ export const USER_LOGOUT = 'RA/USER_LOGOUT'; * @param redirectTo Path to direct to after logout * @return {{type: string, payload: {redirectTo: string}, meta: {auth: boolean}}} */ -export const userLogout = redirectTo => ({ +export const userLogout = ( + redirectTo: string +): { + type: string; + payload: { redirectTo: string }; + meta: { auth: boolean }; +} => ({ type: USER_LOGOUT, payload: { redirectTo, diff --git a/packages/ra-core/src/actions/fetchActions.js b/packages/ra-core/src/actions/fetchActions.ts similarity index 57% rename from packages/ra-core/src/actions/fetchActions.js rename to packages/ra-core/src/actions/fetchActions.ts index e5502fd7b20..bcaddac5051 100644 --- a/packages/ra-core/src/actions/fetchActions.js +++ b/packages/ra-core/src/actions/fetchActions.ts @@ -3,18 +3,18 @@ export const FETCH_END = 'RA/FETCH_END'; export const FETCH_ERROR = 'RA/FETCH_ERROR'; export const FETCH_CANCEL = 'RA/FETCH_CANCEL'; -export const fetchStart = () => ({ +export const fetchStart = (): { type: string } => ({ type: FETCH_START, }); -export const fetchEnd = () => ({ +export const fetchEnd = (): { type: string } => ({ type: FETCH_END, }); -export const fetchError = () => ({ +export const fetchError = (): { type: string } => ({ type: FETCH_ERROR, }); -export const fetchCancel = () => ({ +export const fetchCancel = (): { type: string } => ({ type: FETCH_CANCEL, }); diff --git a/packages/ra-core/src/actions/filterActions.js b/packages/ra-core/src/actions/filterActions.js deleted file mode 100644 index 80e51a25ae7..00000000000 --- a/packages/ra-core/src/actions/filterActions.js +++ /dev/null @@ -1,21 +0,0 @@ -export const CRUD_SHOW_FILTER = 'RA/CRUD_SHOW_FILTER'; -export const CRUD_HIDE_FILTER = 'RA/CRUD_HIDE_FILTER'; -export const CRUD_SET_FILTER = 'RA/CRUD_SET_FILTER'; - -export const showFilter = (resource, field) => ({ - type: CRUD_SHOW_FILTER, - payload: { field }, - meta: { resource }, -}); - -export const hideFilter = (resource, field) => ({ - type: CRUD_HIDE_FILTER, - payload: { field }, - meta: { resource }, -}); - -export const setFilter = (resource, field, value) => ({ - type: CRUD_SET_FILTER, - payload: { field, value }, - meta: { resource }, -}); diff --git a/packages/ra-core/src/actions/filterActions.ts b/packages/ra-core/src/actions/filterActions.ts new file mode 100644 index 00000000000..db36ae940a2 --- /dev/null +++ b/packages/ra-core/src/actions/filterActions.ts @@ -0,0 +1,43 @@ +export const CRUD_SHOW_FILTER = 'RA/CRUD_SHOW_FILTER'; +export const CRUD_HIDE_FILTER = 'RA/CRUD_HIDE_FILTER'; +export const CRUD_SET_FILTER = 'RA/CRUD_SET_FILTER'; + +export const showFilter = ( + resource: string, + field: string +): { + type: string; + payload: { field: string }; + meta: { resource: string }; +} => ({ + type: CRUD_SHOW_FILTER, + payload: { field }, + meta: { resource }, +}); + +export const hideFilter = ( + resource: string, + field: string +): { + type: string; + payload: { field: string }; + meta: { resource: string }; +} => ({ + type: CRUD_HIDE_FILTER, + payload: { field }, + meta: { resource }, +}); + +export const setFilter = ( + resource: string, + field: string, + value: any +): { + type: string; + payload: { field: string; value: any }; + meta: { resource: string }; +} => ({ + type: CRUD_SET_FILTER, + payload: { field, value }, + meta: { resource }, +}); diff --git a/packages/ra-core/src/actions/formActions.js b/packages/ra-core/src/actions/formActions.ts similarity index 51% rename from packages/ra-core/src/actions/formActions.js rename to packages/ra-core/src/actions/formActions.ts index 2a5f86b8902..845d5e03e0a 100644 --- a/packages/ra-core/src/actions/formActions.js +++ b/packages/ra-core/src/actions/formActions.ts @@ -2,16 +2,24 @@ export const INITIALIZE_FORM = 'RA/INITIALIZE_FORM'; export const RESET_FORM = 'RA/RESET_FORM'; export const BEFORE_LOCATION_CHANGE = 'RA/BEFORE_LOCATION_CHANGE'; -export const initializeForm = initialValues => ({ +export const initializeForm = ( + initialValues: any +): { type: string; payload: any } => ({ type: INITIALIZE_FORM, payload: initialValues, }); -export const resetForm = () => ({ +export const resetForm = (): { type: string } => ({ type: RESET_FORM, }); -export const beforeLocationChange = ({ payload, meta }) => ({ +export const beforeLocationChange = ({ + payload, + meta, +}: { + payload: any; + meta: any; +}): { type: string; payload: any; meta: any } => ({ type: BEFORE_LOCATION_CHANGE, payload, meta, diff --git a/packages/ra-core/src/actions/index.js b/packages/ra-core/src/actions/index.ts similarity index 100% rename from packages/ra-core/src/actions/index.js rename to packages/ra-core/src/actions/index.ts diff --git a/packages/ra-core/src/actions/listActions.js b/packages/ra-core/src/actions/listActions.ts similarity index 51% rename from packages/ra-core/src/actions/listActions.js rename to packages/ra-core/src/actions/listActions.ts index 475d5c8e27b..3d1522ff8c9 100644 --- a/packages/ra-core/src/actions/listActions.js +++ b/packages/ra-core/src/actions/listActions.ts @@ -2,19 +2,28 @@ export const CRUD_CHANGE_LIST_PARAMS = 'RA/CRUD_CHANGE_LIST_PARAMS'; export const SET_LIST_SELECTED_IDS = 'RA/SET_LIST_SELECTED_IDS'; export const TOGGLE_LIST_ITEM = 'RA/TOGGLE_LIST_ITEM'; -export const changeListParams = (resource, params) => ({ +export const changeListParams = ( + resource: string, + params +): { type: string; payload: any; meta: { resource: string } } => ({ type: CRUD_CHANGE_LIST_PARAMS, payload: params, meta: { resource }, }); -export const setListSelectedIds = (resource, ids) => ({ +export const setListSelectedIds = ( + resource: string, + ids: [] +): { type: string; payload: []; meta: { resource: string } } => ({ type: SET_LIST_SELECTED_IDS, payload: ids, meta: { resource }, }); -export const toggleListItem = (resource, id) => ({ +export const toggleListItem = ( + resource: string, + id +): { type: string; payload: any; meta: { resource: string } } => ({ type: TOGGLE_LIST_ITEM, payload: id, meta: { resource }, From 166d67a27cbc39554855ccfdfba9ae19fd09a3af Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Fri, 9 Nov 2018 21:19:04 +0100 Subject: [PATCH 2/5] Add interfaces for actions --- .../ra-core/src/actions/accumulateActions.ts | 36 ++++++++------- packages/ra-core/src/actions/authActions.ts | 44 ++++++++++--------- packages/ra-core/src/actions/fetchActions.ts | 37 ++++++++++------ packages/ra-core/src/actions/filterActions.ts | 42 +++++++++++------- packages/ra-core/src/actions/formActions.ts | 30 +++++++++---- packages/ra-core/src/actions/listActions.ts | 32 +++++++++++--- 6 files changed, 138 insertions(+), 83 deletions(-) diff --git a/packages/ra-core/src/actions/accumulateActions.ts b/packages/ra-core/src/actions/accumulateActions.ts index 90aca6da751..1b583fb0e9f 100644 --- a/packages/ra-core/src/actions/accumulateActions.ts +++ b/packages/ra-core/src/actions/accumulateActions.ts @@ -2,19 +2,21 @@ import { crudGetMany, crudGetMatching } from './dataActions'; export const CRUD_GET_MANY_ACCUMULATE = 'RA/CRUD_GET_MANY_ACCUMULATE'; -export const crudGetManyAccumulate = ( - resource: string, - ids: [] -): { - type: string; - payload: { +export interface CrudGetManyAccumulateAction { + readonly type: typeof CRUD_GET_MANY_ACCUMULATE; + readonly payload: { resource: string; ids: []; }; - meta: { + readonly meta: { accumulate: any; }; -} => ({ +} + +export const crudGetManyAccumulate = ( + resource: string, + ids: [] +): CrudGetManyAccumulateAction => ({ type: CRUD_GET_MANY_ACCUMULATE, payload: { resource, ids }, meta: { accumulate: crudGetMany }, @@ -22,20 +24,22 @@ export const crudGetManyAccumulate = ( export const CRUD_GET_MATCHING_ACCUMULATE = 'RA/CRUD_GET_MATCHING_ACCUMULATE'; +export interface CrudGetMatchingAccumulateAction { + readonly type: typeof CRUD_GET_MATCHING_ACCUMULATE; + readonly meta: { + accumulate: () => any; + accumulateValues?: () => boolean; + accumulateKey?: string; + }; +} + export const crudGetMatchingAccumulate = ( reference: string, relatedTo: string, pagination: object, sort: object, filter: object -): { - type: string; - meta: { - accumulate: any; - accumulateValues: () => boolean; - accumulateKey: string; - }; -} => { +): CrudGetMatchingAccumulateAction => { const action = crudGetMatching( reference, relatedTo, diff --git a/packages/ra-core/src/actions/authActions.ts b/packages/ra-core/src/actions/authActions.ts index bae47c3f7a5..155666c067f 100644 --- a/packages/ra-core/src/actions/authActions.ts +++ b/packages/ra-core/src/actions/authActions.ts @@ -1,33 +1,37 @@ -export const USER_CHECK_SUCCESS = 'RA/USER_CHECK_SUCCESS'; export const USER_LOGIN = 'RA/USER_LOGIN'; export const USER_LOGIN_LOADING = 'RA/USER_LOGIN_LOADING'; export const USER_LOGIN_FAILURE = 'RA/USER_LOGIN_FAILURE'; export const USER_LOGIN_SUCCESS = 'RA/USER_LOGIN_SUCCESS'; +export interface UserLoginAction { + readonly type: typeof USER_LOGIN; + readonly payload: object; + readonly meta: { auth: boolean; pathName: string }; +} + export const userLogin = ( payload: object, pathName: string -): { - type: string; - payload: object; - meta: { auth: boolean; pathName: string }; -} => ({ +): UserLoginAction => ({ type: USER_LOGIN, payload, meta: { auth: true, pathName }, }); export const USER_CHECK = 'RA/USER_CHECK'; +export const USER_CHECK_SUCCESS = 'RA/USER_CHECK_SUCCESS'; + +export interface UserCheckAction { + readonly type: typeof USER_CHECK; + readonly payload: object; + readonly meta: { auth: boolean; pathName: string }; +} export const userCheck = ( payload: object, pathName: string, routeParams -): { - type: string; - payload: object; - meta: { auth: boolean; pathName: string }; -} => ({ +): UserCheckAction => ({ type: USER_CHECK, payload: { ...payload, @@ -38,6 +42,12 @@ export const userCheck = ( export const USER_LOGOUT = 'RA/USER_LOGOUT'; +export interface UserLogoutAction { + readonly type: typeof USER_LOGOUT; + readonly payload: { redirectTo?: string }; + readonly meta: { auth: boolean }; +} + /** * Action to trigger logout of the current user. The entire redux state will be cleared * thanks to the resettableAppReducer in Admin. @@ -45,16 +55,8 @@ export const USER_LOGOUT = 'RA/USER_LOGOUT'; * @param redirectTo Path to direct to after logout * @return {{type: string, payload: {redirectTo: string}, meta: {auth: boolean}}} */ -export const userLogout = ( - redirectTo: string -): { - type: string; - payload: { redirectTo: string }; - meta: { auth: boolean }; -} => ({ +export const userLogout = (redirectTo?: string): UserLogoutAction => ({ type: USER_LOGOUT, - payload: { - redirectTo, - }, + payload: { redirectTo }, meta: { auth: true }, }); diff --git a/packages/ra-core/src/actions/fetchActions.ts b/packages/ra-core/src/actions/fetchActions.ts index bcaddac5051..e22cb93c8b9 100644 --- a/packages/ra-core/src/actions/fetchActions.ts +++ b/packages/ra-core/src/actions/fetchActions.ts @@ -1,20 +1,31 @@ export const FETCH_START = 'RA/FETCH_START'; + +export interface FetchStartAction { + readonly type: typeof FETCH_START; +} + +export const fetchStart = (): FetchStartAction => ({ type: FETCH_START }); + export const FETCH_END = 'RA/FETCH_END'; + +export interface FetchEndAction { + readonly type: typeof FETCH_END; +} + +export const fetchEnd = (): FetchEndAction => ({ type: FETCH_END }); + export const FETCH_ERROR = 'RA/FETCH_ERROR'; -export const FETCH_CANCEL = 'RA/FETCH_CANCEL'; -export const fetchStart = (): { type: string } => ({ - type: FETCH_START, -}); +export interface FetchErrorAction { + readonly type: typeof FETCH_ERROR; +} -export const fetchEnd = (): { type: string } => ({ - type: FETCH_END, -}); +export const fetchError = (): FetchErrorAction => ({ type: FETCH_ERROR }); + +export const FETCH_CANCEL = 'RA/FETCH_CANCEL'; -export const fetchError = (): { type: string } => ({ - type: FETCH_ERROR, -}); +export interface FetchCancelAction { + readonly type: typeof FETCH_CANCEL; +} -export const fetchCancel = (): { type: string } => ({ - type: FETCH_CANCEL, -}); +export const fetchCancel = (): FetchCancelAction => ({ type: FETCH_CANCEL }); diff --git a/packages/ra-core/src/actions/filterActions.ts b/packages/ra-core/src/actions/filterActions.ts index db36ae940a2..802b3529781 100644 --- a/packages/ra-core/src/actions/filterActions.ts +++ b/packages/ra-core/src/actions/filterActions.ts @@ -1,42 +1,50 @@ export const CRUD_SHOW_FILTER = 'RA/CRUD_SHOW_FILTER'; -export const CRUD_HIDE_FILTER = 'RA/CRUD_HIDE_FILTER'; -export const CRUD_SET_FILTER = 'RA/CRUD_SET_FILTER'; + +export interface ShowFilterAction { + readonly type: typeof CRUD_SHOW_FILTER; + readonly payload: { field: string }; + readonly meta: { resource: string }; +} export const showFilter = ( resource: string, field: string -): { - type: string; - payload: { field: string }; - meta: { resource: string }; -} => ({ +): ShowFilterAction => ({ type: CRUD_SHOW_FILTER, payload: { field }, meta: { resource }, }); +export const CRUD_HIDE_FILTER = 'RA/CRUD_HIDE_FILTER'; + +export interface HideFilterAction { + readonly type: typeof CRUD_HIDE_FILTER; + readonly payload: { field: string }; + readonly meta: { resource: string }; +} + export const hideFilter = ( resource: string, field: string -): { - type: string; - payload: { field: string }; - meta: { resource: string }; -} => ({ +): HideFilterAction => ({ type: CRUD_HIDE_FILTER, payload: { field }, meta: { resource }, }); +export const CRUD_SET_FILTER = 'RA/CRUD_SET_FILTER'; + +export interface SetFilterAction { + readonly type: typeof CRUD_SET_FILTER; + readonly payload: { field: string; value: any }; + readonly meta: { resource: string }; +} + export const setFilter = ( resource: string, field: string, value: any -): { - type: string; - payload: { field: string; value: any }; - meta: { resource: string }; -} => ({ +): SetFilterAction => ({ type: CRUD_SET_FILTER, payload: { field, value }, meta: { resource }, diff --git a/packages/ra-core/src/actions/formActions.ts b/packages/ra-core/src/actions/formActions.ts index 845d5e03e0a..ba133ba9673 100644 --- a/packages/ra-core/src/actions/formActions.ts +++ b/packages/ra-core/src/actions/formActions.ts @@ -1,25 +1,37 @@ export const INITIALIZE_FORM = 'RA/INITIALIZE_FORM'; -export const RESET_FORM = 'RA/RESET_FORM'; -export const BEFORE_LOCATION_CHANGE = 'RA/BEFORE_LOCATION_CHANGE'; -export const initializeForm = ( - initialValues: any -): { type: string; payload: any } => ({ +export interface InitializeFormAction { + readonly type: typeof INITIALIZE_FORM; + readonly payload: any; +} + +export const initializeForm = (initialValues: any): InitializeFormAction => ({ type: INITIALIZE_FORM, payload: initialValues, }); -export const resetForm = (): { type: string } => ({ - type: RESET_FORM, -}); +export const RESET_FORM = 'RA/RESET_FORM'; + +export interface ResetFormAction { + readonly type: typeof RESET_FORM; +} + +export const resetForm = (): ResetFormAction => ({ type: RESET_FORM }); + +export const BEFORE_LOCATION_CHANGE = 'RA/BEFORE_LOCATION_CHANGE'; +export interface BeforeLocationChangeAction { + readonly type: typeof BEFORE_LOCATION_CHANGE; + readonly payload: any; + readonly meta: any; +} export const beforeLocationChange = ({ payload, meta, }: { payload: any; meta: any; -}): { type: string; payload: any; meta: any } => ({ +}): BeforeLocationChangeAction => ({ type: BEFORE_LOCATION_CHANGE, payload, meta, diff --git a/packages/ra-core/src/actions/listActions.ts b/packages/ra-core/src/actions/listActions.ts index 3d1522ff8c9..71abd0a2824 100644 --- a/packages/ra-core/src/actions/listActions.ts +++ b/packages/ra-core/src/actions/listActions.ts @@ -1,29 +1,47 @@ export const CRUD_CHANGE_LIST_PARAMS = 'RA/CRUD_CHANGE_LIST_PARAMS'; -export const SET_LIST_SELECTED_IDS = 'RA/SET_LIST_SELECTED_IDS'; -export const TOGGLE_LIST_ITEM = 'RA/TOGGLE_LIST_ITEM'; +export interface ChangeListParamsAction { + readonly type: typeof CRUD_CHANGE_LIST_PARAMS; + readonly payload: any; + readonly meta: { resource: string }; +} export const changeListParams = ( resource: string, - params -): { type: string; payload: any; meta: { resource: string } } => ({ + params: any +): ChangeListParamsAction => ({ type: CRUD_CHANGE_LIST_PARAMS, payload: params, meta: { resource }, }); +export const SET_LIST_SELECTED_IDS = 'RA/SET_LIST_SELECTED_IDS'; + +export interface SetListLelectedIdsAction { + readonly type: typeof SET_LIST_SELECTED_IDS; + readonly payload: []; + readonly meta: { resource: string }; +} export const setListSelectedIds = ( resource: string, ids: [] -): { type: string; payload: []; meta: { resource: string } } => ({ +): SetListLelectedIdsAction => ({ type: SET_LIST_SELECTED_IDS, payload: ids, meta: { resource }, }); +export const TOGGLE_LIST_ITEM = 'RA/TOGGLE_LIST_ITEM'; + +export interface ToggleListItemAction { + readonly type: typeof TOGGLE_LIST_ITEM; + readonly payload: any; + readonly meta: { resource: string }; +} + export const toggleListItem = ( resource: string, - id -): { type: string; payload: any; meta: { resource: string } } => ({ + id: any +): ToggleListItemAction => ({ type: TOGGLE_LIST_ITEM, payload: id, meta: { resource }, From 9042f4b4b8bc6e78c331f0017eeeb467c0f8dd75 Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Fri, 9 Nov 2018 22:05:03 +0100 Subject: [PATCH 3/5] Add more types to actions --- packages/ra-core/src/actions/localeActions.js | 24 --------- packages/ra-core/src/actions/localeActions.ts | 52 +++++++++++++++++++ .../src/actions/notificationActions.js | 35 ------------- .../src/actions/notificationActions.ts | 51 ++++++++++++++++++ .../ra-core/src/actions/resourcesActions.js | 12 ----- .../ra-core/src/actions/resourcesActions.ts | 37 +++++++++++++ packages/ra-core/src/actions/uiActions.js | 18 ------- packages/ra-core/src/actions/uiActions.ts | 33 ++++++++++++ packages/ra-core/src/actions/undoActions.js | 25 --------- packages/ra-core/src/actions/undoActions.ts | 51 ++++++++++++++++++ 10 files changed, 224 insertions(+), 114 deletions(-) delete mode 100644 packages/ra-core/src/actions/localeActions.js create mode 100644 packages/ra-core/src/actions/localeActions.ts delete mode 100644 packages/ra-core/src/actions/notificationActions.js create mode 100644 packages/ra-core/src/actions/notificationActions.ts delete mode 100644 packages/ra-core/src/actions/resourcesActions.js create mode 100644 packages/ra-core/src/actions/resourcesActions.ts delete mode 100644 packages/ra-core/src/actions/uiActions.js create mode 100644 packages/ra-core/src/actions/uiActions.ts delete mode 100644 packages/ra-core/src/actions/undoActions.js create mode 100644 packages/ra-core/src/actions/undoActions.ts diff --git a/packages/ra-core/src/actions/localeActions.js b/packages/ra-core/src/actions/localeActions.js deleted file mode 100644 index aa3a0041e04..00000000000 --- a/packages/ra-core/src/actions/localeActions.js +++ /dev/null @@ -1,24 +0,0 @@ -export const CHANGE_LOCALE = 'RA/CHANGE_LOCALE'; -export const CHANGE_LOCALE_SUCCESS = 'RA/CHANGE_LOCALE_SUCCESS'; -export const CHANGE_LOCALE_FAILURE = 'RA/CHANGE_LOCALE_FAILURE'; - -export const changeLocale = locale => ({ - type: CHANGE_LOCALE, - payload: locale, -}); - -export const changeLocaleSuccess = (locale, messages) => ({ - type: CHANGE_LOCALE_SUCCESS, - payload: { - locale, - messages, - }, -}); - -export const changeLocaleFailure = (locale, error) => ({ - type: CHANGE_LOCALE_FAILURE, - error, - payload: { - locale, - }, -}); diff --git a/packages/ra-core/src/actions/localeActions.ts b/packages/ra-core/src/actions/localeActions.ts new file mode 100644 index 00000000000..ac93927e4cc --- /dev/null +++ b/packages/ra-core/src/actions/localeActions.ts @@ -0,0 +1,52 @@ +export const CHANGE_LOCALE = 'RA/CHANGE_LOCALE'; + +export interface ChangeLocaleAction { + readonly type: typeof CHANGE_LOCALE; + readonly payload: string; +} + +export const changeLocale = (locale: string): ChangeLocaleAction => ({ + type: CHANGE_LOCALE, + payload: locale, +}); + +export const CHANGE_LOCALE_SUCCESS = 'RA/CHANGE_LOCALE_SUCCESS'; + +export interface ChangeLocaleSuccessAction { + readonly type: typeof CHANGE_LOCALE_SUCCESS; + readonly payload: { + locale: string; + messages: any; + }; +} + +export const changeLocaleSuccess = ( + locale: string, + messages: any +): ChangeLocaleSuccessAction => ({ + type: CHANGE_LOCALE_SUCCESS, + payload: { + locale, + messages, + }, +}); + +export const CHANGE_LOCALE_FAILURE = 'RA/CHANGE_LOCALE_FAILURE'; + +export interface ChangeLocaleFailureAction { + readonly type: typeof CHANGE_LOCALE_FAILURE; + readonly error: any; + readonly payload: { + locale: string; + }; +} +export const changeLocaleFailure = ( + locale: string, + error: any +): ChangeLocaleFailureAction => ({ + type: CHANGE_LOCALE_FAILURE, + error, + payload: { + locale, + }, +}); diff --git a/packages/ra-core/src/actions/notificationActions.js b/packages/ra-core/src/actions/notificationActions.js deleted file mode 100644 index 6779b48e9b1..00000000000 --- a/packages/ra-core/src/actions/notificationActions.js +++ /dev/null @@ -1,35 +0,0 @@ -export const SHOW_NOTIFICATION = 'RA/SHOW_NOTIFICATION'; - -/** - * @typedef {Object} notificationOptions - * @param {number} [notificationOptions.autoHideDuration=4000] - The type of the notification - * @param {Object} [notificationOptions.messageArgs] - Arguments used to translate the message - */ - -/** - * Shows a snackbar/toast notification on the screen - * @param {string} message - A translatable label or text to display on notification - * @param {string} [type=info] - The type of the notification - * @param {notificationOptions} [notificationOptions] - Specify additional parameters of notification - * @see {@link https://material-ui.com/api/snackbar/|Material ui snackbar component} - * @see {@link https://material.io/guidelines/components/snackbars-toasts.html|Material ui reference document on snackbar} - * - */ -export const showNotification = ( - message, - type = 'info', - notificationOptions -) => ({ - type: SHOW_NOTIFICATION, - payload: { - ...notificationOptions, - type, - message, - }, -}); - -export const HIDE_NOTIFICATION = 'RA/HIDE_NOTIFICATION'; - -export const hideNotification = () => ({ - type: HIDE_NOTIFICATION, -}); diff --git a/packages/ra-core/src/actions/notificationActions.ts b/packages/ra-core/src/actions/notificationActions.ts new file mode 100644 index 00000000000..8becc68a56d --- /dev/null +++ b/packages/ra-core/src/actions/notificationActions.ts @@ -0,0 +1,51 @@ +export const SHOW_NOTIFICATION = 'RA/SHOW_NOTIFICATION'; + +interface NotificationOptions { + // The type of the notification + autoHideDuration?: number; + // Arguments used to translate the message + messageArgs?: any; +} + +type MessageType = 'info' | 'warning' | 'error'; + +export interface ShowNotificationAction { + readonly type: typeof SHOW_NOTIFICATION; + readonly payload: { + message: string; + type: MessageType; + notificationOptions?: NotificationOptions; + }; +} + +/** + * Shows a snackbar/toast notification on the screen + * + * @see {@link https://material-ui.com/api/snackbar/|Material ui snackbar component} + * @see {@link https://material.io/guidelines/components/snackbars-toasts.html|Material ui reference document on snackbar} + */ +export const showNotification = ( + // A translatable label or text to display on notification + message: string, + // The type of the notification + type: MessageType = 'info', + // Specify additional parameters of notification + notificationOptions?: NotificationOptions +): ShowNotificationAction => ({ + type: SHOW_NOTIFICATION, + payload: { + ...notificationOptions, + type, + message, + }, +}); + +export const HIDE_NOTIFICATION = 'RA/HIDE_NOTIFICATION'; + +export interface HideNotificationAction { + readonly type: typeof HIDE_NOTIFICATION; +} + +export const hideNotification = (): HideNotificationAction => ({ + type: HIDE_NOTIFICATION, +}); diff --git a/packages/ra-core/src/actions/resourcesActions.js b/packages/ra-core/src/actions/resourcesActions.js deleted file mode 100644 index f45cac0be22..00000000000 --- a/packages/ra-core/src/actions/resourcesActions.js +++ /dev/null @@ -1,12 +0,0 @@ -export const REGISTER_RESOURCE = 'RA/REGISTER_RESOURCE'; -export const UNREGISTER_RESOURCE = 'RA/UNREGISTER_RESOURCE'; - -export const registerResource = resource => ({ - type: REGISTER_RESOURCE, - payload: resource, -}); - -export const unregisterResource = resourceName => ({ - type: UNREGISTER_RESOURCE, - payload: resourceName, -}); diff --git a/packages/ra-core/src/actions/resourcesActions.ts b/packages/ra-core/src/actions/resourcesActions.ts new file mode 100644 index 00000000000..bbcd17c6676 --- /dev/null +++ b/packages/ra-core/src/actions/resourcesActions.ts @@ -0,0 +1,37 @@ +export const REGISTER_RESOURCE = 'RA/REGISTER_RESOURCE'; + +export interface ResourceDefinition { + readonly name: string; + readonly options?: any; + readonly hasList?: boolean; + readonly hasEdit?: boolean; + readonly hasShow?: boolean; + readonly hasCreate?: boolean; + readonly icon?: any; +} + +export interface RegisterResourceAction { + readonly type: typeof REGISTER_RESOURCE; + readonly payload: ResourceDefinition; +} + +export const registerResource = ( + resource: ResourceDefinition +): RegisterResourceAction => ({ + type: REGISTER_RESOURCE, + payload: resource, +}); + +export const UNREGISTER_RESOURCE = 'RA/UNREGISTER_RESOURCE'; + +export interface UnregisterResourceAction { + readonly type: typeof UNREGISTER_RESOURCE; + readonly payload: string; +} + +export const unregisterResource = ( + resourceName: string +): UnregisterResourceAction => ({ + type: UNREGISTER_RESOURCE, + payload: resourceName, +}); diff --git a/packages/ra-core/src/actions/uiActions.js b/packages/ra-core/src/actions/uiActions.js deleted file mode 100644 index f4cb0b32285..00000000000 --- a/packages/ra-core/src/actions/uiActions.js +++ /dev/null @@ -1,18 +0,0 @@ -export const TOGGLE_SIDEBAR = 'RA/TOGGLE_SIDEBAR'; - -export const toggleSidebar = () => ({ - type: TOGGLE_SIDEBAR, -}); - -export const SET_SIDEBAR_VISIBILITY = 'RA/SET_SIDEBAR_VISIBILITY'; - -export const setSidebarVisibility = isOpen => ({ - type: SET_SIDEBAR_VISIBILITY, - payload: isOpen, -}); - -export const REFRESH_VIEW = 'RA/REFRESH_VIEW'; - -export const refreshView = () => ({ - type: REFRESH_VIEW, -}); diff --git a/packages/ra-core/src/actions/uiActions.ts b/packages/ra-core/src/actions/uiActions.ts new file mode 100644 index 00000000000..204d826cbde --- /dev/null +++ b/packages/ra-core/src/actions/uiActions.ts @@ -0,0 +1,33 @@ +export const TOGGLE_SIDEBAR = 'RA/TOGGLE_SIDEBAR'; + +export interface ToggleSidebarAction { + readonly type: typeof TOGGLE_SIDEBAR; +} + +export const toggleSidebar = (): ToggleSidebarAction => ({ + type: TOGGLE_SIDEBAR, +}); + +export const SET_SIDEBAR_VISIBILITY = 'RA/SET_SIDEBAR_VISIBILITY'; + +export interface SetSidebarVisibilityAction { + readonly type: typeof SET_SIDEBAR_VISIBILITY; + readonly payload: boolean; +} + +export const setSidebarVisibility = ( + isOpen: boolean +): SetSidebarVisibilityAction => ({ + type: SET_SIDEBAR_VISIBILITY, + payload: isOpen, +}); + +export const REFRESH_VIEW = 'RA/REFRESH_VIEW'; + +export interface RefreshViewAction { + readonly type: typeof REFRESH_VIEW; +} + +export const refreshView = (): RefreshViewAction => ({ + type: REFRESH_VIEW, +}); diff --git a/packages/ra-core/src/actions/undoActions.js b/packages/ra-core/src/actions/undoActions.js deleted file mode 100644 index 032b6fb3161..00000000000 --- a/packages/ra-core/src/actions/undoActions.js +++ /dev/null @@ -1,25 +0,0 @@ -export const UNDOABLE = 'RA/UNDOABLE'; -export const UNDO = 'RA/UNDO'; -export const COMPLETE = 'RA/COMPLETE'; -export const START_OPTIMISTIC_MODE = 'RA/START_OPTIMISTIC_MODE'; -export const STOP_OPTIMISTIC_MODE = 'RA/STOP_OPTIMISTIC_MODE'; - -export const startUndoable = action => ({ - type: UNDOABLE, - payload: { action }, -}); - -export const undo = () => ({ - type: UNDO, -}); -export const complete = () => ({ - type: COMPLETE, -}); - -export const startOptimisticMode = () => ({ - type: START_OPTIMISTIC_MODE, -}); - -export const stopOptimisticMode = () => ({ - type: STOP_OPTIMISTIC_MODE, -}); diff --git a/packages/ra-core/src/actions/undoActions.ts b/packages/ra-core/src/actions/undoActions.ts new file mode 100644 index 00000000000..fd6da504c2e --- /dev/null +++ b/packages/ra-core/src/actions/undoActions.ts @@ -0,0 +1,51 @@ +export const UNDOABLE = 'RA/UNDOABLE'; + +export interface StartUndoableAction { + readonly type: typeof UNDOABLE; + readonly payload: any; +} + +export const startUndoable = (action: any): StartUndoableAction => ({ + type: UNDOABLE, + payload: { action }, +}); + +export const UNDO = 'RA/UNDO'; + +export interface UndoAction { + readonly type: typeof UNDO; +} + +export const undo = (): UndoAction => ({ + type: UNDO, +}); + +export const COMPLETE = 'RA/COMPLETE'; + +export interface CompleteAction { + readonly type: typeof COMPLETE; +} + +export const complete = (): CompleteAction => ({ + type: COMPLETE, +}); + +export const START_OPTIMISTIC_MODE = 'RA/START_OPTIMISTIC_MODE'; + +export interface StartOptimisticModeAction { + readonly type: typeof START_OPTIMISTIC_MODE; +} + +export const startOptimisticMode = (): StartOptimisticModeAction => ({ + type: START_OPTIMISTIC_MODE, +}); + +export const STOP_OPTIMISTIC_MODE = 'RA/STOP_OPTIMISTIC_MODE'; + +export interface StopOptimisticModeAction { + readonly type: typeof STOP_OPTIMISTIC_MODE; +} + +export const stopOptimisticMode = (): StopOptimisticModeAction => ({ + type: STOP_OPTIMISTIC_MODE, +}); From e1cb1a30d3dad22f46549ead791240cb3f06161f Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Fri, 9 Nov 2018 22:51:34 +0100 Subject: [PATCH 4/5] Add types to root reducers --- packages/ra-core/src/reducer/i18n/loading.js | 17 ---------- packages/ra-core/src/reducer/i18n/loading.ts | 34 +++++++++++++++++++ packages/ra-core/src/reducer/i18n/locale.js | 14 -------- packages/ra-core/src/reducer/i18n/locale.ts | 22 ++++++++++++ packages/ra-core/src/reducer/i18n/messages.js | 12 ------- packages/ra-core/src/reducer/i18n/messages.ts | 22 ++++++++++++ 6 files changed, 78 insertions(+), 43 deletions(-) delete mode 100644 packages/ra-core/src/reducer/i18n/loading.js create mode 100644 packages/ra-core/src/reducer/i18n/loading.ts delete mode 100644 packages/ra-core/src/reducer/i18n/locale.js create mode 100644 packages/ra-core/src/reducer/i18n/locale.ts delete mode 100644 packages/ra-core/src/reducer/i18n/messages.js create mode 100644 packages/ra-core/src/reducer/i18n/messages.ts diff --git a/packages/ra-core/src/reducer/i18n/loading.js b/packages/ra-core/src/reducer/i18n/loading.js deleted file mode 100644 index 3d625d0ec38..00000000000 --- a/packages/ra-core/src/reducer/i18n/loading.js +++ /dev/null @@ -1,17 +0,0 @@ -import { - CHANGE_LOCALE, - CHANGE_LOCALE_SUCCESS, - CHANGE_LOCALE_FAILURE, -} from '../../actions/localeActions'; - -export default (loading = false, action) => { - switch (action.type) { - case CHANGE_LOCALE: - return true; - case CHANGE_LOCALE_SUCCESS: - case CHANGE_LOCALE_FAILURE: - return false; - default: - return loading; - } -}; diff --git a/packages/ra-core/src/reducer/i18n/loading.ts b/packages/ra-core/src/reducer/i18n/loading.ts new file mode 100644 index 00000000000..4cc858ad260 --- /dev/null +++ b/packages/ra-core/src/reducer/i18n/loading.ts @@ -0,0 +1,34 @@ +import { Reducer } from 'redux'; +import { + CHANGE_LOCALE, + CHANGE_LOCALE_SUCCESS, + CHANGE_LOCALE_FAILURE, + ChangeLocaleAction, + ChangeLocaleSuccessAction, + ChangeLocaleFailureAction, +} from '../../actions/localeActions'; + +type ActionTypes = + | ChangeLocaleAction + | ChangeLocaleSuccessAction + | ChangeLocaleFailureAction + | { type: 'OTHER_ACTION' }; + +type State = boolean; + +const loadingReducer: Reducer = ( + loading = false, + action: ActionTypes +) => { + switch (action.type) { + case CHANGE_LOCALE: + return true; + case CHANGE_LOCALE_SUCCESS: + case CHANGE_LOCALE_FAILURE: + return false; + default: + return loading; + } +}; + +export default loadingReducer; diff --git a/packages/ra-core/src/reducer/i18n/locale.js b/packages/ra-core/src/reducer/i18n/locale.js deleted file mode 100644 index f2c3d3a44ba..00000000000 --- a/packages/ra-core/src/reducer/i18n/locale.js +++ /dev/null @@ -1,14 +0,0 @@ -import { DEFAULT_LOCALE } from '../../i18n/index'; -import { CHANGE_LOCALE_SUCCESS } from '../../actions/localeActions'; - -export default (initialLocale = DEFAULT_LOCALE) => ( - previousLocale = initialLocale, - { type, payload } -) => { - switch (type) { - case CHANGE_LOCALE_SUCCESS: - return payload.locale; - default: - return previousLocale; - } -}; diff --git a/packages/ra-core/src/reducer/i18n/locale.ts b/packages/ra-core/src/reducer/i18n/locale.ts new file mode 100644 index 00000000000..9a297f4a2c3 --- /dev/null +++ b/packages/ra-core/src/reducer/i18n/locale.ts @@ -0,0 +1,22 @@ +import { Reducer } from 'redux'; +import { DEFAULT_LOCALE } from '../../i18n/index'; +import { + CHANGE_LOCALE_SUCCESS, + ChangeLocaleSuccessAction, +} from '../../actions/localeActions'; + +type ActionTypes = ChangeLocaleSuccessAction | { type: 'OTHER_ACTION' }; + +type State = string; + +export default (initialLocale: string = DEFAULT_LOCALE): Reducer => ( + previousLocale = initialLocale, + action: ActionTypes +) => { + switch (action.type) { + case CHANGE_LOCALE_SUCCESS: + return action.payload.locale; + default: + return previousLocale; + } +}; diff --git a/packages/ra-core/src/reducer/i18n/messages.js b/packages/ra-core/src/reducer/i18n/messages.js deleted file mode 100644 index ada94e6ead3..00000000000 --- a/packages/ra-core/src/reducer/i18n/messages.js +++ /dev/null @@ -1,12 +0,0 @@ -import { CHANGE_LOCALE_SUCCESS } from '../../actions/index'; - -export default defaultMessages => { - return (previousState = defaultMessages, { type, payload }) => { - switch (type) { - case CHANGE_LOCALE_SUCCESS: - return payload.messages; - default: - return previousState; - } - }; -}; diff --git a/packages/ra-core/src/reducer/i18n/messages.ts b/packages/ra-core/src/reducer/i18n/messages.ts new file mode 100644 index 00000000000..bd6732f4172 --- /dev/null +++ b/packages/ra-core/src/reducer/i18n/messages.ts @@ -0,0 +1,22 @@ +import { Reducer } from 'redux'; +import { + CHANGE_LOCALE_SUCCESS, + ChangeLocaleSuccessAction, +} from '../../actions/index'; + +type ActionTypes = ChangeLocaleSuccessAction | { type: 'OTHER_ACTION' }; + +type State = any; + +const messagesReducer: Reducer = defaultMessages => { + return (previousState = defaultMessages, action: ActionTypes) => { + switch (action.type) { + case CHANGE_LOCALE_SUCCESS: + return action.payload.messages; + default: + return previousState; + } + }; +}; + +export default messagesReducer; From 23d0155893f056f32a7ef5bd61202f12325a19f0 Mon Sep 17 00:00:00 2001 From: Francois Zaninotto Date: Fri, 9 Nov 2018 23:47:59 +0100 Subject: [PATCH 5/5] migrate more reducers --- .../src/actions/notificationActions.ts | 16 +++-- .../src/reducer/admin/notifications.js | 23 ------- ...ications.spec.js => notifications.spec.ts} | 18 ++++-- .../src/reducer/admin/notifications.ts | 39 +++++++++++ packages/ra-core/src/reducer/admin/ui.spec.js | 50 --------------- packages/ra-core/src/reducer/admin/ui.spec.ts | 64 +++++++++++++++++++ .../src/reducer/admin/{ui.js => ui.ts} | 34 ++++++++-- packages/ra-core/src/reducer/i18n/loading.ts | 4 +- .../i18n/{locale.spec.js => locale.spec.ts} | 2 +- 9 files changed, 156 insertions(+), 94 deletions(-) delete mode 100644 packages/ra-core/src/reducer/admin/notifications.js rename packages/ra-core/src/reducer/admin/{notifications.spec.js => notifications.spec.ts} (71%) create mode 100644 packages/ra-core/src/reducer/admin/notifications.ts delete mode 100644 packages/ra-core/src/reducer/admin/ui.spec.js create mode 100644 packages/ra-core/src/reducer/admin/ui.spec.ts rename packages/ra-core/src/reducer/admin/{ui.js => ui.ts} (51%) rename packages/ra-core/src/reducer/i18n/{locale.spec.js => locale.spec.ts} (92%) diff --git a/packages/ra-core/src/actions/notificationActions.ts b/packages/ra-core/src/actions/notificationActions.ts index 8becc68a56d..a5e8a5d94f2 100644 --- a/packages/ra-core/src/actions/notificationActions.ts +++ b/packages/ra-core/src/actions/notificationActions.ts @@ -1,5 +1,7 @@ export const SHOW_NOTIFICATION = 'RA/SHOW_NOTIFICATION'; +export type NotificationType = 'info' | 'warning' | 'error'; + interface NotificationOptions { // The type of the notification autoHideDuration?: number; @@ -7,15 +9,15 @@ interface NotificationOptions { messageArgs?: any; } -type MessageType = 'info' | 'warning' | 'error'; +export interface Notification { + readonly message: string; + readonly type: NotificationType; + readonly notificationOptions?: NotificationOptions; +} export interface ShowNotificationAction { readonly type: typeof SHOW_NOTIFICATION; - readonly payload: { - message: string; - type: MessageType; - notificationOptions?: NotificationOptions; - }; + readonly payload: Notification; } /** @@ -28,7 +30,7 @@ export const showNotification = ( // A translatable label or text to display on notification message: string, // The type of the notification - type: MessageType = 'info', + type: NotificationType = 'info', // Specify additional parameters of notification notificationOptions?: NotificationOptions ): ShowNotificationAction => ({ diff --git a/packages/ra-core/src/reducer/admin/notifications.js b/packages/ra-core/src/reducer/admin/notifications.js deleted file mode 100644 index c25fc9c8dbf..00000000000 --- a/packages/ra-core/src/reducer/admin/notifications.js +++ /dev/null @@ -1,23 +0,0 @@ -import { - SHOW_NOTIFICATION, - HIDE_NOTIFICATION, -} from '../../actions/notificationActions'; -import { UNDO } from '../../actions/undoActions'; - -export default (previousState = [], { type, payload }) => { - switch (type) { - case SHOW_NOTIFICATION: - return previousState.concat(payload); - case HIDE_NOTIFICATION: - case UNDO: - return previousState.slice(1); - default: - return previousState; - } -}; - -/** - * Returns the first available notification to show - * @param {Object} state - Redux state - */ -export const getNotification = state => state.admin.notifications[0]; diff --git a/packages/ra-core/src/reducer/admin/notifications.spec.js b/packages/ra-core/src/reducer/admin/notifications.spec.ts similarity index 71% rename from packages/ra-core/src/reducer/admin/notifications.spec.js rename to packages/ra-core/src/reducer/admin/notifications.spec.ts index fd865c7657e..9505e2d0c8f 100644 --- a/packages/ra-core/src/reducer/admin/notifications.spec.js +++ b/packages/ra-core/src/reducer/admin/notifications.spec.ts @@ -2,20 +2,21 @@ import assert from 'assert'; import { HIDE_NOTIFICATION, SHOW_NOTIFICATION, + NotificationType, } from '../../actions/notificationActions'; import reducer from './notifications'; describe('notifications reducer', () => { it('should return empty notification by default', () => { - assert.deepEqual([], reducer(undefined, {})); + assert.deepEqual([], reducer(undefined, { type: 'foo' })); }); it('should set autoHideDuration when passed in payload', () => { assert.deepEqual( - [{ text: 'test', type: 'info', autoHideDuration: 1337 }], + [{ message: 'test', type: 'info', autoHideDuration: 1337 }], reducer(undefined, { type: SHOW_NOTIFICATION, payload: { - text: 'test', + message: 'test', type: 'info', autoHideDuration: 1337, }, @@ -24,11 +25,11 @@ describe('notifications reducer', () => { }); it('should set text and type upon SHOW_NOTIFICATION', () => { assert.deepEqual( - [{ text: 'foo', type: 'warning' }], + [{ message: 'foo', type: 'warning' }], reducer(undefined, { type: SHOW_NOTIFICATION, payload: { - text: 'foo', + message: 'foo', type: 'warning', }, }) @@ -37,13 +38,16 @@ describe('notifications reducer', () => { it('should have no elements upon last HIDE_NOTIFICATION', () => { assert.deepEqual( [], - reducer([{ text: 'foo', type: 'warning' }], { + reducer([{ message: 'foo', type: 'warning' as NotificationType }], { type: HIDE_NOTIFICATION, }) ); }); it('should have one less notification upon HIDE_NOTIFICATION with multiple notifications', () => { - const notifications = [{ text: 'foo' }, { text: 'bar' }]; + const notifications = [ + { message: 'foo', type: 'info' as NotificationType }, + { message: 'bar', type: 'info' as NotificationType }, + ]; assert.equal( notifications.length - 1, reducer(notifications, { diff --git a/packages/ra-core/src/reducer/admin/notifications.ts b/packages/ra-core/src/reducer/admin/notifications.ts new file mode 100644 index 00000000000..011fbe406e1 --- /dev/null +++ b/packages/ra-core/src/reducer/admin/notifications.ts @@ -0,0 +1,39 @@ +import { Reducer } from 'redux'; +import { + SHOW_NOTIFICATION, + ShowNotificationAction, + HIDE_NOTIFICATION, + HideNotificationAction, + Notification, +} from '../../actions/notificationActions'; +import { UNDO, UndoAction } from '../../actions/undoActions'; + +type ActionTypes = + | ShowNotificationAction + | HideNotificationAction + | UndoAction + | { type: 'OTHER_TYPE' }; + +type State = Notification[]; + +const notificationsReducer: Reducer = ( + previousState = [], + action: ActionTypes +) => { + switch (action.type) { + case SHOW_NOTIFICATION: + return previousState.concat(action.payload); + case HIDE_NOTIFICATION: + case UNDO: + return previousState.slice(1); + default: + return previousState; + } +}; + +export default notificationsReducer; +/** + * Returns the first available notification to show + * @param {Object} state - Redux state + */ +export const getNotification = state => state.admin.notifications[0]; diff --git a/packages/ra-core/src/reducer/admin/ui.spec.js b/packages/ra-core/src/reducer/admin/ui.spec.js deleted file mode 100644 index 9794751f464..00000000000 --- a/packages/ra-core/src/reducer/admin/ui.spec.js +++ /dev/null @@ -1,50 +0,0 @@ -import assert from 'assert'; -import { - toggleSidebar, - setSidebarVisibility, - refreshView, -} from '../../actions/uiActions'; -import reducer from './ui'; - -describe('ui reducer', () => { - it('should return hidden sidebar by default', () => { - assert.deepEqual( - { optimistic: false, sidebarOpen: false, viewVersion: 0 }, - reducer(undefined, {}) - ); - }); - it('should toggle sidebar visibility upon TOGGLE_SIDEBAR', () => { - assert.deepEqual( - { sidebarOpen: false }, - reducer({ sidebarOpen: true }, toggleSidebar()) - ); - assert.deepEqual( - { sidebarOpen: true }, - reducer({ sidebarOpen: false }, toggleSidebar()) - ); - }); - it('should set sidebar visibility upon SET_SIDEBAR_VISIBILITY', () => { - assert.deepEqual( - { sidebarOpen: false }, - reducer({ sidebarOpen: true }, setSidebarVisibility(false)) - ); - assert.deepEqual( - { sidebarOpen: true }, - reducer({ sidebarOpen: true }, setSidebarVisibility(true)) - ); - assert.deepEqual( - { sidebarOpen: false }, - reducer({ sidebarOpen: false }, setSidebarVisibility(false)) - ); - assert.deepEqual( - { sidebarOpen: true }, - reducer({ sidebarOpen: false }, setSidebarVisibility(true)) - ); - }); - it('should increment the viewVersion upon REFRESH_VIEW', () => { - assert.deepEqual( - { optimistic: false, sidebarOpen: false, viewVersion: 1 }, - reducer(undefined, refreshView()) - ); - }); -}); diff --git a/packages/ra-core/src/reducer/admin/ui.spec.ts b/packages/ra-core/src/reducer/admin/ui.spec.ts new file mode 100644 index 00000000000..45b9e0a6512 --- /dev/null +++ b/packages/ra-core/src/reducer/admin/ui.spec.ts @@ -0,0 +1,64 @@ +import assert from 'assert'; +import { + toggleSidebar, + setSidebarVisibility, + refreshView, +} from '../../actions/uiActions'; +import reducer from './ui'; + +describe('ui reducer', () => { + const defaultState = { + sidebarOpen: false, + optimistic: false, + viewVersion: 0, + }; + it('should return hidden sidebar by default', () => { + assert.deepEqual(defaultState, reducer(undefined, { type: 'foo' })); + }); + it('should toggle sidebar visibility upon TOGGLE_SIDEBAR', () => { + assert.deepEqual( + { ...defaultState, sidebarOpen: false }, + reducer({ ...defaultState, sidebarOpen: true }, toggleSidebar()) + ); + assert.deepEqual( + { ...defaultState, sidebarOpen: true }, + reducer({ ...defaultState, sidebarOpen: false }, toggleSidebar()) + ); + }); + it('should set sidebar visibility upon SET_SIDEBAR_VISIBILITY', () => { + assert.deepEqual( + { ...defaultState, sidebarOpen: false }, + reducer( + { ...defaultState, sidebarOpen: true }, + setSidebarVisibility(false) + ) + ); + assert.deepEqual( + { ...defaultState, sidebarOpen: true }, + reducer( + { ...defaultState, sidebarOpen: true }, + setSidebarVisibility(true) + ) + ); + assert.deepEqual( + { ...defaultState, sidebarOpen: false }, + reducer( + { ...defaultState, sidebarOpen: false }, + setSidebarVisibility(false) + ) + ); + assert.deepEqual( + { ...defaultState, sidebarOpen: true }, + reducer( + { ...defaultState, sidebarOpen: false }, + setSidebarVisibility(true) + ) + ); + }); + it('should increment the viewVersion upon REFRESH_VIEW', () => { + assert.deepEqual( + { optimistic: false, sidebarOpen: false, viewVersion: 1 }, + reducer(undefined, refreshView()) + ); + }); +}); diff --git a/packages/ra-core/src/reducer/admin/ui.js b/packages/ra-core/src/reducer/admin/ui.ts similarity index 51% rename from packages/ra-core/src/reducer/admin/ui.js rename to packages/ra-core/src/reducer/admin/ui.ts index c2fa79fc6c2..3e59819bfe2 100644 --- a/packages/ra-core/src/reducer/admin/ui.js +++ b/packages/ra-core/src/reducer/admin/ui.ts @@ -1,26 +1,50 @@ +import { Reducer } from 'redux'; import { TOGGLE_SIDEBAR, + ToggleSidebarAction, SET_SIDEBAR_VISIBILITY, + SetSidebarVisibilityAction, REFRESH_VIEW, + RefreshViewAction, START_OPTIMISTIC_MODE, + StartOptimisticModeAction, STOP_OPTIMISTIC_MODE, + StopOptimisticModeAction, } from '../../actions'; +import { number } from '../../form'; -const defaultState = { +type ActionTypes = + | ToggleSidebarAction + | SetSidebarVisibilityAction + | RefreshViewAction + | StartOptimisticModeAction + | StopOptimisticModeAction + | { type: 'OTHER_ACTION' }; + +interface State { + readonly sidebarOpen: boolean; + readonly optimistic: boolean; + readonly viewVersion: number; +} + +const defaultState: State = { sidebarOpen: false, optimistic: false, viewVersion: 0, }; -export default (previousState = defaultState, { type, payload }) => { - switch (type) { +const uiReducer: Reducer = ( + previousState = defaultState, + action: ActionTypes +) => { + switch (action.type) { case TOGGLE_SIDEBAR: return { ...previousState, sidebarOpen: !previousState.sidebarOpen, }; case SET_SIDEBAR_VISIBILITY: - return { ...previousState, sidebarOpen: payload }; + return { ...previousState, sidebarOpen: action.payload }; case REFRESH_VIEW: return { ...previousState, @@ -34,3 +58,5 @@ export default (previousState = defaultState, { type, payload }) => { return previousState; } }; + +export default uiReducer; diff --git a/packages/ra-core/src/reducer/i18n/loading.ts b/packages/ra-core/src/reducer/i18n/loading.ts index 4cc858ad260..a0c98aea0cd 100644 --- a/packages/ra-core/src/reducer/i18n/loading.ts +++ b/packages/ra-core/src/reducer/i18n/loading.ts @@ -1,10 +1,10 @@ import { Reducer } from 'redux'; import { CHANGE_LOCALE, - CHANGE_LOCALE_SUCCESS, - CHANGE_LOCALE_FAILURE, ChangeLocaleAction, + CHANGE_LOCALE_SUCCESS, ChangeLocaleSuccessAction, + CHANGE_LOCALE_FAILURE, ChangeLocaleFailureAction, } from '../../actions/localeActions'; diff --git a/packages/ra-core/src/reducer/i18n/locale.spec.js b/packages/ra-core/src/reducer/i18n/locale.spec.ts similarity index 92% rename from packages/ra-core/src/reducer/i18n/locale.spec.js rename to packages/ra-core/src/reducer/i18n/locale.spec.ts index 155ae655b64..74a064e9f83 100644 --- a/packages/ra-core/src/reducer/i18n/locale.spec.js +++ b/packages/ra-core/src/reducer/i18n/locale.spec.ts @@ -9,7 +9,7 @@ import { describe('locale reducer', () => { it('should return DEFAULT_LOCALE by default', () => { - assert.equal(DEFAULT_LOCALE, reducer()(undefined, {})); + assert.equal(DEFAULT_LOCALE, reducer()(undefined, { type: 'foo' })); }); it('should change with CHANGE_LOCALE_SUCCESS action', () => { assert.equal(