1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-18 21:35:27 -04:00

Use react-query for Quality Definitions

This commit is contained in:
Mark McDowall
2025-12-29 23:38:30 -08:00
parent 243a3057ae
commit cf593b1f5d
17 changed files with 320 additions and 370 deletions
@@ -7,7 +7,6 @@ import AppSectionState, {
PagedAppSectionState,
} from 'App/State/AppSectionState';
import Language from 'Language/Language';
import { QualityProfileModel } from 'Settings/Profiles/Quality/useQualityProfiles';
import AutoTagging, { AutoTaggingSpecification } from 'typings/AutoTagging';
import CustomFormat from 'typings/CustomFormat';
import CustomFormatSpecification from 'typings/CustomFormatSpecification';
@@ -19,7 +18,6 @@ import ImportListOptionsSettings from 'typings/ImportListOptionsSettings';
import Indexer from 'typings/Indexer';
import IndexerFlag from 'typings/IndexerFlag';
import Notification from 'typings/Notification';
import QualityDefinition from 'typings/QualityDefinition';
import DownloadClientOptions from 'typings/Settings/DownloadClientOptions';
import General from 'typings/Settings/General';
import IndexerOptions from 'typings/Settings/IndexerOptions';
@@ -100,14 +98,6 @@ export interface NotificationAppState
AppSectionSaveState,
AppSectionSchemaState<Presets<Notification>> {}
export interface QualityDefinitionsAppState
extends AppSectionState<QualityDefinition>,
AppSectionSaveState {
pendingChanges: {
[key: number]: Partial<QualityProfileModel>;
};
}
export interface CustomFormatAppState
extends AppSectionState<CustomFormat>,
AppSectionDeleteState,
@@ -155,7 +145,6 @@ interface SettingsAppState {
naming: NamingAppState;
namingExamples: NamingExamplesAppState;
notifications: NotificationAppState;
qualityDefinitions: QualityDefinitionsAppState;
}
export default SettingsAppState;
+5 -2
View File
@@ -15,7 +15,6 @@ import { EpisodeFile } from 'EpisodeFile/EpisodeFile';
import { PagedQueryResponse } from 'Helpers/Hooks/usePagedApiQuery';
import Series from 'Series/Series';
import { removeItem, updateItem } from 'Store/Actions/baseActions';
import { fetchQualityDefinitions } from 'Store/Actions/settingsActions';
import { repopulatePage } from 'Utilities/pagePopulator';
import SignalRLogger from 'Utilities/SignalRLogger';
@@ -291,7 +290,11 @@ function SignalRListener() {
}
if (name === 'qualitydefinition') {
dispatch(fetchQualityDefinitions());
if (version < 5) {
return;
}
queryClient.invalidateQueries({ queryKey: ['/qualitydefinition'] });
return;
}
@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { create, useStore } from 'zustand';
import { useShallow } from 'zustand/react/shallow';
@@ -23,34 +23,40 @@ export const usePendingChangesStore = <T extends object>(
});
});
const setPendingChange = <K extends keyof T>(key: K, value: T[K]) => {
store.setState((state) => ({
...state,
pendingChanges: {
...state.pendingChanges,
[key]: value,
},
}));
};
const unsetPendingChange = <K extends keyof T>(key: K) => {
store.setState((state) => {
const newPendingChanges = { ...state.pendingChanges };
delete newPendingChanges[key];
return {
const setPendingChange = useCallback(
<K extends keyof T>(key: K, value: T[K]) => {
store.setState((state) => ({
...state,
pendingChanges: newPendingChanges,
};
});
};
pendingChanges: {
...state.pendingChanges,
[key]: value,
},
}));
},
[store]
);
const clearPendingChanges = () => {
const unsetPendingChange = useCallback(
<K extends keyof T>(key: K) => {
store.setState((state) => {
const newPendingChanges = { ...state.pendingChanges };
delete newPendingChanges[key];
return {
...state,
pendingChanges: newPendingChanges,
};
});
},
[store]
);
const clearPendingChanges = useCallback(() => {
store.setState((state) => ({
...state,
pendingChanges: {},
}));
};
}, [store]);
const pendingChanges = useStore(
store,
@@ -0,0 +1,121 @@
import { useCallback, useMemo, useState } from 'react';
import { create, useStore } from 'zustand';
import { useShallow } from 'zustand/react/shallow';
interface PendingItemsStore<T extends { id: number }> {
pendingItems: Map<number, Partial<T>>;
}
export const usePendingItemsStore = <T extends { id: number }>() => {
// eslint-disable-next-line react/hook-use-state
const [store] = useState(() => {
return create<PendingItemsStore<T>>()((_set) => {
return {
pendingItems: new Map(),
};
});
});
const setPendingItem = useCallback(
<K extends keyof T>(id: number, key: K, value: T[K], originalItem?: T) => {
store.setState((state) => {
const newPendingItems = new Map(state.pendingItems);
const existingChanges = newPendingItems.get(id) || {};
// If the value matches the original, remove it from pending changes
if (originalItem && originalItem[key] === value) {
const { [key]: removed, ...rest } = existingChanges;
if (Object.keys(rest).length === 0) {
newPendingItems.delete(id);
} else {
newPendingItems.set(id, rest);
}
} else {
newPendingItems.set(id, {
...existingChanges,
[key]: value,
});
}
return {
...state,
pendingItems: newPendingItems,
};
});
},
[store]
);
const unsetPendingItem = useCallback(
(id: number) => {
store.setState((state) => {
const newPendingItems = new Map(state.pendingItems);
newPendingItems.delete(id);
return {
...state,
pendingItems: newPendingItems,
};
});
},
[store]
);
const clearPendingItems = useCallback(() => {
store.setState((state) => ({
...state,
pendingItems: new Map(),
}));
}, [store]);
const pendingItems = useStore(
store,
useShallow((state) => state.pendingItems)
);
const getItemsWithPendingChanges = useCallback(
(originalItems: T[]): T[] => {
return originalItems.map((originalItem) => {
const pendingChanges = pendingItems.get(originalItem.id);
return pendingChanges
? { ...originalItem, ...pendingChanges }
: originalItem;
});
},
[pendingItems]
);
const hasPendingChanges = useMemo(() => {
return pendingItems.size > 0;
}, [pendingItems]);
const getPendingChangesForSave = useCallback(
(originalItems: T[]): T[] => {
return originalItems.reduce<T[]>((acc, originalItem) => {
const pendingChanges = pendingItems.get(originalItem.id);
if (pendingChanges) {
acc.push({
...originalItem,
...pendingChanges,
});
}
return acc;
}, []);
},
[pendingItems]
);
return {
store,
setPendingItem,
unsetPendingItem,
clearPendingItems,
getItemsWithPendingChanges,
getPendingChangesForSave,
hasPendingChanges,
};
};
@@ -1,11 +1,11 @@
import ModelBase from 'App/ModelBase';
import Quality from './Quality';
export default interface QualityDefinition {
export default interface QualityDefinitionModel extends ModelBase {
quality: Quality;
title: string;
weight: number;
minSize: number;
maxSize: number;
preferredSize: number;
id: number;
}
@@ -1,31 +1,29 @@
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import TextInput from 'Components/Form/TextInput';
import Quality from 'Quality/Quality';
import { setQualityDefinitionValue } from 'Store/Actions/settingsActions';
import { useManageQualityDefinitions } from './useQualityDefinitions';
import styles from './QualityDefinition.css';
interface QualityDefinitionProps {
id: number;
quality: Quality;
title: string;
updateDefinition: ReturnType<
typeof useManageQualityDefinitions
>['updateDefinition'];
}
function QualityDefinition(props: QualityDefinitionProps) {
const { id, quality, title } = props;
const dispatch = useDispatch();
function QualityDefinition({
id,
quality,
title,
updateDefinition,
}: QualityDefinitionProps) {
const handleTitleChange = useCallback(
({ value }: { value: string }) => {
dispatch(
setQualityDefinitionValue({
id,
name: 'title',
value,
})
);
updateDefinition(id, 'title', value);
},
[id, dispatch]
[id, updateDefinition]
);
return (
@@ -1,42 +1,17 @@
import { isEmpty } from 'lodash';
import { useQueryClient } from '@tanstack/react-query';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FieldSet from 'Components/FieldSet';
import PageSectionContent from 'Components/Page/PageSectionContent';
import usePrevious from 'Helpers/Hooks/usePrevious';
import {
fetchQualityDefinitions,
saveQualityDefinitions,
} from 'Store/Actions/settingsActions';
import {
OnChildStateChange,
SetChildSave,
} from 'typings/Settings/SettingsState';
import translate from 'Utilities/String/translate';
import QualityDefinition from './QualityDefinition';
import { useManageQualityDefinitions } from './useQualityDefinitions';
import styles from './QualityDefinitions.css';
function createQualityDefinitionsSelector() {
return createSelector(
(state: AppState) => state.settings.qualityDefinitions,
(qualityDefinitions) => {
const items = qualityDefinitions.items.map((item) => {
const pendingChanges = qualityDefinitions.pendingChanges[item.id] || {};
return Object.assign({}, item, pendingChanges);
});
return {
...qualityDefinitions,
items,
hasPendingChanges: !isEmpty(qualityDefinitions.pendingChanges),
};
}
);
}
interface QualityDefinitionsProps {
isResettingQualityDefinitions: boolean;
setChildSave: SetChildSave;
@@ -48,21 +23,27 @@ function QualityDefinitions({
setChildSave,
onChildStateChange,
}: QualityDefinitionsProps) {
const dispatch = useDispatch();
const { items, isFetching, isPopulated, isSaving, error, hasPendingChanges } =
useSelector(createQualityDefinitionsSelector());
const queryClient = useQueryClient();
const {
items,
isFetching,
isFetched,
isSaving,
error,
hasPendingChanges,
updateDefinition,
saveQualityDefinitions,
} = useManageQualityDefinitions();
const wasResettingQualityDefinitions = usePrevious(
isResettingQualityDefinitions
);
useEffect(() => {
dispatch(fetchQualityDefinitions());
setChildSave(() => {
dispatch(saveQualityDefinitions());
saveQualityDefinitions();
});
}, [dispatch, setChildSave]);
}, [saveQualityDefinitions, setChildSave]);
useEffect(() => {
onChildStateChange({
@@ -73,16 +54,20 @@ function QualityDefinitions({
useEffect(() => {
if (wasResettingQualityDefinitions && !isResettingQualityDefinitions) {
dispatch(fetchQualityDefinitions());
queryClient.invalidateQueries({ queryKey: ['/qualitydefinition'] });
}
}, [isResettingQualityDefinitions, wasResettingQualityDefinitions, dispatch]);
}, [
isResettingQualityDefinitions,
wasResettingQualityDefinitions,
queryClient,
]);
return (
<FieldSet legend={translate('QualityDefinitions')}>
<PageSectionContent
errorMessage={translate('QualityDefinitionsLoadError')}
isFetching={isFetching}
isPopulated={isPopulated}
isPopulated={isFetched}
error={error}
>
<div className={styles.header}>
@@ -92,7 +77,13 @@ function QualityDefinitions({
<div className={styles.definitions}>
{items.map((item) => {
return <QualityDefinition key={item.id} {...item} />;
return (
<QualityDefinition
key={item.id}
{...item}
updateDefinition={updateDefinition}
/>
);
})}
</div>
</PageSectionContent>
@@ -0,0 +1,99 @@
import { useQueryClient } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
import useApiMutation from 'Helpers/Hooks/useApiMutation';
import useApiQuery from 'Helpers/Hooks/useApiQuery';
import { usePendingItemsStore } from 'Helpers/Hooks/usePendingItemsStore';
import QualityDefinitionModel from 'Quality/QualityDefinitionModel';
import { useSaveSettings } from 'Settings/useSettings';
const PATH = '/qualitydefinition';
const DEFAULT_QUALITY_DEFINITIONS: QualityDefinitionModel[] = [];
export const useQualityDefinitions = () => {
const result = useApiQuery<QualityDefinitionModel[]>({
path: PATH,
});
return {
...result,
data: result.data ?? DEFAULT_QUALITY_DEFINITIONS,
};
};
export const useSaveQualityDefinitions = (onSuccess?: () => void) => {
const queryClient = useQueryClient();
const { mutate, isPending, error } = useApiMutation<
QualityDefinitionModel[],
QualityDefinitionModel[]
>({
path: PATH,
method: 'PUT',
mutationOptions: {
onSuccess: (updatedSettings: QualityDefinitionModel[]) => {
queryClient.setQueryData<QualityDefinitionModel[]>(
[PATH],
updatedSettings
);
onSuccess?.();
},
},
});
return {
save: mutate,
isSaving: isPending,
saveError: error,
};
};
export const useManageQualityDefinitions = () => {
const { data, isFetching, isFetched, error } = useQualityDefinitions();
const {
setPendingItem,
clearPendingItems,
getItemsWithPendingChanges,
getPendingChangesForSave,
hasPendingChanges,
} = usePendingItemsStore<QualityDefinitionModel>();
const { save, isSaving, saveError } = useSaveSettings(
PATH,
clearPendingItems
);
const settings = useMemo(() => {
return {
items: getItemsWithPendingChanges(data),
hasPendingChanges,
};
}, [data, getItemsWithPendingChanges, hasPendingChanges]);
const saveQualityDefinitions = useCallback(() => {
const updatedSettings = getPendingChangesForSave(data);
save(updatedSettings);
}, [data, getPendingChangesForSave, save]);
const updateDefinition = useCallback(
<K extends keyof QualityDefinitionModel>(
id: number,
key: keyof QualityDefinitionModel,
value: QualityDefinitionModel[K]
) => {
const originalItem = data.find((def) => def.id === id);
setPendingItem(id, key, value, originalItem);
},
[data, setPendingItem]
);
return {
...settings,
updateDefinition,
saveQualityDefinitions,
isFetching,
isFetched,
isSaving,
error,
saveError,
};
};
+20 -5
View File
@@ -1,6 +1,7 @@
import React, { useCallback, useRef, useState } from 'react';
import CommandNames from 'Commands/CommandNames';
import { useCommandExecuting } from 'Commands/useCommands';
import { useCommandExecuting, useExecuteCommand } from 'Commands/useCommands';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
@@ -13,9 +14,9 @@ import {
} from 'typings/Settings/SettingsState';
import translate from 'Utilities/String/translate';
import QualityDefinitions from './Definition/QualityDefinitions';
import ResetQualityDefinitionsModal from './Reset/ResetQualityDefinitionsModal';
function Quality() {
const executeCommand = useExecuteCommand();
const isResettingQualityDefinitions = useCommandExecuting(
CommandNames.ResetQualityDefinitions
);
@@ -51,6 +52,15 @@ function Quality() {
setIsConfirmQualityDefinitionResetModalOpen(false);
}, []);
const handleResetQualityDefinitionsConfirmed = useCallback(() => {
executeCommand({
name: CommandNames.ResetQualityDefinitions,
resetTitles: true,
});
setIsConfirmQualityDefinitionResetModalOpen(false);
}, [executeCommand]);
const handleSavePress = useCallback(() => {
saveDefinitions.current?.();
}, []);
@@ -68,13 +78,13 @@ function Quality() {
label={translate('ResetDefinitions')}
iconName={icons.REFRESH}
isSpinning={isResettingQualityDefinitions}
isDisabled={isResettingQualityDefinitions}
onPress={handleResetQualityDefinitionsPress}
/>
</>
}
onSavePress={handleSavePress}
/>
<PageContentBody>
<QualityDefinitions
isResettingQualityDefinitions={isResettingQualityDefinitions}
@@ -83,9 +93,14 @@ function Quality() {
/>
</PageContentBody>
<ResetQualityDefinitionsModal
<ConfirmModal
isOpen={isConfirmQualityDefinitionResetModalOpen}
onModalClose={handleCloseResetQualityDefinitionsModal}
kind="danger"
title={translate('ResetQualityDefinitions')}
message={translate('ResetQualityDefinitionsMessageText')}
confirmLabel={translate('Reset')}
onConfirm={handleResetQualityDefinitionsConfirmed}
onCancel={handleCloseResetQualityDefinitionsModal}
/>
</PageContent>
);
@@ -1,22 +0,0 @@
import React from 'react';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import ResetQualityDefinitionsModalContent from './ResetQualityDefinitionsModalContent';
interface ResetQualityDefinitionsModalProps {
isOpen: boolean;
onModalClose: () => void;
}
function ResetQualityDefinitionsModal({
isOpen,
onModalClose,
}: ResetQualityDefinitionsModalProps) {
return (
<Modal isOpen={isOpen} size={sizes.MEDIUM} onModalClose={onModalClose}>
<ResetQualityDefinitionsModalContent onModalClose={onModalClose} />
</Modal>
);
}
export default ResetQualityDefinitionsModal;
@@ -1,3 +0,0 @@
.messageContainer {
margin-bottom: 20px;
}
@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'messageContainer': string;
}
export const cssExports: CssExports;
export default cssExports;
@@ -1,87 +0,0 @@
import React, { useCallback, useState } from 'react';
import CommandNames from 'Commands/CommandNames';
import { useCommandExecuting, useExecuteCommand } from 'Commands/useCommands';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import { InputChanged } from 'typings/inputs';
import translate from 'Utilities/String/translate';
import styles from './ResetQualityDefinitionsModalContent.css';
interface ResetQualityDefinitionsModalContentProps {
onModalClose: () => void;
}
function ResetQualityDefinitionsModalContent({
onModalClose,
}: ResetQualityDefinitionsModalContentProps) {
const executeCommand = useExecuteCommand();
const isResettingQualityDefinitions = useCommandExecuting(
CommandNames.ResetQualityDefinitions
);
const [resetDefinitionTitles, setResetDefinitionTitles] = useState(false);
const handleResetDefinitionTitlesChange = useCallback(
({ value }: InputChanged<boolean>) => {
setResetDefinitionTitles(value);
},
[]
);
const handleResetQualityDefinitionsConfirmed = useCallback(() => {
const resetTitles = resetDefinitionTitles;
setResetDefinitionTitles(false);
executeCommand({
name: CommandNames.ResetQualityDefinitions,
resetTitles,
});
onModalClose();
}, [resetDefinitionTitles, executeCommand, onModalClose]);
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{translate('ResetQualityDefinitions')}</ModalHeader>
<ModalBody>
<div className={styles.messageContainer}>
{translate('ResetQualityDefinitionsMessageText')}
</div>
<FormGroup>
<FormLabel>{translate('ResetTitles')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="resetDefinitionTitles"
value={resetDefinitionTitles}
helpText={translate('ResetDefinitionTitlesHelpText')}
onChange={handleResetDefinitionTitlesChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button
kind={kinds.DANGER}
isDisabled={isResettingQualityDefinitions}
onPress={handleResetQualityDefinitionsConfirmed}
>
{translate('Reset')}
</Button>
</ModalFooter>
</ModalContent>
);
}
export default ResetQualityDefinitionsModalContent;
@@ -1,137 +0,0 @@
import _ from 'lodash';
import { createAction } from 'redux-actions';
import { batchActions } from 'redux-batched-actions';
import { clearPendingChanges, set, update } from 'Store/Actions/baseActions';
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
import { createThunk } from 'Store/thunks';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import getSectionState from 'Utilities/State/getSectionState';
import updateSectionState from 'Utilities/State/updateSectionState';
//
// Variables
const section = 'settings.qualityDefinitions';
//
// Actions Types
export const FETCH_QUALITY_DEFINITIONS = 'settings/qualityDefinitions/fetchQualityDefinitions';
export const SAVE_QUALITY_DEFINITIONS = 'settings/qualityDefinitions/saveQualityDefinitions';
export const SET_QUALITY_DEFINITION_VALUE = 'settings/qualityDefinitions/setQualityDefinitionValue';
//
// Action Creators
export const fetchQualityDefinitions = createThunk(FETCH_QUALITY_DEFINITIONS);
export const saveQualityDefinitions = createThunk(SAVE_QUALITY_DEFINITIONS);
export const setQualityDefinitionValue = createAction(SET_QUALITY_DEFINITION_VALUE);
//
// Details
export default {
//
// State
defaultState: {
isFetching: false,
isPopulated: false,
error: null,
items: [],
isSaving: false,
saveError: null,
pendingChanges: {}
},
//
// Action Handlers
actionHandlers: {
[FETCH_QUALITY_DEFINITIONS]: createFetchHandler(section, '/qualitydefinition'),
[SAVE_QUALITY_DEFINITIONS]: createSaveHandler(section, '/qualitydefinition'),
[SAVE_QUALITY_DEFINITIONS]: function(getState, payload, dispatch) {
const qualityDefinitions = getState().settings.qualityDefinitions;
const upatedDefinitions = Object.keys(qualityDefinitions.pendingChanges).map((key) => {
const id = parseInt(key);
const pendingChanges = qualityDefinitions.pendingChanges[id] || {};
const item = _.find(qualityDefinitions.items, { id });
return Object.assign({}, item, pendingChanges);
});
// If there is nothing to save don't bother isSaving
if (!upatedDefinitions || !upatedDefinitions.length) {
return;
}
dispatch(set({
section,
isSaving: true
}));
const promise = createAjaxRequest({
method: 'PUT',
url: '/qualitydefinition/update',
data: JSON.stringify(upatedDefinitions),
contentType: 'application/json',
dataType: 'json'
}).request;
promise.done((data) => {
dispatch(batchActions([
set({
section,
isSaving: false,
saveError: null
}),
update({ section, data }),
clearPendingChanges({ section })
]));
});
promise.fail((xhr) => {
dispatch(set({
section,
isSaving: false,
saveError: xhr
}));
});
}
},
//
// Reducers
reducers: {
[SET_QUALITY_DEFINITION_VALUE]: function(state, { payload }) {
const { id, name, value } = payload;
const newState = getSectionState(state, section);
newState.pendingChanges = _.cloneDeep(newState.pendingChanges);
const pendingState = newState.pendingChanges[id] || {};
const currentValue = _.find(newState.items, { id })[name];
if (currentValue === value) {
delete pendingState[name];
} else {
pendingState[name] = value;
}
if (_.isEmpty(pendingState)) {
delete newState.pendingChanges[id];
} else {
newState.pendingChanges[id] = pendingState;
}
return updateSectionState(state, section, newState);
}
}
};
@@ -20,7 +20,6 @@ import metadata from './Settings/metadata';
import naming from './Settings/naming';
import namingExamples from './Settings/namingExamples';
import notifications from './Settings/notifications';
import qualityDefinitions from './Settings/qualityDefinitions';
export * from './Settings/autoTaggingSpecifications';
export * from './Settings/autoTaggings';
@@ -42,7 +41,6 @@ export * from './Settings/metadata';
export * from './Settings/naming';
export * from './Settings/namingExamples';
export * from './Settings/notifications';
export * from './Settings/qualityDefinitions';
//
// Variables
@@ -73,8 +71,7 @@ export const defaultState = {
metadata: metadata.defaultState,
naming: naming.defaultState,
namingExamples: namingExamples.defaultState,
notifications: notifications.defaultState,
qualityDefinitions: qualityDefinitions.defaultState
notifications: notifications.defaultState
};
export const persistState = [
@@ -104,8 +101,7 @@ export const actionHandlers = handleThunks({
...metadata.actionHandlers,
...naming.actionHandlers,
...namingExamples.actionHandlers,
...notifications.actionHandlers,
...qualityDefinitions.actionHandlers
...notifications.actionHandlers
});
//
@@ -131,7 +127,6 @@ export const reducers = createHandleActions({
...metadata.reducers,
...naming.reducers,
...namingExamples.reducers,
...notifications.reducers,
...qualityDefinitions.reducers
...notifications.reducers
}, defaultState, section);
-10
View File
@@ -1,10 +0,0 @@
import Quality from 'Quality/Quality';
interface QualityDefinition {
id: number;
quality: Quality;
title: string;
weight: number;
}
export default QualityDefinition;