Fix changing sort direction

This commit is contained in:
Mark McDowall 2025-11-15 11:49:59 -08:00
parent 21592f3d69
commit aac4760d30
13 changed files with 133 additions and 38 deletions

View file

@ -17,6 +17,7 @@ import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager'; import TablePager from 'Components/Table/TablePager';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector'; import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
@ -31,6 +32,7 @@ import translate from 'Utilities/String/translate';
import BlocklistFilterModal from './BlocklistFilterModal'; import BlocklistFilterModal from './BlocklistFilterModal';
import { import {
setBlocklistOption, setBlocklistOption,
setBlocklistSort,
useBlocklistOptions, useBlocklistOptions,
} from './blocklistOptionsStore'; } from './blocklistOptionsStore';
import BlocklistRow from './BlocklistRow'; import BlocklistRow from './BlocklistRow';
@ -129,9 +131,15 @@ function BlocklistContent() {
[] []
); );
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setBlocklistOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setBlocklistSort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {

View file

@ -6,7 +6,7 @@ import translate from 'Utilities/String/translate';
export type BlocklistOptions = PageableOptions; export type BlocklistOptions = PageableOptions;
const { useOptions, useOption, setOptions, setOption } = const { useOptions, useOption, setOptions, setOption, setSort } =
createOptionsStore<BlocklistOptions>('blocklist_options', () => { createOptionsStore<BlocklistOptions>('blocklist_options', () => {
return { return {
pageSize: 20, pageSize: 20,
@ -69,3 +69,4 @@ export const useBlocklistOptions = useOptions;
export const setBlocklistOptions = setOptions; export const setBlocklistOptions = setOptions;
export const useBlocklistOption = useOption; export const useBlocklistOption = useOption;
export const setBlocklistOption = setOption; export const setBlocklistOption = setOption;
export const setBlocklistSort = setSort;

View file

@ -1,9 +1,5 @@
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import {
setQueueOption,
setQueueOptions,
} from 'Activity/Queue/queueOptionsStore';
import Alert from 'Components/Alert'; import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu'; import FilterMenu from 'Components/Menu/FilterMenu';
@ -19,6 +15,7 @@ import TablePager from 'Components/Table/TablePager';
import createEpisodesFetchingSelector from 'Episode/createEpisodesFetchingSelector'; import createEpisodesFetchingSelector from 'Episode/createEpisodesFetchingSelector';
import useCurrentPage from 'Helpers/Hooks/useCurrentPage'; import useCurrentPage from 'Helpers/Hooks/useCurrentPage';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions'; import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions';
import { clearEpisodeFiles } from 'Store/Actions/episodeFileActions'; import { clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector'; import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
@ -31,7 +28,12 @@ import {
} from 'Utilities/pagePopulator'; } from 'Utilities/pagePopulator';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import HistoryFilterModal from './HistoryFilterModal'; import HistoryFilterModal from './HistoryFilterModal';
import { useHistoryOptions } from './historyOptionsStore'; import {
setHistoryOption,
setHistoryOptions,
setHistorySort,
useHistoryOptions,
} from './historyOptionsStore';
import HistoryRow from './HistoryRow'; import HistoryRow from './HistoryRow';
import useHistory, { useFilters } from './useHistory'; import useHistory, { useFilters } from './useHistory';
@ -67,18 +69,24 @@ function History() {
const handleFilterSelect = useCallback( const handleFilterSelect = useCallback(
(selectedFilterKey: string | number) => { (selectedFilterKey: string | number) => {
setQueueOption('selectedFilterKey', selectedFilterKey); setHistoryOption('selectedFilterKey', selectedFilterKey);
}, },
[] []
); );
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setQueueOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setHistorySort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {
setQueueOptions(payload); setHistoryOptions(payload);
if (payload.pageSize) { if (payload.pageSize) {
goToPage(1); goToPage(1);

View file

@ -9,7 +9,7 @@ import translate from 'Utilities/String/translate';
export type HistoryOptions = PageableOptions; export type HistoryOptions = PageableOptions;
const { useOptions, useOption, setOptions, setOption } = const { useOptions, useOption, setOptions, setOption, setSort } =
createOptionsStore<HistoryOptions>('history_options', () => { createOptionsStore<HistoryOptions>('history_options', () => {
return { return {
includeUnknownSeriesItems: true, includeUnknownSeriesItems: true,
@ -107,3 +107,4 @@ export const useHistoryOptions = useOptions;
export const setHistoryOptions = setOptions; export const setHistoryOptions = setOptions;
export const useHistoryOption = useOption; export const useHistoryOption = useOption;
export const setHistoryOption = setOption; export const setHistoryOption = setOption;
export const setHistorySort = setSort;

View file

@ -24,6 +24,7 @@ import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptions
import TablePager from 'Components/Table/TablePager'; import TablePager from 'Components/Table/TablePager';
import createEpisodesFetchingSelector from 'Episode/createEpisodesFetchingSelector'; import createEpisodesFetchingSelector from 'Episode/createEpisodesFetchingSelector';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions'; import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector'; import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
@ -42,6 +43,7 @@ import QueueOptions from './QueueOptions';
import { import {
setQueueOption, setQueueOption,
setQueueOptions, setQueueOptions,
setQueueSort,
useQueueOptions, useQueueOptions,
} from './queueOptionsStore'; } from './queueOptionsStore';
import QueueRow from './QueueRow'; import QueueRow from './QueueRow';
@ -164,9 +166,15 @@ function QueueContent() {
[] []
); );
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setQueueOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setQueueSort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {

View file

@ -17,7 +17,7 @@ export interface QueueOptions extends PageableOptions {
removalOptions: QueueRemovalOptions; removalOptions: QueueRemovalOptions;
} }
const { useOptions, useOption, setOptions, setOption } = const { useOptions, useOption, setOptions, setOption, setSort } =
createOptionsStore<QueueOptions>('queue_options', () => { createOptionsStore<QueueOptions>('queue_options', () => {
return { return {
includeUnknownSeriesItems: true, includeUnknownSeriesItems: true,
@ -158,3 +158,4 @@ export const useQueueOptions = useOptions;
export const setQueueOptions = setOptions; export const setQueueOptions = setOptions;
export const useQueueOption = useOption; export const useQueueOption = useOption;
export const setQueueOption = setOption; export const setQueueOption = setOption;
export const setQueueSort = setSort;

View file

@ -8,9 +8,12 @@ type TSettingsWithoutColumns = object;
interface TSettingsWithColumns { interface TSettingsWithColumns {
columns: Column[]; columns: Column[];
selectedFilterKey: string | number;
sortKey: string;
sortDirection: SortDirection;
} }
type TSettingd = TSettingsWithoutColumns | TSettingsWithColumns; type TSettings = TSettingsWithoutColumns | TSettingsWithColumns;
export interface PageableOptions { export interface PageableOptions {
pageSize: number; pageSize: number;
@ -25,7 +28,7 @@ export type OptionChanged<T> = {
value: T[keyof T]; value: T[keyof T];
}; };
export const createOptionsStore = <T extends TSettingd>( export const createOptionsStore = <T extends TSettings>(
name: string, name: string,
state: StateCreator<T>, state: StateCreator<T>,
options: Omit<PersistOptions<T>, 'name' | 'storage'> = {} options: Omit<PersistOptions<T>, 'name' | 'storage'> = {}
@ -52,6 +55,10 @@ export const createOptionsStore = <T extends TSettingd>(
}; };
const setOptions = (options: Partial<T>) => { const setOptions = (options: Partial<T>) => {
if ('sortKey' in options || 'sortDirection' in options) {
throw new Error('Use setSort to set sortKey and sortDirection');
}
store.setState((state) => ({ store.setState((state) => ({
...state, ...state,
...options, ...options,
@ -59,12 +66,47 @@ export const createOptionsStore = <T extends TSettingd>(
}; };
const setOption = <K extends keyof T>(key: K, value: T[K]) => { const setOption = <K extends keyof T>(key: K, value: T[K]) => {
if (key === 'sortKey' || key === 'sortDirection') {
throw new Error('Use setSort to set sortKey and sortDirection');
}
store.setState((state) => ({ store.setState((state) => ({
...state, ...state,
[key]: value, [key]: value,
})); }));
}; };
const setSort = ({
sortKey,
sortDirection,
}: {
sortKey: string;
sortDirection: SortDirection | undefined;
}) => {
// @ts-expect-error - Cannot verify if T has sortKey and sortDirection
store.setState((state) => {
if ('sortKey' in state === false || 'sortDirection' in state === false) {
return state;
}
let newSortDirection = sortDirection;
if (sortDirection == null) {
if (state.sortKey === sortKey) {
newSortDirection =
state.sortDirection === 'ascending' ? 'descending' : 'ascending';
} else {
newSortDirection = state.sortDirection;
}
}
return {
sortKey,
sortDirection: newSortDirection,
};
});
};
return { return {
store, store,
useOptions, useOptions,
@ -73,10 +115,11 @@ export const createOptionsStore = <T extends TSettingd>(
getOption, getOption,
setOptions, setOptions,
setOption, setOption,
setSort,
}; };
}; };
const merge = <T extends TSettingd>( const merge = <T extends TSettings>(
persistedState: unknown, persistedState: unknown,
currentState: T currentState: T
) => { ) => {

View file

@ -14,6 +14,7 @@ import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager'; import TablePager from 'Components/Table/TablePager';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { TableOptionsChangePayload } from 'typings/Table'; import { TableOptionsChangePayload } from 'typings/Table';
@ -21,6 +22,7 @@ import translate from 'Utilities/String/translate';
import { import {
setEventOption, setEventOption,
setEventOptions, setEventOptions,
setEventSort,
useEventOptions, useEventOptions,
} from './eventOptionsStore'; } from './eventOptionsStore';
import LogsTableRow from './LogsTableRow'; import LogsTableRow from './LogsTableRow';
@ -56,9 +58,15 @@ function LogsTable() {
[] []
); );
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setEventOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setEventSort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {

View file

@ -6,9 +6,8 @@ import translate from 'Utilities/String/translate';
export type EventOptions = PageableOptions; export type EventOptions = PageableOptions;
const { useOptions, setOptions, setOption } = createOptionsStore<EventOptions>( const { useOptions, setOptions, setOption, setSort } =
'event_options', createOptionsStore<EventOptions>('event_options', () => {
() => {
return { return {
pageSize: 50, pageSize: 50,
selectedFilterKey: 'all', selectedFilterKey: 'all',
@ -52,9 +51,9 @@ const { useOptions, setOptions, setOption } = createOptionsStore<EventOptions>(
}, },
], ],
}; };
} });
);
export const useEventOptions = useOptions; export const useEventOptions = useOptions;
export const setEventOptions = setOptions; export const setEventOptions = setOptions;
export const setEventOption = setOption; export const setEventOption = setOption;
export const setEventSort = setSort;

View file

@ -21,6 +21,7 @@ import TablePager from 'Components/Table/TablePager';
import Episode from 'Episode/Episode'; import Episode from 'Episode/Episode';
import { useToggleEpisodesMonitored } from 'Episode/useEpisode'; import { useToggleEpisodesMonitored } from 'Episode/useEpisode';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import { fetchEpisodeFiles } from 'Store/Actions/episodeFileActions'; import { fetchEpisodeFiles } from 'Store/Actions/episodeFileActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
@ -36,6 +37,7 @@ import translate from 'Utilities/String/translate';
import { import {
setCutoffUnmetOption, setCutoffUnmetOption,
setCutoffUnmetOptions, setCutoffUnmetOptions,
setCutoffUnmetSort,
useCutoffUnmetOptions, useCutoffUnmetOptions,
} from './cutoffUnmetOptionsStore'; } from './cutoffUnmetOptionsStore';
import CutoffUnmetRow from './CutoffUnmetRow'; import CutoffUnmetRow from './CutoffUnmetRow';
@ -156,9 +158,15 @@ function CutoffUnmetContent() {
setCutoffUnmetOption('selectedFilterKey', filterKey); setCutoffUnmetOption('selectedFilterKey', filterKey);
}, []); }, []);
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setCutoffUnmetOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setCutoffUnmetSort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {

View file

@ -4,7 +4,7 @@ import {
} from 'Helpers/Hooks/useOptionsStore'; } from 'Helpers/Hooks/useOptionsStore';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
const { useOptions, useOption, setOptions, setOption } = const { useOptions, useOption, setOptions, setOption, setSort } =
createOptionsStore<PageableOptions>('cutoffUnmet_options', () => { createOptionsStore<PageableOptions>('cutoffUnmet_options', () => {
return { return {
pageSize: 20, pageSize: 20,
@ -65,3 +65,4 @@ export const useCutoffUnmetOptions = useOptions;
export const setCutoffUnmetOptions = setOptions; export const setCutoffUnmetOptions = setOptions;
export const useCutoffUnmetOption = useOption; export const useCutoffUnmetOption = useOption;
export const setCutoffUnmetOption = setOption; export const setCutoffUnmetOption = setOption;
export const setCutoffUnmetSort = setSort;

View file

@ -21,6 +21,7 @@ import TablePager from 'Components/Table/TablePager';
import Episode from 'Episode/Episode'; import Episode from 'Episode/Episode';
import { useToggleEpisodesMonitored } from 'Episode/useEpisode'; import { useToggleEpisodesMonitored } from 'Episode/useEpisode';
import { align, icons, kinds } from 'Helpers/Props'; import { align, icons, kinds } from 'Helpers/Props';
import { SortDirection } from 'Helpers/Props/sortDirections';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal'; import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
@ -36,6 +37,7 @@ import translate from 'Utilities/String/translate';
import { import {
setMissingOption, setMissingOption,
setMissingOptions, setMissingOptions,
setMissingSort,
useMissingOptions, useMissingOptions,
} from './missingOptionsStore'; } from './missingOptionsStore';
import MissingRow from './MissingRow'; import MissingRow from './MissingRow';
@ -163,9 +165,15 @@ function MissingContent() {
setMissingOption('selectedFilterKey', filterKey); setMissingOption('selectedFilterKey', filterKey);
}, []); }, []);
const handleSortPress = useCallback((sortKey: string) => { const handleSortPress = useCallback(
setMissingOption('sortKey', sortKey); (sortKey: string, sortDirection?: SortDirection) => {
}, []); setMissingSort({
sortKey,
sortDirection,
});
},
[]
);
const handleTableOptionChange = useCallback( const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => { (payload: TableOptionsChangePayload) => {

View file

@ -4,7 +4,7 @@ import {
} from 'Helpers/Hooks/useOptionsStore'; } from 'Helpers/Hooks/useOptionsStore';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
const { useOptions, useOption, setOptions, setOption } = const { useOptions, useOption, setOptions, setOption, setSort } =
createOptionsStore<PageableOptions>('missing_options', () => { createOptionsStore<PageableOptions>('missing_options', () => {
return { return {
pageSize: 20, pageSize: 20,
@ -60,3 +60,4 @@ export const useMissingOptions = useOptions;
export const setMissingOptions = setOptions; export const setMissingOptions = setOptions;
export const useMissingOption = useOption; export const useMissingOption = useOption;
export const setMissingOption = setOption; export const setMissingOption = setOption;
export const setMissingSort = setSort;