diff --git a/cvat-ui/.eslintrc.js b/cvat-ui/.eslintrc.js index 22c0aa1a38e0..fcf75da5758d 100644 --- a/cvat-ui/.eslintrc.js +++ b/cvat-ui/.eslintrc.js @@ -34,6 +34,7 @@ module.exports = { 'jsx-quotes': ['error', 'prefer-single'], 'arrow-parens': ['error', 'always'], '@typescript-eslint/no-explicit-any': [0], + '@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }], 'no-restricted-syntax': [0, {'selector': 'ForOfStatement'}], 'no-plusplus': [0], 'lines-between-class-members': 0, diff --git a/cvat-ui/src/actions/about-actions.ts b/cvat-ui/src/actions/about-actions.ts index a7e69f58e17a..979c5ae8d178 100644 --- a/cvat-ui/src/actions/about-actions.ts +++ b/cvat-ui/src/actions/about-actions.ts @@ -1,5 +1,5 @@ +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import getCore from 'cvat-core'; -import { ActionUnion, createAction, ThunkAction } from '../utils/redux'; const core = getCore(); @@ -17,7 +17,7 @@ const aboutActions = { export type AboutActions = ActionUnion; -export const getAboutAsync = (): ThunkAction => async (dispatch) => { +export const getAboutAsync = (): ThunkAction => async (dispatch): Promise => { dispatch(aboutActions.getAbout()); try { diff --git a/cvat-ui/src/actions/auth-actions.ts b/cvat-ui/src/actions/auth-actions.ts index 4071f617949f..ca89720382ec 100644 --- a/cvat-ui/src/actions/auth-actions.ts +++ b/cvat-ui/src/actions/auth-actions.ts @@ -1,5 +1,5 @@ +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import getCore from 'cvat-core'; -import { ActionUnion, createAction, ThunkAction } from '../utils/redux'; const cvat = getCore(); diff --git a/cvat-ui/src/actions/formats-actions.ts b/cvat-ui/src/actions/formats-actions.ts index d34510c87d6c..3668e0a173d5 100644 --- a/cvat-ui/src/actions/formats-actions.ts +++ b/cvat-ui/src/actions/formats-actions.ts @@ -1,6 +1,4 @@ -import { AnyAction, Dispatch, ActionCreator } from 'redux'; -import { ThunkAction } from 'redux-thunk'; - +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import getCore from 'cvat-core'; const cvat = getCore(); @@ -11,48 +9,36 @@ export enum FormatsActionTypes { GET_FORMATS_FAILED = 'GET_FORMATS_FAILED', } -function getFormats(): AnyAction { - return { - type: FormatsActionTypes.GET_FORMATS, - payload: {}, - }; -} - -function getFormatsSuccess( - annotationFormats: any[], - datasetFormats: any[], -): AnyAction { - return { - type: FormatsActionTypes.GET_FORMATS_SUCCESS, - payload: { +const formatsActions = { + getFormats: () => createAction(FormatsActionTypes.GET_FORMATS), + getFormatsSuccess: (annotationFormats: any[], datasetFormats: any[]) => ( + createAction(FormatsActionTypes.GET_FORMATS_SUCCESS, { annotationFormats, datasetFormats, - }, - }; -} - -function getFormatsFailed(error: any): AnyAction { - return { - type: FormatsActionTypes.GET_FORMATS_FAILED, - payload: { - error, - }, - }; -} - -export function getFormatsAsync(): ThunkAction, {}, {}, AnyAction> { - return async (dispatch: ActionCreator): Promise => { - dispatch(getFormats()); + }) + ), + getFormatsFailed: (error: any) => ( + createAction(FormatsActionTypes.GET_FORMATS_FAILED, { error }) + ), +}; + +export type FormatsActions = ActionUnion; + +export function getFormatsAsync(): ThunkAction { + return async (dispatch): Promise => { + dispatch(formatsActions.getFormats()); let annotationFormats = null; let datasetFormats = null; + try { annotationFormats = await cvat.server.formats(); datasetFormats = await cvat.server.datasetFormats(); + + dispatch( + formatsActions.getFormatsSuccess(annotationFormats, datasetFormats), + ); } catch (error) { - dispatch(getFormatsFailed(error)); - return; + dispatch(formatsActions.getFormatsFailed(error)); } - - dispatch(getFormatsSuccess(annotationFormats, datasetFormats)); }; } diff --git a/cvat-ui/src/actions/plugins-actions.ts b/cvat-ui/src/actions/plugins-actions.ts index a102db714d72..fe67d3be4b97 100644 --- a/cvat-ui/src/actions/plugins-actions.ts +++ b/cvat-ui/src/actions/plugins-actions.ts @@ -1,5 +1,4 @@ -import { AnyAction, Dispatch, ActionCreator } from 'redux'; -import { ThunkAction } from 'redux-thunk'; +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import { SupportedPlugins } from 'reducers/interfaces'; import PluginChecker from 'utils/plugin-checker'; @@ -8,49 +7,45 @@ export enum PluginsActionTypes { CHECKED_ALL_PLUGINS = 'CHECKED_ALL_PLUGINS' } -interface PluginObjects { - [plugin: string]: boolean; -} - -function checkPlugins(): AnyAction { - const action = { - type: PluginsActionTypes.CHECK_PLUGINS, - payload: {}, - }; - - return action; -} +type PluginObjects = Record; -function checkedAllPlugins(list: PluginObjects): AnyAction { - const action = { - type: PluginsActionTypes.CHECKED_ALL_PLUGINS, - payload: { +const pluginActions = { + checkPlugins: () => createAction(PluginsActionTypes.CHECK_PLUGINS), + checkedAllPlugins: (list: PluginObjects) => ( + createAction(PluginsActionTypes.CHECKED_ALL_PLUGINS, { list, - }, - }; - - return action; -} - -export function checkPluginsAsync(): -ThunkAction, {}, {}, AnyAction> { - return async (dispatch: ActionCreator): Promise => { - dispatch(checkPlugins()); - const plugins: PluginObjects = {}; - - const promises: Promise[] = []; - const keys = Object.keys(SupportedPlugins); - for (const key of keys) { - const plugin = SupportedPlugins[key as any]; - promises.push(PluginChecker.check(plugin as SupportedPlugins)); - } + }) + ), +}; + +export type PluginActions = ActionUnion; + +export function checkPluginsAsync(): ThunkAction { + return async (dispatch): Promise => { + dispatch(pluginActions.checkPlugins()); + const plugins: PluginObjects = { + ANALYTICS: false, + AUTO_ANNOTATION: false, + GIT_INTEGRATION: false, + TF_ANNOTATION: false, + TF_SEGMENTATION: false, + }; + + const promises: Promise[] = [ + PluginChecker.check(SupportedPlugins.ANALYTICS), + PluginChecker.check(SupportedPlugins.AUTO_ANNOTATION), + PluginChecker.check(SupportedPlugins.GIT_INTEGRATION), + PluginChecker.check(SupportedPlugins.TF_ANNOTATION), + PluginChecker.check(SupportedPlugins.TF_SEGMENTATION), + ]; const values = await Promise.all(promises); - let i = 0; - for (const key of keys) { - plugins[key] = values[i++]; - } + [plugins.ANALYTICS] = values; + [, plugins.AUTO_ANNOTATION] = values; + [,, plugins.GIT_INTEGRATION] = values; + [,,, plugins.TF_ANNOTATION] = values; + [,,,, plugins.TF_SEGMENTATION] = values; - dispatch(checkedAllPlugins(plugins)); + dispatch(pluginActions.checkedAllPlugins(plugins)); }; } diff --git a/cvat-ui/src/actions/share-actions.ts b/cvat-ui/src/actions/share-actions.ts index 978f4fa8655e..757e702b4108 100644 --- a/cvat-ui/src/actions/share-actions.ts +++ b/cvat-ui/src/actions/share-actions.ts @@ -1,8 +1,7 @@ -import { AnyAction, Dispatch, ActionCreator } from 'redux'; -import { ThunkAction } from 'redux-thunk'; +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; +import getCore from 'cvat-core'; import { ShareFileInfo } from 'reducers/interfaces'; -import getCore from 'cvat-core'; const core = getCore(); @@ -12,49 +11,35 @@ export enum ShareActionTypes { LOAD_SHARE_DATA_FAILED = 'LOAD_SHARE_DATA_FAILED', } -function loadShareData(): AnyAction { - const action = { - type: ShareActionTypes.LOAD_SHARE_DATA, - payload: {}, - }; - - return action; -} - -function loadShareDataSuccess(values: ShareFileInfo[], directory: string): AnyAction { - const action = { - type: ShareActionTypes.LOAD_SHARE_DATA_SUCCESS, - payload: { +const shareActions = { + loadShareData: () => createAction(ShareActionTypes.LOAD_SHARE_DATA), + loadShareDataSuccess: (values: ShareFileInfo[], directory: string) => ( + createAction(ShareActionTypes.LOAD_SHARE_DATA_SUCCESS, { values, directory, - }, - }; - - return action; -} - -function loadShareDataFailed(error: any): AnyAction { - const action = { - type: ShareActionTypes.LOAD_SHARE_DATA_FAILED, - payload: { - error, - }, - }; - - return action; -} - -export function loadShareDataAsync(directory: string, success: () => void, failure: () => void): -ThunkAction, {}, {}, AnyAction> { - return async (dispatch: ActionCreator): Promise => { + }) + ), + loadShareDataFailed: (error: any) => ( + createAction(ShareActionTypes.LOAD_SHARE_DATA_FAILED, { error }) + ), +}; + +export type ShareActions = ActionUnion; + +export function loadShareDataAsync( + directory: string, + success: () => void, + failure: () => void, +): ThunkAction { + return async (dispatch): Promise => { try { - dispatch(loadShareData()); + dispatch(shareActions.loadShareData()); const values = await core.server.share(directory); success(); - dispatch(loadShareDataSuccess(values as ShareFileInfo[], directory)); + dispatch(shareActions.loadShareDataSuccess(values as ShareFileInfo[], directory)); } catch (error) { - dispatch(loadShareDataFailed(error)); failure(); + dispatch(shareActions.loadShareDataFailed(error)); } }; } diff --git a/cvat-ui/src/actions/users-actions.ts b/cvat-ui/src/actions/users-actions.ts index d69ca0246d14..5d31134227ea 100644 --- a/cvat-ui/src/actions/users-actions.ts +++ b/cvat-ui/src/actions/users-actions.ts @@ -1,6 +1,4 @@ -import { AnyAction, Dispatch, ActionCreator } from 'redux'; -import { ThunkAction } from 'redux-thunk'; - +import { ActionUnion, createAction, ThunkAction } from 'utils/redux'; import getCore from 'cvat-core'; const core = getCore(); @@ -11,47 +9,25 @@ export enum UsersActionTypes { GET_USERS_FAILED = 'GET_USERS_FAILED', } -function getUsers(): AnyAction { - const action = { - type: UsersActionTypes.GET_USERS, - payload: {}, - }; - - return action; -} - -function getUsersSuccess(users: any[]): AnyAction { - const action = { - type: UsersActionTypes.GET_USERS_SUCCESS, - payload: { users }, - }; +const usersActions = { + getUsers: () => createAction(UsersActionTypes.GET_USERS), + getUsersSuccess: (users: any[]) => createAction(UsersActionTypes.GET_USERS_SUCCESS, { users }), + getUsersFailed: (error: any) => createAction(UsersActionTypes.GET_USERS_FAILED, { error }), +}; - return action; -} - -function getUsersFailed(error: any): AnyAction { - const action = { - type: UsersActionTypes.GET_USERS_FAILED, - payload: { error }, - }; - - return action; -} +export type UsersActions = ActionUnion; -export function getUsersAsync(): -ThunkAction, {}, {}, AnyAction> { - return async (dispatch: ActionCreator): Promise => { - dispatch(getUsers()); +export function getUsersAsync(): ThunkAction { + return async (dispatch): Promise => { + dispatch(usersActions.getUsers()); try { const users = await core.users.get(); - dispatch( - getUsersSuccess( - users.map((userData: any): any => new core.classes.User(userData)), - ), - ); + const wrappedUsers = users + .map((userData: any): any => new core.classes.User(userData)); + dispatch(usersActions.getUsersSuccess(wrappedUsers)); } catch (error) { - dispatch(getUsersFailed(error)); + dispatch(usersActions.getUsersFailed(error)); } }; } diff --git a/cvat-ui/src/reducers/auth-reducer.ts b/cvat-ui/src/reducers/auth-reducer.ts index a18cf610669d..4354bd2fd6e4 100644 --- a/cvat-ui/src/reducers/auth-reducer.ts +++ b/cvat-ui/src/reducers/auth-reducer.ts @@ -7,7 +7,7 @@ const defaultState: AuthState = { user: null, }; -export default (state = defaultState, action: AuthActions): AuthState => { +export default function (state = defaultState, action: AuthActions): AuthState { switch (action.type) { case AuthActionTypes.AUTHORIZED_SUCCESS: return { @@ -67,4 +67,4 @@ export default (state = defaultState, action: AuthActions): AuthState => { default: return state; } -}; +} diff --git a/cvat-ui/src/reducers/formats-reducer.ts b/cvat-ui/src/reducers/formats-reducer.ts index b66afab8bc02..da9d50dc38fb 100644 --- a/cvat-ui/src/reducers/formats-reducer.ts +++ b/cvat-ui/src/reducers/formats-reducer.ts @@ -1,6 +1,5 @@ -import { AnyAction } from 'redux'; -import { FormatsActionTypes } from 'actions/formats-actions'; -import { AuthActionTypes } from 'actions/auth-actions'; +import { FormatsActionTypes, FormatsActions } from 'actions/formats-actions'; +import { AuthActionTypes, AuthActions } from 'actions/auth-actions'; import { FormatsState } from './interfaces'; @@ -11,7 +10,10 @@ const defaultState: FormatsState = { fetching: false, }; -export default (state = defaultState, action: AnyAction): FormatsState => { +export default ( + state: FormatsState = defaultState, + action: FormatsActions | AuthActions, +): FormatsState => { switch (action.type) { case FormatsActionTypes.GET_FORMATS: { return { diff --git a/cvat-ui/src/reducers/plugins-reducer.ts b/cvat-ui/src/reducers/plugins-reducer.ts index 97ec0344d0ab..16e08f7cdf0b 100644 --- a/cvat-ui/src/reducers/plugins-reducer.ts +++ b/cvat-ui/src/reducers/plugins-reducer.ts @@ -1,13 +1,9 @@ -import { AnyAction } from 'redux'; - -import { PluginsActionTypes } from 'actions/plugins-actions'; -import { AuthActionTypes } from 'actions/auth-actions'; +import { PluginsActionTypes, PluginActions } from 'actions/plugins-actions'; import { registerGitPlugin } from 'utils/git-utils'; import { PluginsState, } from './interfaces'; - const defaultState: PluginsState = { fetching: false, initialized: false, @@ -19,7 +15,11 @@ const defaultState: PluginsState = { ANALYTICS: false, }, }; -export default function (state = defaultState, action: AnyAction): PluginsState { + +export default function ( + state: PluginsState = defaultState, + action: PluginActions, +): PluginsState { switch (action.type) { case PluginsActionTypes.CHECK_PLUGINS: { return { @@ -42,11 +42,6 @@ export default function (state = defaultState, action: AnyAction): PluginsState list, }; } - case AuthActionTypes.LOGOUT_SUCCESS: { - return { - ...defaultState, - }; - } default: return state; } diff --git a/cvat-ui/src/reducers/share-reducer.ts b/cvat-ui/src/reducers/share-reducer.ts index 6fe4d6cba784..e711db21f25e 100644 --- a/cvat-ui/src/reducers/share-reducer.ts +++ b/cvat-ui/src/reducers/share-reducer.ts @@ -1,7 +1,5 @@ -import { AnyAction } from 'redux'; - -import { ShareActionTypes } from 'actions/share-actions'; -import { AuthActionTypes } from 'actions/auth-actions'; +import { ShareActionTypes, ShareActions } from 'actions/share-actions'; +import { AuthActionTypes, AuthActions } from 'actions/auth-actions'; import { ShareState, ShareFileInfo, @@ -16,7 +14,10 @@ const defaultState: ShareState = { }, }; -export default function (state = defaultState, action: AnyAction): ShareState { +export default function ( + state: ShareState = defaultState, + action: ShareActions | AuthActions, +): ShareState { switch (action.type) { case ShareActionTypes.LOAD_SHARE_DATA_SUCCESS: { const { values } = action.payload; diff --git a/cvat-ui/src/reducers/users-reducer.ts b/cvat-ui/src/reducers/users-reducer.ts index e339e4d541c4..ea2f742f030e 100644 --- a/cvat-ui/src/reducers/users-reducer.ts +++ b/cvat-ui/src/reducers/users-reducer.ts @@ -1,7 +1,5 @@ -import { AnyAction } from 'redux'; - -import { AuthActionTypes } from 'actions/auth-actions'; -import { UsersActionTypes } from 'actions/users-actions'; +import { AuthActionTypes, AuthActions } from 'actions/auth-actions'; +import { UsersActionTypes, UsersActions } from 'actions/users-actions'; import { UsersState } from './interfaces'; const defaultState: UsersState = { @@ -10,7 +8,10 @@ const defaultState: UsersState = { initialized: false, }; -export default function (state: UsersState = defaultState, action: AnyAction): UsersState { +export default function ( + state: UsersState = defaultState, + action: UsersActions | AuthActions, +): UsersState { switch (action.type) { case UsersActionTypes.GET_USERS: { return { diff --git a/cvat-ui/src/utils/redux.ts b/cvat-ui/src/utils/redux.ts index 081662aeabea..bc30f6e77c6f 100644 --- a/cvat-ui/src/utils/redux.ts +++ b/cvat-ui/src/utils/redux.ts @@ -8,7 +8,9 @@ export interface ActionWithPayload extends Action { export function createAction(type: T): Action; export function createAction(type: T, payload: P): ActionWithPayload; -export function createAction(type: T, payload?: P) { +export function createAction( + type: T, payload?: P, +): Action | ActionWithPayload { return typeof payload === 'undefined' ? { type } : { type, payload }; }