diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index e9d3369f..81d047ed 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -16,13 +16,20 @@ const SettingsSections: FC<{ items: ReactNode[][] }> = ({ items }) => (
>
);
-const Settings = (RealTimeUpdates: FC, ShortUrlCreation: FC, UserInterface: FC, Visits: FC, Tags: FC) => () => (
+const Settings = (
+ RealTimeUpdates: FC,
+ ShortUrlCreation: FC,
+ ShortUrlsList: FC,
+ UserInterface: FC,
+ Visits: FC,
+ Tags: FC,
+) => () => (
], // eslint-disable-line react/jsx-key
- [ , ], // eslint-disable-line react/jsx-key
- [ , ], // eslint-disable-line react/jsx-key
+ [ , ], // eslint-disable-line react/jsx-key
+ [ , ], // eslint-disable-line react/jsx-key
+ [ , ], // eslint-disable-line react/jsx-key
]}
/>
diff --git a/src/settings/ShortUrlsList.tsx b/src/settings/ShortUrlsList.tsx
new file mode 100644
index 00000000..aadbb502
--- /dev/null
+++ b/src/settings/ShortUrlsList.tsx
@@ -0,0 +1,24 @@
+import { FC } from 'react';
+import { FormGroup } from 'reactstrap';
+import SortingDropdown from '../utils/SortingDropdown';
+import { SORTABLE_FIELDS } from '../short-urls/data';
+import { SimpleCard } from '../utils/SimpleCard';
+import { DEFAULT_SHORT_URLS_ORDERING, Settings, ShortUrlsListSettings } from './reducers/settings';
+
+interface ShortUrlsListProps {
+ settings: Settings;
+ setShortUrlsListSettings: (settings: ShortUrlsListSettings) => void;
+}
+
+export const ShortUrlsList: FC = ({ settings: { shortUrlsList }, setShortUrlsListSettings }) => (
+
+
+
+ setShortUrlsListSettings({ defaultOrdering: { field, dir } })}
+ />
+
+
+);
diff --git a/src/settings/Tags.tsx b/src/settings/Tags.tsx
index 63bc4aab..cbbd2af8 100644
--- a/src/settings/Tags.tsx
+++ b/src/settings/Tags.tsx
@@ -13,7 +13,7 @@ interface TagsProps {
}
export const Tags: FC = ({ settings: { tags }, setTagsSettings }) => (
-
+
({
+ type: SET_SETTINGS,
+ shortUrlsList: settings,
+});
+
export const setUiSettings = (settings: UiSettings): PartialSettingsAction => ({
type: SET_SETTINGS,
ui: settings,
diff --git a/src/settings/services/provideServices.ts b/src/settings/services/provideServices.ts
index 93d82584..c54d37aa 100644
--- a/src/settings/services/provideServices.ts
+++ b/src/settings/services/provideServices.ts
@@ -4,6 +4,7 @@ import Settings from '../Settings';
import {
setRealTimeUpdatesInterval,
setShortUrlCreationSettings,
+ setShortUrlsListSettings,
setTagsSettings,
setUiSettings,
setVisitsSettings,
@@ -15,10 +16,20 @@ import { ShortUrlCreation } from '../ShortUrlCreation';
import { UserInterface } from '../UserInterface';
import { Visits } from '../Visits';
import { Tags } from '../Tags';
+import { ShortUrlsList } from '../ShortUrlsList';
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
// Components
- bottle.serviceFactory('Settings', Settings, 'RealTimeUpdates', 'ShortUrlCreation', 'UserInterface', 'Visits', 'Tags');
+ bottle.serviceFactory(
+ 'Settings',
+ Settings,
+ 'RealTimeUpdates',
+ 'ShortUrlCreation',
+ 'ShortUrlsListSettings',
+ 'UserInterface',
+ 'Visits',
+ 'Tags',
+ );
bottle.decorator('Settings', withoutSelectedServer);
bottle.decorator('Settings', connect(null, [ 'resetSelectedServer' ]));
@@ -40,10 +51,14 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('Tags', () => Tags);
bottle.decorator('Tags', connect([ 'settings' ], [ 'setTagsSettings' ]));
+ bottle.serviceFactory('ShortUrlsListSettings', () => ShortUrlsList);
+ bottle.decorator('ShortUrlsListSettings', connect([ 'settings' ], [ 'setShortUrlsListSettings' ]));
+
// Actions
bottle.serviceFactory('toggleRealTimeUpdates', () => toggleRealTimeUpdates);
bottle.serviceFactory('setRealTimeUpdatesInterval', () => setRealTimeUpdatesInterval);
bottle.serviceFactory('setShortUrlCreationSettings', () => setShortUrlCreationSettings);
+ bottle.serviceFactory('setShortUrlsListSettings', () => setShortUrlsListSettings);
bottle.serviceFactory('setUiSettings', () => setUiSettings);
bottle.serviceFactory('setVisitsSettings', () => setVisitsSettings);
bottle.serviceFactory('setTagsSettings', () => setTagsSettings);
diff --git a/src/short-urls/ShortUrlsList.tsx b/src/short-urls/ShortUrlsList.tsx
index b3e63943..09227fff 100644
--- a/src/short-urls/ShortUrlsList.tsx
+++ b/src/short-urls/ShortUrlsList.tsx
@@ -33,7 +33,7 @@ const ShortUrlsList = (ShortUrlsTable: FC, SearchBar: FC) =
settings,
}: ShortUrlsListProps) => {
const serverId = getServerId(selectedServer);
- const initialOrderBy = settings.shortUrlList?.defaultOrdering ?? DEFAULT_SHORT_URLS_ORDERING;
+ const initialOrderBy = settings.shortUrlsList?.defaultOrdering ?? DEFAULT_SHORT_URLS_ORDERING;
const [ order, setOrder ] = useState(initialOrderBy);
const [{ tags, search, startDate, endDate }, toFirstPage ] = useShortUrlsQuery({ history, match, location });
const selectedTags = useMemo(() => tags?.split(',') ?? [], [ tags ]);
diff --git a/test/settings/Settings.test.tsx b/test/settings/Settings.test.tsx
index e8f3560c..0810cf8f 100644
--- a/test/settings/Settings.test.tsx
+++ b/test/settings/Settings.test.tsx
@@ -4,7 +4,7 @@ import NoMenuLayout from '../../src/common/NoMenuLayout';
describe('', () => {
const Component = () => null;
- const Settings = createSettings(Component, Component, Component, Component, Component);
+ const Settings = createSettings(Component, Component, Component, Component, Component, Component);
it('renders a no-menu layout with the expected settings sections', () => {
const wrapper = shallow();
@@ -13,6 +13,6 @@ describe('', () => {
expect(layout).toHaveLength(1);
expect(sections).toHaveLength(1);
- expect((sections.prop('items') as any[]).flat()).toHaveLength(5);
+ expect((sections.prop('items') as any[]).flat()).toHaveLength(6);
});
});
diff --git a/test/settings/ShortUrlsList.test.tsx b/test/settings/ShortUrlsList.test.tsx
new file mode 100644
index 00000000..3c1136de
--- /dev/null
+++ b/test/settings/ShortUrlsList.test.tsx
@@ -0,0 +1,48 @@
+import { shallow, ShallowWrapper } from 'enzyme';
+import { Mock } from 'ts-mockery';
+import { DEFAULT_SHORT_URLS_ORDERING, Settings, ShortUrlsListSettings } from '../../src/settings/reducers/settings';
+import { ShortUrlsList } from '../../src/settings/ShortUrlsList';
+import SortingDropdown from '../../src/utils/SortingDropdown';
+import { ShortUrlsOrder } from '../../src/short-urls/data';
+
+describe('', () => {
+ let wrapper: ShallowWrapper;
+ const setSettings = jest.fn();
+ const createWrapper = (shortUrlsList?: ShortUrlsListSettings) => {
+ wrapper = shallow(
+ ({ shortUrlsList })} setShortUrlsListSettings={setSettings} />,
+ );
+
+ return wrapper;
+ };
+
+ afterEach(() => wrapper?.unmount());
+ afterEach(jest.clearAllMocks);
+
+ it.each([
+ [ undefined, DEFAULT_SHORT_URLS_ORDERING ],
+ [{}, DEFAULT_SHORT_URLS_ORDERING ],
+ [{ defaultOrdering: {} }, {}],
+ [{ defaultOrdering: { field: 'longUrl', dir: 'DESC' } as ShortUrlsOrder }, { field: 'longUrl', dir: 'DESC' }],
+ [{ defaultOrdering: { field: 'visits', dir: 'ASC' } as ShortUrlsOrder }, { field: 'visits', dir: 'ASC' }],
+ ])('shows expected ordering', (shortUrlsList, expectedOrder) => {
+ const wrapper = createWrapper(shortUrlsList);
+ const dropdown = wrapper.find(SortingDropdown);
+
+ expect(dropdown.prop('order')).toEqual(expectedOrder);
+ });
+
+ it.each([
+ [ undefined, undefined ],
+ [ 'longUrl', 'ASC' ],
+ [ 'visits', undefined ],
+ [ 'title', 'DESC' ],
+ ])('invokes setSettings when ordering changes', (field, dir) => {
+ const wrapper = createWrapper();
+ const dropdown = wrapper.find(SortingDropdown);
+
+ expect(setSettings).not.toHaveBeenCalled();
+ dropdown.simulate('change', field, dir);
+ expect(setSettings).toHaveBeenCalledWith({ defaultOrdering: { field, dir } });
+ });
+});
diff --git a/test/settings/reducers/settings.test.ts b/test/settings/reducers/settings.test.ts
index 272e8905..09a7b14c 100644
--- a/test/settings/reducers/settings.test.ts
+++ b/test/settings/reducers/settings.test.ts
@@ -7,6 +7,7 @@ import reducer, {
setUiSettings,
setVisitsSettings,
setTagsSettings,
+ setShortUrlsListSettings,
} from '../../../src/settings/reducers/settings';
describe('settingsReducer', () => {
@@ -14,8 +15,8 @@ describe('settingsReducer', () => {
const shortUrlCreation = { validateUrls: false };
const ui = { theme: 'light' };
const visits = { defaultInterval: 'last30Days' };
- const shortUrlList = { defaultOrdering: DEFAULT_SHORT_URLS_ORDERING };
- const settings = { realTimeUpdates, shortUrlCreation, ui, visits, shortUrlList };
+ const shortUrlsList = { defaultOrdering: DEFAULT_SHORT_URLS_ORDERING };
+ const settings = { realTimeUpdates, shortUrlCreation, ui, visits, shortUrlsList };
describe('reducer', () => {
it('returns realTimeUpdates when action is SET_SETTINGS', () => {
@@ -70,4 +71,12 @@ describe('settingsReducer', () => {
expect(result).toEqual({ type: SET_SETTINGS, tags: { defaultMode: 'list' } });
});
});
+
+ describe('setShortUrlsListSettings', () => {
+ it('creates action to set short URLs list settings', () => {
+ const result = setShortUrlsListSettings({ defaultOrdering: DEFAULT_SHORT_URLS_ORDERING });
+
+ expect(result).toEqual({ type: SET_SETTINGS, shortUrlsList: { defaultOrdering: DEFAULT_SHORT_URLS_ORDERING } });
+ });
+ });
});
diff --git a/test/short-urls/ShortUrlsList.test.tsx b/test/short-urls/ShortUrlsList.test.tsx
index e6379e14..3602667e 100644
--- a/test/short-urls/ShortUrlsList.test.tsx
+++ b/test/short-urls/ShortUrlsList.test.tsx
@@ -41,7 +41,7 @@ describe('', () => {
shortUrlsList={shortUrlsList}
history={Mock.of({ push })}
selectedServer={Mock.of({ id: '1' })}
- settings={Mock.of({ shortUrlList: { defaultOrdering } })}
+ settings={Mock.of({ shortUrlsList: { defaultOrdering } })}
/>,
).dive(); // Dive is needed as this component is wrapped in a HOC