Update react-scripts & fix eslint

This commit is contained in:
Jannis Mattheis 2021-03-27 20:03:17 +01:00
parent 14d15abd94
commit 43c4eba0fa
35 changed files with 4224 additions and 3182 deletions

View File

@ -39,22 +39,22 @@ rules:
import/first: error
import/no-unused-modules: error
unicorn/no-abusive-eslint-disable: error
unicorn/no-abusive-eslint-disable: off
unicorn/no-array-instanceof: error
unicorn/no-unreadable-array-destructuring: error
unicorn/no-zero-fractions: error
react/jsx-key: error
react/jsx-pascal-case: error
react/destructuring-assignment: warn
react/function-component-definition: [error, {namedComponents: arrow-function, unnamedComponents: arrow-function}]
react/destructuring-assignment: off
react/function-component-definition: off
react/no-array-index-key: error
react/no-deprecated: error
react/no-deprecated: off
react/no-string-refs: error
react/no-this-in-sfc: error
react/no-typos: error
react/no-unknown-property: error
react/prefer-stateless-function: error
react/prefer-stateless-function: off
react/prop-types: off
jest/expect-expect: off
@ -65,18 +65,21 @@ rules:
"@typescript-eslint/await-thenable": error
"@typescript-eslint/no-unused-vars": error
"@typescript-eslint/no-use-before-define": off
"@typescript-eslint/no-unsafe-call": off
"@typescript-eslint/consistent-type-assertions": [error, {assertionStyle: as}]
"@typescript-eslint/no-extra-non-null-assertion": error
"@typescript-eslint/no-inferrable-types": error
"@typescript-eslint/no-this-alias": error
"@typescript-eslint/no-throw-literal": error
"@typescript-eslint/no-non-null-assertion": off
"@typescript-eslint/prefer-nullish-coalescing": error
"@typescript-eslint/prefer-optional-chain": error
"@typescript-eslint/prefer-readonly": error
"@typescript-eslint/prefer-readonly": off
"@typescript-eslint/unbound-method": error
"@typescript-eslint/no-empty-function": off
"@typescript-eslint/explicit-module-boundary-types": off
"@typescript-eslint/ban-ts-comment": off
"@typescript-eslint/no-floating-promises": off
"@typescript-eslint/no-unsafe-member-access": off
"@typescript-eslint/no-unsafe-return": off

View File

@ -32,7 +32,7 @@
"build": "react-scripts build",
"test": "react-scripts test --env=node",
"eject": "react-scripts eject",
"lint": "eslint \"src/*.{ts,tsx}\"",
"lint": "eslint \"src/**/*.{ts,tsx}\"",
"format": "prettier \"src/**/*.{ts,tsx}\" --write",
"testformat": "prettier \"src/**/*.{ts,tsx}\" --list-different"
},
@ -62,7 +62,7 @@
"get-port": "^5.1.1",
"prettier": "^2.1.1",
"puppeteer": "^5.3.0",
"react-scripts": "^3.4.3",
"react-scripts": "^4.0.3",
"rimraf": "^3.0.2",
"tree-kill": "^1.2.0",
"typescript": "4.0.2",

View File

@ -12,18 +12,16 @@ export class AppStore extends BaseStore<IApplication> {
super();
}
protected requestItems = (): Promise<IApplication[]> => {
return axios
protected requestItems = (): Promise<IApplication[]> =>
axios
.get<IApplication[]>(`${config.get('url')}application`)
.then((response) => response.data);
};
protected requestDelete = (id: number): Promise<void> => {
return axios.delete(`${config.get('url')}application/${id}`).then(() => {
protected requestDelete = (id: number): Promise<void> =>
axios.delete(`${config.get('url')}application/${id}`).then(() => {
this.onDelete();
return this.snack('Application deleted');
});
};
@action
public uploadImage = async (id: number, file: Blob): Promise<void> => {

View File

@ -72,8 +72,7 @@ class Applications extends Component<Stores<'appStore'>> {
</TableRow>
</TableHead>
<TableBody>
{apps.map((app: IApplication) => {
return (
{apps.map((app: IApplication) => (
<Row
key={app.id}
description={app.description}
@ -85,8 +84,7 @@ class Applications extends Component<Stores<'appStore'>> {
fEdit={() => (this.updateId = app.id)}
noDelete={app.internal}
/>
);
})}
))}
</TableBody>
</Table>
<input
@ -133,7 +131,7 @@ class Applications extends Component<Stores<'appStore'>> {
};
private onUploadImage = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files && e.target.files[0];
const file = e.target.files?.[0];
if (!file) {
return;
}

View File

@ -23,8 +23,12 @@ interface IState {
export default class UpdateDialog extends Component<IProps, IState> {
public state = {name: '', description: ''};
public componentWillMount() {
this.setState({name: this.props.initialName, description: this.props.initialDescription});
constructor(props: IProps) {
super(props);
this.state = {
name: props.initialName,
description: props.initialDescription,
};
}
public render() {

View File

@ -10,9 +10,8 @@ export class ClientStore extends BaseStore<IClient> {
super();
}
protected requestItems = (): Promise<IClient[]> => {
return axios.get<IClient[]>(`${config.get('url')}client`).then((response) => response.data);
};
protected requestItems = (): Promise<IClient[]> =>
axios.get<IClient[]>(`${config.get('url')}client`).then((response) => response.data);
protected requestDelete(id: number): Promise<void> {
return axios

View File

@ -64,8 +64,7 @@ class Clients extends Component<Stores<'clientStore'>> {
</TableRow>
</TableHead>
<TableBody>
{clients.map((client: IClient) => {
return (
{clients.map((client: IClient) => (
<Row
key={client.id}
name={client.name}
@ -73,8 +72,7 @@ class Clients extends Component<Stores<'clientStore'>> {
fEdit={() => (this.updateId = client.id)}
fDelete={() => (this.deleteId = client.id)}
/>
);
})}
))}
</TableBody>
</Table>
</Paper>

View File

@ -21,8 +21,11 @@ interface IState {
export default class UpdateDialog extends Component<IProps, IState> {
public state = {name: ''};
public componentWillMount() {
this.setState({name: this.props.initialName});
constructor(props: IProps) {
super(props);
this.state = {
name: props.initialName,
};
}
public render() {

View File

@ -38,9 +38,8 @@ export abstract class BaseStore<T extends HasID> implements IClearable {
return item;
};
public getByIDOrUndefined = (id: number): T | undefined => {
return this.items.find((hasId: HasID) => hasId.id === id);
};
public getByIDOrUndefined = (id: number): T | undefined =>
this.items.find((hasId: HasID) => hasId.id === id);
public getItems = (): T[] => this.items;

View File

@ -8,8 +8,7 @@ interface ConnectionErrorBannerProps {
message: string;
}
export const ConnectionErrorBanner = ({height, retry, message}: ConnectionErrorBannerProps) => {
return (
export const ConnectionErrorBanner = ({height, retry, message}: ConnectionErrorBannerProps) => (
<div
style={{
backgroundColor: '#e74c3c',
@ -26,4 +25,3 @@ export const ConnectionErrorBanner = ({height, retry, message}: ConnectionErrorB
</Typography>
</div>
);
};

View File

@ -9,15 +9,13 @@ const styles = () => ({
});
interface IProps extends WithStyles<'paper'> {
style?: object;
style?: React.CSSProperties;
}
const Container: React.SFC<IProps> = ({classes, children, style}) => {
return (
const Container: React.FC<IProps> = ({classes, children, style}) => (
<Paper elevation={6} className={classes.paper} style={style}>
{children}
</Paper>
);
};
export default withStyles(styles)(Container);

View File

@ -2,11 +2,11 @@ import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import React, {Component} from 'react';
import React, {Component, CSSProperties} from 'react';
interface IProps {
value: string;
style?: object;
style?: CSSProperties;
}
interface IState {

View File

@ -209,7 +209,7 @@ const ResponsiveButton: React.FC<{
id?: string;
onClick?: () => void;
icon: React.ReactNode;
}> = ({width, icon, children, label, ...rest}) => {
}> = ({width, icon, label, ...rest}) => {
if (width === 'xs' || width === 'sm') {
return <IconButton {...rest}>{icon}</IconButton>;
}

View File

@ -50,9 +50,8 @@ const themeMap: Record<ThemeKey, Theme> = {
}),
};
const isThemeKey = (value: string | null): value is ThemeKey => {
return value === 'light' || value === 'dark';
};
const isThemeKey = (value: string | null): value is ThemeKey =>
value === 'light' || value === 'dark';
@observer
class Layout extends React.Component<

View File

@ -52,8 +52,7 @@ class Navigation extends Component<
const userApps =
apps.length === 0
? null
: apps.map((app) => {
return (
: apps.map((app) => (
<Link
onClick={() => setNavOpen(false)}
className={`${classes.link} item`}
@ -63,8 +62,7 @@ class Navigation extends Component<
<ListItemText primary={app.name} />
</ListItem>
</Link>
);
});
));
const placeholderItems = [
<ListItem button disabled key={-1}>
@ -108,8 +106,7 @@ class Navigation extends Component<
const ResponsiveDrawer: React.FC<
DrawerProps & {navOpen: boolean; setNavOpen: (open: boolean) => void}
> = ({navOpen, setNavOpen, children, ...rest}) => {
return (
> = ({navOpen, setNavOpen, children, ...rest}) => (
<>
<Hidden smUp implementation="css">
<Drawer variant="temporary" open={navOpen} {...rest}>
@ -126,6 +123,5 @@ const ResponsiveDrawer: React.FC<
</Hidden>
</>
);
};
export default withStyles(styles, {withTheme: true})(inject('appStore')(Navigation));

View File

@ -12,7 +12,7 @@ import {observable} from 'mobx';
import ReactInfinite from 'react-infinite';
import {IMessage} from '../types';
interface IProps extends RouteComponentProps<{id: string}> {}
type IProps = RouteComponentProps<{id: string}>;
interface IState {
appId: number;
@ -121,8 +121,7 @@ class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>,
private deleteMessage = (message: IMessage) => () =>
this.props.messagesStore.removeSingle(message);
private renderMessage = (message: IMessage) => {
return (
private renderMessage = (message: IMessage) => (
<Message
key={message.id}
height={(height: number) => {
@ -138,7 +137,6 @@ class Messages extends Component<IProps & Stores<'messagesStore' | 'appStore'>,
extras={message.extras}
/>
);
};
private checkIfLoadMore() {
const {appId} = this.state;

View File

@ -50,7 +50,7 @@ export class MessagesStore {
);
state.messages.replace([...state.messages, ...pagedResult.messages]);
state.nextSince = pagedResult.paging.since || 0;
state.nextSince = pagedResult.paging.since ?? 0;
state.hasMore = 'next' in pagedResult.paging;
state.loaded = true;
this.loading = false;
@ -139,12 +139,10 @@ export class MessagesStore {
.getItems()
.reduce((all, app) => ({...all, [app.id]: app.image}), {});
return this.stateOf(appId, false).messages.map((message: IMessage) => {
return {
return this.stateOf(appId, false).messages.map((message: IMessage) => ({
...message,
image: appToImage[message.appid] || null,
};
});
}));
};
public get = createTransformer(this.getUnCached);

View File

@ -38,7 +38,7 @@ export class WebSocketStore {
setTimeout(() => this.listen(callback), 30000);
})
.catch((error: AxiosError) => {
if (error && error.response && error.response.status === 401) {
if (error?.response?.status === 401) {
this.snack('Could not authenticate with client token, logging out.');
}
});
@ -47,5 +47,5 @@ export class WebSocketStore {
this.ws = ws;
};
public close = () => this.ws && this.ws.close(1000, 'WebSocketStore#close');
public close = () => this.ws?.close(1000, 'WebSocketStore#close');
}

View File

@ -17,7 +17,7 @@ import Container from '../common/Container';
import {inject, Stores} from '../inject';
import {IPlugin} from '../types';
interface IProps extends RouteComponentProps<{id: string}> {}
type IProps = RouteComponentProps<{id: string}>;
interface IState {
displayText: string | null;
@ -122,7 +122,7 @@ interface IPanelWrapperProps {
icon?: React.ComponentType;
}
const PanelWrapper: React.SFC<IPanelWrapperProps> = ({
const PanelWrapper: React.FC<IPanelWrapperProps> = ({
name,
description,
refresh,
@ -175,7 +175,7 @@ class ConfigurerPanel extends Component<IConfigurerPanelProps, {unsavedChanges:
theme: 'material',
lineNumbers: true,
}}
onChange={(instance, data, value) => {
onChange={(_, _1, value) => {
let newConf: string | null = value;
if (value === this.props.initialConfig) {
newConf = null;
@ -195,6 +195,7 @@ class ConfigurerPanel extends Component<IConfigurerPanelProps, {unsavedChanges:
className="config-save"
onClick={() => {
const newConfig = this.state.unsavedChanges;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.props.save(newConfig!).then(() => {
this.setState({unsavedChanges: null});
});
@ -210,7 +211,7 @@ interface IDisplayerPanelProps {
pluginInfo: IPlugin;
displayText: string;
}
const DisplayerPanel: React.SFC<IDisplayerPanelProps> = ({pluginInfo, displayText}) => (
const DisplayerPanel: React.FC<IDisplayerPanelProps> = ({displayText}) => (
<Typography variant="body2">
<ReactMarkDown source={displayText} />
</Typography>

View File

@ -12,23 +12,16 @@ export class PluginStore extends BaseStore<IPlugin> {
super();
}
public requestConfig = (id: number): Promise<string> => {
return axios
.get(`${config.get('url')}plugin/${id}/config`)
.then((response) => response.data);
};
public requestConfig = (id: number): Promise<string> =>
axios.get(`${config.get('url')}plugin/${id}/config`).then((response) => response.data);
public requestDisplay = (id: number): Promise<string> => {
return axios
.get(`${config.get('url')}plugin/${id}/display`)
.then((response) => response.data);
};
public requestDisplay = (id: number): Promise<string> =>
axios.get(`${config.get('url')}plugin/${id}/display`).then((response) => response.data);
protected requestItems = (): Promise<IPlugin[]> => {
return axios.get<IPlugin[]>(`${config.get('url')}plugin`).then((response) => response.data);
};
protected requestItems = (): Promise<IPlugin[]> =>
axios.get<IPlugin[]>(`${config.get('url')}plugin`).then((response) => response.data);
protected requestDelete = (id: number): Promise<void> => {
protected requestDelete = (): Promise<void> => {
this.snack('Cannot delete plugin');
throw new Error('Cannot delete plugin');
};

View File

@ -39,8 +39,7 @@ class Plugins extends Component<Stores<'pluginStore'>> {
</TableRow>
</TableHead>
<TableBody>
{plugins.map((plugin: IPlugin) => {
return (
{plugins.map((plugin: IPlugin) => (
<Row
key={plugin.token}
id={plugin.id}
@ -54,8 +53,7 @@ class Plugins extends Component<Stores<'pluginStore'>> {
)
}
/>
);
})}
))}
</TableBody>
</Table>
</Paper>

View File

@ -26,19 +26,20 @@ const hiddenToken = '•••••••••••••••';
const $table = selector.table('#app-table');
const $dialog = selector.form('#app-dialog');
const hasApp = (name: string, description: string, row: number): (() => Promise<void>) => {
return async () => {
const hasApp = (
name: string,
description: string,
row: number
): (() => Promise<void>) => async () => {
expect(await innerText(page, $table.cell(row, Col.Name))).toBe(name);
expect(await innerText(page, $table.cell(row, Col.Token))).toBe(hiddenToken);
expect(await innerText(page, $table.cell(row, Col.Description))).toBe(description);
};
};
export const updateApp = (
const updateApp = (
id: number,
data: {name?: string; description?: string}
): (() => Promise<void>) => {
return async () => {
): (() => Promise<void>) => async () => {
await page.click($table.cell(id, Col.EditUpdate, '.edit'));
await page.waitForSelector($dialog.selector());
if (data.name) {
@ -54,17 +55,14 @@ export const updateApp = (
await page.click($dialog.button('.update'));
await waitToDisappear(page, $dialog.selector());
};
};
export const createApp = (name: string, description: string): (() => Promise<void>) => {
return async () => {
const createApp = (name: string, description: string): (() => Promise<void>) => async () => {
await page.click('#create-app');
await page.waitForSelector($dialog.selector());
await page.type($dialog.input('.name'), name);
await page.type($dialog.textarea('.description'), description);
await page.click($dialog.button('.create'));
};
};
describe('Application', () => {
it('does login', async () => await auth.login(page));

View File

@ -21,14 +21,11 @@ enum Col {
Delete = 4,
}
const hasClient = (name: string, row: number): (() => Promise<void>) => {
return async () => {
const hasClient = (name: string, row: number): (() => Promise<void>) => async () => {
expect(await innerText(page, $table.cell(row, Col.Name))).toBe(name);
};
};
export const updateClient = (id: number, data: {name?: string}): (() => Promise<void>) => {
return async () => {
const updateClient = (id: number, data: {name?: string}): (() => Promise<void>) => async () => {
await page.click($table.cell(id, Col.Edit, '.edit'));
await page.waitForSelector($dialog.selector());
if (data.name) {
@ -39,7 +36,6 @@ export const updateClient = (id: number, data: {name?: string}): (() => Promise<
await page.click($dialog.button('.update'));
await waitToDisappear(page, $dialog.selector());
};
};
const $table = selector.table('#client-table');
const $dialog = selector.form('#client-dialog');
@ -57,14 +53,12 @@ describe('Client', () => {
expect(await count(page, $table.rows())).toBe(1);
});
describe('create clients', () => {
const createClient = (name: string): (() => Promise<void>) => {
return async () => {
const createClient = (name: string): (() => Promise<void>) => async () => {
await page.click('#create-client');
await page.waitForSelector($dialog.selector());
await page.type($dialog.input('.name'), name);
await page.click($dialog.button('.create'));
};
};
it('phone', createClient('phone'));
it('desktop app', createClient('desktop app'));
});

View File

@ -44,11 +44,10 @@ describe('Messages', () => {
it('has url', async () => {
expect(page.url()).toContain('/');
});
const createApp = (name: string) => {
return axios
const createApp = (name: string) =>
axios
.post<IApplication>(`${gotify.url}/application`, {name}, axiosAuth)
.then((resp) => resp.data.token);
};
it('shows navigation', async () => {
await page.waitForSelector(naviId);
});
@ -121,11 +120,10 @@ describe('Messages', () => {
const backup2 = m('Backup done', 'Windows Server Backup finished (6.2GB).');
const backup3 = m('Backup done', 'Gotify Backup finished (0.1MB).');
const createMessage = (msg: Partial<IMessage>, token: string) => {
return axios.post<IMessage>(`${gotify.url}/message`, msg, {
const createMessage = (msg: Partial<IMessage>, token: string) =>
axios.post<IMessage>(`${gotify.url}/message`, msg, {
headers: {'X-Gotify-Key': token},
});
};
const expectMessages = async (toCheck: {
all: Msg[];

View File

@ -49,13 +49,10 @@ const toggleEnabled = async (id: number) => {
);
};
const pluginInfo = async (className: string) => {
return await innerText(page, `.plugin-info .${className} > span`);
};
const pluginInfo = async (className: string) =>
await innerText(page, `.plugin-info .${className} > span`);
const getDisplayer = async () => {
return await innerText(page, '.displayer');
};
const getDisplayer = async () => await innerText(page, '.displayer');
const hasReceivedMessage = async (title: RegExp, content: RegExp) => {
await page.click('#message-navigation a');

View File

@ -1,24 +1,18 @@
export const heading = () => {
return `main h4`;
};
export const heading = () => `main h4`;
export const table = (tableSelector: string) => {
return {
export const table = (tableSelector: string) => ({
selector: () => tableSelector,
rows: () => `${tableSelector} tbody tr`,
row: (index: number) => `${tableSelector} tbody tr:nth-child(${index})`,
cell: (index: number, col: number, suffix = '') =>
`${tableSelector} tbody tr:nth-child(${index}) td:nth-child(${col}) ${suffix}`,
};
};
});
export const form = (dialogSelector: string) => {
return {
export const form = (dialogSelector: string) => ({
selector: () => dialogSelector,
input: (selector: string) => `${dialogSelector} ${selector} input`,
textarea: (selector: string) => `${dialogSelector} ${selector} textarea`,
button: (selector: string) => `${dialogSelector} button${selector}`,
};
};
});
export const $confirmDialog = form('.confirm-dialog');

View File

@ -82,8 +82,8 @@ const testFilePath = (): string => {
return path.join(testBuildPath, filename);
};
const waitForGotify = (url: string): Promise<void> => {
return new Promise((resolve, err) => {
const waitForGotify = (url: string): Promise<void> =>
new Promise((resolve, err) => {
wait({resources: [url], timeout: 40000}, (error: string) => {
if (error) {
console.log(error);
@ -93,7 +93,6 @@ const waitForGotify = (url: string): Promise<void> => {
}
});
});
};
const buildGoPlugin = (filename: string, pluginPath: string): Promise<void> => {
process.stdout.write(`### Building Plugin ${pluginPath}\n`);

View File

@ -39,8 +39,7 @@ describe('User', () => {
name: string,
password: string,
isAdmin: boolean
): (() => Promise<void>) => {
return async () => {
): (() => Promise<void>) => async () => {
await page.click('#create-user');
await page.waitForSelector($dialog.selector());
await page.type($dialog.input('.name'), name);
@ -51,17 +50,18 @@ describe('User', () => {
await page.click($dialog.button('.save-create'));
await waitToDisappear(page, $dialog.selector());
};
};
it('nicories', createUser('nicories', '123', false));
it('jmattheis', createUser('jmattheis', 'noice', true));
it('dude', createUser('dude', '1', false));
});
const hasUser = (name: string, isAdmin: boolean, row: number): (() => Promise<void>) => {
return async () => {
const hasUser = (
name: string,
isAdmin: boolean,
row: number
): (() => Promise<void>) => async () => {
expect(await innerText(page, $table.cell(row, Col.Name))).toBe(name);
expect(await innerText(page, $table.cell(row, Col.Admin))).toBe(isAdmin ? 'Yes' : 'No');
};
};
describe('has created users', () => {
it('has four users', async () => {
@ -131,10 +131,10 @@ describe('User', () => {
it('does logout', async () => await auth.logout(page));
it('can login with new password (admin)', async () =>
await auth.login(page, 'admin', 'changed'));
it('does logout', async () => await auth.logout(page));
it('does logout admin', async () => await auth.logout(page));
it('can login with nicolas', async () => await auth.login(page, 'nicolas', '123'));
it('does logout', async () => await auth.logout(page));
it('does logout nicolas', async () => await auth.logout(page));
it('can login with jmattheis', async () => await auth.login(page, 'jmattheis', 'unicorn'));
it('does logout', async () => await auth.logout(page));
it('does logout jmattheis', async () => await auth.logout(page));
});

View File

@ -4,7 +4,8 @@ export const innerText = async (page: ElementHandle | Page, selector: string): P
const element = await page.$(selector);
const handle = await element!.getProperty('innerText');
const value = await handle.jsonValue();
return (value as object).toString().trim();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (value as any).toString().trim();
};
export const clickByText = async (page: Page, selector: string, text: string): Promise<void> => {
@ -21,42 +22,32 @@ export const clickByText = async (page: Page, selector: string, text: string): P
);
};
export const count = async (page: Page, selector: string): Promise<number> => {
return page.$$(selector).then((elements) => elements.length);
};
export const count = async (page: Page, selector: string): Promise<number> =>
page.$$(selector).then((elements) => elements.length);
export const waitToDisappear = async (page: Page, selector: string): Promise<JSHandle> => {
return page.waitForFunction(
(_selector: string) => !document.querySelector(_selector),
{},
selector
);
};
export const waitToDisappear = async (page: Page, selector: string): Promise<JSHandle> =>
page.waitForFunction((_selector: string) => !document.querySelector(_selector), {}, selector);
export const waitForCount = async (
page: Page,
selector: string,
amount: number
): Promise<JSHandle> => {
return page.waitForFunction(
): Promise<JSHandle> =>
page.waitForFunction(
(_selector: string, _amount: number) =>
document.querySelectorAll(_selector).length === _amount,
{},
selector,
amount
);
};
export const waitForExists = async (page: Page, selector: string, text: string): Promise<void> => {
text = text.toLowerCase();
await page.waitForFunction(
(_selector: string, _text: string) => {
return (
(_selector: string, _text: string) =>
Array.from(document.querySelectorAll(_selector)).filter(
(element) => element.textContent!.toLowerCase().trim() === _text
).length > 0
);
},
).length > 0,
{},
selector,
text
@ -67,7 +58,6 @@ export const clearField = async (element: ElementHandle | Page, selector: string
const elementHandle = await element.$(selector);
if (!elementHandle) {
fail();
return;
}
await elementHandle.click();
await elementHandle.focus();

View File

@ -5,5 +5,5 @@ declare module 'react-timeago' {
date: string;
}
export default class TimeAgo extends React.Component<ITimeAgoProps, any> {}
export default class TimeAgo extends React.Component<ITimeAgoProps, unknown> {}
}

View File

@ -25,9 +25,9 @@ interface IState {
export default class AddEditDialog extends Component<IProps, IState> {
public state = {
name: '',
name: this.props.name ?? '',
pass: '',
admin: false,
admin: this.props.admin ?? false,
};
public render() {
@ -107,11 +107,6 @@ export default class AddEditDialog extends Component<IProps, IState> {
);
}
public componentWillMount() {
const {name, admin} = this.props;
this.setState({...this.state, name: name || '', admin: admin || false});
}
private handleChange(propertyName: string, event: ChangeEvent<HTMLInputElement>) {
const state = this.state;
state[propertyName] = event.target.value;

View File

@ -10,9 +10,8 @@ export class UserStore extends BaseStore<IUser> {
super();
}
protected requestItems = (): Promise<IUser[]> => {
return axios.get<IUser[]>(`${config.get('url')}user`).then((response) => response.data);
};
protected requestItems = (): Promise<IUser[]> =>
axios.get<IUser[]>(`${config.get('url')}user`).then((response) => response.data);
protected requestDelete(id: number): Promise<void> {
return axios

View File

@ -90,8 +90,7 @@ class Users extends Component<WithStyles<'wrapper'> & Stores<'userStore'>> {
</TableRow>
</TableHead>
<TableBody>
{users.map((user: IUser) => {
return (
{users.map((user: IUser) => (
<UserRow
key={user.id}
name={user.name}
@ -99,8 +98,7 @@ class Users extends Component<WithStyles<'wrapper'> & Stores<'userStore'>> {
fDelete={() => (this.deleteId = user.id)}
fEdit={() => (this.editId = user.id)}
/>
);
})}
))}
</TableBody>
</Table>
</Paper>

View File

@ -28,7 +28,8 @@
"noEmit": true,
"module": "esnext",
"resolveJsonModule": true,
"keyofStringsOnly": true
"keyofStringsOnly": true,
"noFallthroughCasesInSwitch": true
},
"exclude": [
"node_modules",

File diff suppressed because it is too large Load Diff