mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Remove more ovbious ramda helper usages
This commit is contained in:
parent
8699eaca32
commit
7ba78fd919
8 changed files with 25 additions and 29 deletions
|
@ -1,7 +1,6 @@
|
||||||
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useElementRef, useToggle } from '@shlinkio/shlink-frontend-kit';
|
import { useElementRef, useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||||
import { complement } from 'ramda';
|
|
||||||
import type { ChangeEvent, PropsWithChildren } from 'react';
|
import type { ChangeEvent, PropsWithChildren } from 'react';
|
||||||
import { useCallback, useRef, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||||
|
@ -27,8 +26,8 @@ type ImportServersBtnDeps = {
|
||||||
ServersImporter: ServersImporter
|
ServersImporter: ServersImporter
|
||||||
};
|
};
|
||||||
|
|
||||||
const serversFiltering = (servers: ServerData[]) =>
|
const serversInclude = (servers: ServerData[], { url, apiKey }: ServerData) =>
|
||||||
({ url, apiKey }: ServerData) => servers.some((server) => server.url === url && server.apiKey === apiKey);
|
servers.some((server) => server.url === url && server.apiKey === apiKey);
|
||||||
|
|
||||||
const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBtnDeps> = ({
|
const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBtnDeps> = ({
|
||||||
createServers,
|
createServers,
|
||||||
|
@ -56,7 +55,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
||||||
serversToCreate.current = newServers;
|
serversToCreate.current = newServers;
|
||||||
|
|
||||||
const existingServers = Object.values(servers);
|
const existingServers = Object.values(servers);
|
||||||
const dupServers = newServers.filter(serversFiltering(existingServers));
|
const dupServers = newServers.filter((server) => serversInclude(existingServers, server));
|
||||||
const hasDuplicatedServers = !!dupServers.length;
|
const hasDuplicatedServers = !!dupServers.length;
|
||||||
|
|
||||||
!hasDuplicatedServers ? create(newServers) : setDuplicatedServers(dupServers);
|
!hasDuplicatedServers ? create(newServers) : setDuplicatedServers(dupServers);
|
||||||
|
@ -75,7 +74,7 @@ const ImportServersBtn: FCWithDeps<ImportServersBtnConnectProps, ImportServersBt
|
||||||
hideModal();
|
hideModal();
|
||||||
}, [create, hideModal, serversToCreate]);
|
}, [create, hideModal, serversToCreate]);
|
||||||
const createNonDuplicatedServers = useCallback(() => {
|
const createNonDuplicatedServers = useCallback(() => {
|
||||||
create(serversToCreate.current.filter(complement(serversFiltering(duplicatedServers))));
|
create(serversToCreate.current.filter((server) => !serversInclude(duplicatedServers, server)));
|
||||||
hideModal();
|
hideModal();
|
||||||
}, [create, duplicatedServers, hideModal]);
|
}, [create, duplicatedServers, hideModal]);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { values } from 'ramda';
|
|
||||||
import type { JsonToCsv } from '../../utils/helpers/csvjson';
|
import type { JsonToCsv } from '../../utils/helpers/csvjson';
|
||||||
import { saveCsv } from '../../utils/helpers/files';
|
import { saveCsv } from '../../utils/helpers/files';
|
||||||
import type { LocalStorage } from '../../utils/services/LocalStorage';
|
import type { LocalStorage } from '../../utils/services/LocalStorage';
|
||||||
|
@ -15,7 +14,7 @@ export class ServersExporter {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public readonly exportServers = async () => {
|
public readonly exportServers = async () => {
|
||||||
const servers = values(this.storage.get<ServersMap>('servers') ?? {}).map(serverWithIdToServerData);
|
const servers = Object.values(this.storage.get<ServersMap>('servers') ?? {}).map(serverWithIdToServerData);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const csv = this.jsonToCsv(servers);
|
const csv = this.jsonToCsv(servers);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import type Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import { prop } from 'ramda';
|
|
||||||
import type { ConnectDecorator } from '../../container/types';
|
import type { ConnectDecorator } from '../../container/types';
|
||||||
import { CreateServerFactory } from '../CreateServer';
|
import { CreateServerFactory } from '../CreateServer';
|
||||||
import { DeleteServerButtonFactory } from '../DeleteServerButton';
|
import { DeleteServerButtonFactory } from '../DeleteServerButton';
|
||||||
|
@ -70,5 +69,5 @@ export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
|
|
||||||
// Reducers
|
// Reducers
|
||||||
bottle.serviceFactory('selectedServerReducerCreator', selectedServerReducerCreator, 'selectServer');
|
bottle.serviceFactory('selectedServerReducerCreator', selectedServerReducerCreator, 'selectServer');
|
||||||
bottle.serviceFactory('selectedServerReducer', prop('reducer'), 'selectedServerReducerCreator');
|
bottle.serviceFactory('selectedServerReducer', (obj) => obj.reducer, 'selectedServerReducerCreator');
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { AsyncThunkPayloadCreator } from '@reduxjs/toolkit';
|
import type { AsyncThunkPayloadCreator } from '@reduxjs/toolkit';
|
||||||
import { createAsyncThunk as baseCreateAsyncThunk } from '@reduxjs/toolkit';
|
import { createAsyncThunk as baseCreateAsyncThunk } from '@reduxjs/toolkit';
|
||||||
import { identity } from 'ramda';
|
|
||||||
import type { ShlinkState } from '../../container/types';
|
import type { ShlinkState } from '../../container/types';
|
||||||
|
|
||||||
export const createAsyncThunk = <Returned, ThunkArg>(
|
export const createAsyncThunk = <Returned, ThunkArg>(
|
||||||
|
@ -9,5 +8,5 @@ export const createAsyncThunk = <Returned, ThunkArg>(
|
||||||
) => baseCreateAsyncThunk(
|
) => baseCreateAsyncThunk(
|
||||||
typePrefix,
|
typePrefix,
|
||||||
payloadCreator,
|
payloadCreator,
|
||||||
{ serializeError: identity },
|
{ serializeError: (e) => e },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
import { compare } from 'compare-versions';
|
import { compare } from 'compare-versions';
|
||||||
import { identity, isEmpty, isNil, memoizeWith } from 'ramda';
|
import { memoizeWith } from 'ramda';
|
||||||
|
|
||||||
export type Empty = null | undefined | '' | never[];
|
export type Empty = null | undefined | '' | never[];
|
||||||
|
|
||||||
const hasValue = <T>(value: T | Empty): value is T => !isNil(value) && !isEmpty(value);
|
const isEmpty = (value: Exclude<any, undefined | null>): boolean => (
|
||||||
|
(Array.isArray(value) && value.length === 0)
|
||||||
|
|| (typeof value === 'string' && value === '')
|
||||||
|
|| (typeof value === 'object' && Object.keys(value).length === 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const hasValue = <T>(value: T | Empty): value is T => value !== undefined && value !== null && !isEmpty(value);
|
||||||
|
|
||||||
type SemVerPatternFragment = `${bigint | '*'}`;
|
type SemVerPatternFragment = `${bigint | '*'}`;
|
||||||
|
|
||||||
|
@ -29,7 +35,7 @@ export const versionMatch = (versionToMatch: SemVer | Empty, { maxVersion, minVe
|
||||||
return matchesMaxVersion && matchesMinVersion;
|
return matchesMaxVersion && matchesMinVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
const versionIsValidSemVer = memoizeWith(identity, (version: string): version is SemVer => {
|
const versionIsValidSemVer = memoizeWith((v) => v, (version: string): version is SemVer => {
|
||||||
try {
|
try {
|
||||||
return compare(version, version, '=');
|
return compare(version, version, '=');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
import { pipe, range } from 'ramda';
|
import { range } from 'ramda';
|
||||||
import type { SyntheticEvent } from 'react';
|
import type { SyntheticEvent } from 'react';
|
||||||
|
|
||||||
type Optional<T> = T | null | undefined;
|
export const handleEventPreventingDefault = <T>(handler: () => T) => (e: SyntheticEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
export type OptionalString = Optional<string>;
|
handler();
|
||||||
|
};
|
||||||
export const handleEventPreventingDefault = <T>(handler: () => T) => pipe(
|
|
||||||
(e: SyntheticEvent) => e.preventDefault(),
|
|
||||||
handler,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const rangeOf = <T>(size: number, mappingFn: (value: number) => T, startAt = 1): T[] =>
|
export const rangeOf = <T>(size: number, mappingFn: (value: number) => T, startAt = 1): T[] =>
|
||||||
range(startAt, size + 1).map(mappingFn);
|
range(startAt, size + 1).map(mappingFn);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
import { values } from 'ramda';
|
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import type { ServersMap } from '../../src/servers/data';
|
import type { ServersMap } from '../../src/servers/data';
|
||||||
import { ServersDropdown } from '../../src/servers/ServersDropdown';
|
import { ServersDropdown } from '../../src/servers/ServersDropdown';
|
||||||
|
@ -28,7 +27,7 @@ describe('<ServersDropdown />', () => {
|
||||||
|
|
||||||
await user.click(screen.getByText('Servers'));
|
await user.click(screen.getByText('Servers'));
|
||||||
const items = screen.getAllByRole('menuitem');
|
const items = screen.getAllByRole('menuitem');
|
||||||
expect(items).toHaveLength(values(fallbackServers).length + 1);
|
expect(items).toHaveLength(Object.values(fallbackServers).length + 1);
|
||||||
expect(items[0]).toHaveTextContent('foo');
|
expect(items[0]).toHaveTextContent('foo');
|
||||||
expect(items[1]).toHaveTextContent('bar');
|
expect(items[1]).toHaveTextContent('bar');
|
||||||
expect(items[2]).toHaveTextContent('baz');
|
expect(items[2]).toHaveTextContent('baz');
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
import { dissoc, values } from 'ramda';
|
|
||||||
import type { RegularServer, ServersMap, ServerWithId } from '../../../src/servers/data';
|
import type { RegularServer, ServersMap, ServerWithId } from '../../../src/servers/data';
|
||||||
import {
|
import {
|
||||||
createServers,
|
createServers,
|
||||||
|
@ -101,17 +100,17 @@ describe('serversReducer', () => {
|
||||||
|
|
||||||
describe('createServers', () => {
|
describe('createServers', () => {
|
||||||
it('returns expected action', () => {
|
it('returns expected action', () => {
|
||||||
const newServers = values(list);
|
const newServers = Object.values(list);
|
||||||
const { payload } = createServers(newServers);
|
const { payload } = createServers(newServers);
|
||||||
|
|
||||||
expect(payload).toEqual(list);
|
expect(payload).toEqual(list);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('generates an id for every provided server if they do not have it', () => {
|
it('generates an id for every provided server if they do not have it', () => {
|
||||||
const servers = values(list).map(dissoc('id'));
|
const servers = Object.values(list).map(({ id, ...rest }) => rest);
|
||||||
const { payload } = createServers(servers);
|
const { payload } = createServers(servers);
|
||||||
|
|
||||||
expect(values(payload).every(({ id }) => !!id)).toEqual(true);
|
expect(Object.values(payload).every(({ id }) => !!id)).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue