Skip to content

Commit ef6ad9b

Browse files
committed
Modernise callbacks + various simplifications
- swap useCallback and various helpers with useEvent - remove memoisation of some leaf components where it is not helpful - disable expensive graphical effects when running E2E tests to improve performance - remove explicit void returns - remove crypto patch for node 16 (unsupported now)
1 parent efbb895 commit ef6ad9b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+545
-812
lines changed

backend/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { logError, logInfo } from './log';
1212
let activeApp: App | null = null;
1313
const server = createServer();
1414

15-
function startServer(): void {
15+
function startServer() {
1616
server.listen(config.port, config.serverBindAddress, () => {
1717
logInfo(`Available at http://localhost:${config.port}/`);
1818
logInfo('Press Ctrl+C to stop');

backend/src/routers/ForwardingRouter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Router } from 'websocket-express';
2-
import type { RequestHandler } from 'http-proxy-middleware';
2+
import { type RequestHandler } from 'http-proxy-middleware';
33

44
const filteredLogger = {
55
info: () => null,

backend/src/routers/StaticRouter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class StaticRouter extends Router {
2626
serveStatic: {
2727
cacheControl: false,
2828
redirect: false,
29-
setHeaders: (res, filePath): void => {
29+
setHeaders: (res, filePath) => {
3030
if (VERSIONED_FILE.test(filePath)) {
3131
res.setHeader('cache-control', VERSIONED_CACHE_CONTROL);
3232
} else {

backend/src/services/RetroService.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ChangeListener {
1919
) => void;
2020

2121
public constructor() {
22-
this.onChange = (message: ChangeInfo<Spec<Retro>>, meta: unknown): void => {
22+
this.onChange = (message: ChangeInfo<Spec<Retro>>, meta: unknown) => {
2323
this.messages.push({ message, meta });
2424
};
2525
}

backend/src/services/RetroService.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { extractRetro } from '../helpers/jsonParsers';
1313
const VALID_SLUG = /^[a-z0-9][a-z0-9_\-]*$/;
1414
const MAX_SLUG_LENGTH = 64;
1515

16-
function validateSlug(slug: string): void {
16+
function validateSlug(slug: string) {
1717
if (slug.length > MAX_SLUG_LENGTH) {
1818
throw new Error('URL is too long');
1919
}

backend/src/tokens/TokenManager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const asyncGenerateKeyPair = promisify(
1515
type: string,
1616
options: Record<string, unknown>,
1717
callback: GenerateKeyPairCallback,
18-
): void =>
18+
) =>
1919
generateKeyPair(
2020
type as any,
2121
options as any,

e2e/helpers/downloads.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ export async function waitForFile(
2222
try {
2323
return await readFile(fileName, { encoding: 'utf-8' });
2424
} catch (e) {
25-
await new Promise((res): void => {
26-
setTimeout(res, 100);
27-
});
25+
await new Promise((res) => setTimeout(res, 100));
2826
}
2927
} while (Date.now() < exp);
3028

e2e/helpers/selenium.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const headless = process.env['HEADLESS'] !== 'false';
1111

1212
const width = 900; // ensure non-mobile display
1313
const height = 500;
14+
const headlessUserAgent = 'HeadlessEndToEndTest';
1415

1516
const chromeOptions = new ChromeOptions();
1617
chromeOptions.windowSize({ width, height });
@@ -34,8 +35,13 @@ if (process.env['DOCKER'] === 'true') {
3435
}
3536

3637
if (headless) {
37-
chromeOptions.addArguments('--headless=new');
38-
firefoxOptions.addArguments('--headless');
38+
chromeOptions.addArguments(
39+
'--headless=new',
40+
'--user-agent=' + headlessUserAgent,
41+
);
42+
firefoxOptions
43+
.addArguments('--headless')
44+
.setPreference('general.useragent.override', headlessUserAgent);
3945
}
4046

4147
const logPrefs = new logging.Preferences();

frontend/src/api/PasswordService.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export class PasswordService {
55

66
public async countPasswordBreaches(password: string): Promise<number> {
77
const passwordHash = (await sha1(password)).toUpperCase();
8-
const key = passwordHash.substr(0, 5);
9-
const rest = passwordHash.substr(5);
8+
const key = passwordHash.substring(0, 5);
9+
const rest = passwordHash.substring(5);
1010

1111
const response = await fetch(`${this.apiBase}/password-check/${key}`);
1212
const lines = (await response.text()).split('\n');

frontend/src/api/RetroTracker.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,33 @@ class RetroWrapper {
4343
) {
4444
this.retroStateCallbacks = new Set();
4545

46-
const setState = (state: RetroState): void => {
46+
const setState = (state: RetroState) => {
4747
this.latestState = state;
4848
this.retroStateCallbacks.forEach((fn) => fn(state));
4949
};
5050

5151
this.reducer = SharedReducer.for<Retro>(
5252
`${wsBase}/retros/${retroId}`,
53-
(data): void => setState({ retro: data, error: null }),
53+
(data) => setState({ retro: data, error: null }),
5454
)
5555
.withReducer(context)
5656
.withToken(retroToken)
57-
.withErrorHandler((err): void => setState({ retro: null, error: err }))
57+
.withErrorHandler((err) => setState({ retro: null, error: err }))
5858
.build();
5959
}
6060

61-
public addStateCallback(stateCallback: RetroStateCallback): void {
61+
public addStateCallback(stateCallback: RetroStateCallback) {
6262
this.retroStateCallbacks.add(stateCallback);
6363
if (this.latestState) {
6464
stateCallback(this.latestState);
6565
}
6666
}
6767

68-
public removeStateCallback(stateCallback: RetroStateCallback): void {
68+
public removeStateCallback(stateCallback: RetroStateCallback) {
6969
this.retroStateCallbacks.delete(stateCallback);
7070
}
7171

72-
public close(): void {
72+
public close() {
7373
this.reducer.close();
7474
}
7575
}
@@ -84,7 +84,7 @@ export class RetroTracker {
8484
this.subscriptionTracker = new SubscriptionTracker(
8585
({ retroId, retroToken }): RetroWrapper =>
8686
new RetroWrapper(apiBase, wsBase, retroId, retroToken),
87-
(service): void => service.close(),
87+
(service) => service.close(),
8888
);
8989
}
9090

@@ -100,7 +100,7 @@ export class RetroTracker {
100100
sub.service.addStateCallback(retroStateCallback);
101101

102102
return {
103-
unsubscribe: (): void => {
103+
unsubscribe: () => {
104104
sub.service.removeStateCallback(retroStateCallback);
105105
sub.unsubscribe().catch((e) => {
106106
console.warn(`Failed to unsubscribe from retro ${retroId}`, e);

frontend/src/api/SlugTracker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ export class SlugTracker {
4747
return this.storage.get(slug).observable;
4848
}
4949

50-
public set(slug: string, id: string): void {
50+
public set(slug: string, id: string) {
5151
this.storage.get(slug).subject.next(id);
5252
}
5353

54-
public remove(slug: string): void {
54+
public remove(slug: string) {
5555
this.storage.remove(slug);
5656
}
5757

frontend/src/api/__mocks__/api.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ class FakeRetroTracker {
2020

2121
private expectedRetroToken: string | null = null;
2222

23-
public dispatch = (): void => undefined;
23+
public dispatch = () => undefined;
2424

25-
public setExpectedToken(retroToken: string): void {
25+
public setExpectedToken(retroToken: string) {
2626
this.expectedRetroToken = retroToken;
2727
}
2828

29-
public setServerData(retroId: string, serverData: Partial<RetroState>): void {
29+
public setServerData(retroId: string, serverData: Partial<RetroState>) {
3030
this.data.set(retroId, {
3131
retro: null,
3232
error: null,
@@ -55,7 +55,7 @@ class FakeRetroTracker {
5555
retroStateCallback({ ...serverData });
5656

5757
return {
58-
unsubscribe: (): void => {
58+
unsubscribe: () => {
5959
this.subscribed -= 1;
6060
},
6161
};
@@ -67,15 +67,15 @@ class FakeArchiveTracker {
6767

6868
private expectedRetroToken: string | null = null;
6969

70-
public setExpectedToken(retroToken: string): void {
70+
public setExpectedToken(retroToken: string) {
7171
this.expectedRetroToken = retroToken;
7272
}
7373

7474
public setServerData(
7575
retroId: string,
7676
archiveId: string,
7777
archive: RetroArchive,
78-
): void {
78+
) {
7979
if (!this.data.has(retroId)) {
8080
this.data.set(retroId, new Map());
8181
}
@@ -131,7 +131,7 @@ class FakeUserTokenService {
131131

132132
private userToken: string | null = null;
133133

134-
public setServerData(userToken: string): void {
134+
public setServerData(userToken: string) {
135135
this.userToken = userToken;
136136
}
137137

@@ -153,7 +153,7 @@ class FakeRetroTokenService {
153153

154154
private data = new Map<string, string>();
155155

156-
public setServerData(retroId: string, retroToken: string): void {
156+
public setServerData(retroId: string, retroToken: string) {
157157
this.data.set(retroId, retroToken);
158158
}
159159

@@ -196,7 +196,7 @@ class FakeRetroService {
196196

197197
private id: string | null = null;
198198

199-
public setServerData(retroId: string): void {
199+
public setServerData(retroId: string) {
200200
this.id = retroId;
201201
}
202202

frontend/src/api/reducer.ts

-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
import React from 'react';
21
import listCommands from 'json-immutability-helper/commands/list';
32
import { context as defaultContext, type Spec } from 'json-immutability-helper';
4-
import { makeHooks } from 'json-immutability-helper/helpers/hooks';
53

64
export type { Spec };
75

86
export const context = defaultContext.with(listCommands);
9-
10-
export const { useEvent, useScopedReducer } = makeHooks(context, React);

frontend/src/components/RetroRouter.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function replaceSlug(
3737
setLocation: SetLocation,
3838
newSlug: string,
3939
retroId: string,
40-
): void {
40+
) {
4141
const oldSlug = RETRO_SLUG_PATH.exec(oldPath)?.[1];
4242
if (!oldSlug || oldSlug === newSlug) {
4343
return;
@@ -46,7 +46,7 @@ function replaceSlug(
4646
slugTracker.set(newSlug, retroId);
4747
const oldPrefix = `/retros/${oldSlug}`;
4848
const newPrefix = `/retros/${newSlug}`;
49-
const newPath = newPrefix + oldPath.substr(oldPrefix.length);
49+
const newPath = newPrefix + oldPath.substring(oldPrefix.length);
5050
setLocation(newPath, { replace: true });
5151
}
5252

@@ -83,7 +83,7 @@ function useRetroReducer(
8383
(data: RetroState) => nonce.check(myNonce) && setRetroState(data),
8484
(err: RetroError) => nonce.check(myNonce) && setError(err),
8585
);
86-
return (): void => subscription.unsubscribe();
86+
return () => subscription.unsubscribe();
8787
}, [
8888
retroTracker,
8989
setRetroState,

frontend/src/components/archive-list/ArchiveListPage.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,7 @@ export const ArchiveListPage = memo(({ retroToken, retro }: PropsT) => {
2222
<Loader
2323
error={archivesError}
2424
Component={ArchiveList}
25-
componentProps={
26-
archives
27-
? {
28-
slug: retro.slug,
29-
archives,
30-
}
31-
: null
32-
}
25+
componentProps={archives ? { slug: retro.slug, archives } : null}
3326
/>
3427
<div className="extra-links">
3528
<ApiDownload

frontend/src/components/archive/ArchivePage.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export const ArchivePage = memo(
4444
group,
4545
archive: true,
4646
archiveTime: archive.created,
47-
onComplete: (): void => undefined,
47+
onComplete: () => undefined,
4848
}
4949
: null
5050
}

frontend/src/components/attachments/giphy/GiphyButton.tsx

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { useState, useCallback, memo } from 'react';
1+
import { useState, memo } from 'react';
22
import { type RetroItemAttachment } from '../../../shared/api-entities';
3+
import { useEvent } from '../../../hooks/useEvent';
34
import { Popup } from '../../common/Popup';
45
import { WrappedButton } from '../../common/WrappedButton';
5-
import { useBoundCallback } from '../../../hooks/useBoundCallback';
66
import { GiphyPopup } from './GiphyPopup';
77

88
interface PropsT {
@@ -13,15 +13,12 @@ interface PropsT {
1313
export const GiphyButton = memo(
1414
({ defaultAttachment = null, onChange }: PropsT) => {
1515
const [visible, setVisible] = useState(false);
16-
const show = useBoundCallback(setVisible, true);
17-
const hide = useBoundCallback(setVisible, false);
18-
const handleSave = useCallback(
19-
(newAttachment: RetroItemAttachment | null) => {
20-
hide();
21-
onChange(newAttachment);
22-
},
23-
[hide, onChange],
24-
);
16+
const show = useEvent(() => setVisible(true));
17+
const hide = useEvent(() => setVisible(false));
18+
const handleSave = useEvent((newAttachment: RetroItemAttachment | null) => {
19+
hide();
20+
onChange(newAttachment);
21+
});
2522

2623
let popup = null;
2724
if (visible) {

frontend/src/components/attachments/giphy/GiphyPopup.tsx

+14-19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { useState, useCallback, memo, SyntheticEvent } from 'react';
1+
import { useState, memo, SyntheticEvent } from 'react';
22
import { type RetroItemAttachment } from '../../../shared/api-entities';
33
import { WrappedButton } from '../../common/WrappedButton';
44
import { Input } from '../../common/Input';
5-
import { useBoundCallback } from '../../../hooks/useBoundCallback';
65
import { useNonce } from '../../../hooks/useNonce';
76
import { giphyService } from '../../../api/api';
87
import { type GifInfo } from '../../../api/GiphyService';
@@ -19,33 +18,29 @@ export const GiphyPopup = memo(
1918
const [query, setQuery] = useState('');
2019
const [options, setOptions] = useState<GifInfo[]>([]);
2120

22-
const handleDelete = useBoundCallback(onConfirm, null);
2321
const deleteButton = defaultAttachment ? (
24-
<WrappedButton onClick={handleDelete}>Remove</WrappedButton>
22+
<WrappedButton onClick={() => onConfirm(null)}>Remove</WrappedButton>
2523
) : null;
2624

2725
const loadNonce = useNonce();
28-
const loadOptions = useCallback(
29-
async (e: SyntheticEvent) => {
30-
e.preventDefault();
31-
e.stopPropagation();
32-
const nonce = loadNonce.next();
33-
setOptions([]);
26+
const loadOptions = async (e: SyntheticEvent) => {
27+
e.preventDefault();
28+
e.stopPropagation();
29+
const nonce = loadNonce.next();
30+
setOptions([]);
3431

35-
const gifs = await giphyService.search(query);
36-
if (!loadNonce.check(nonce)) {
37-
return;
38-
}
32+
const gifs = await giphyService.search(query);
33+
if (!loadNonce.check(nonce)) {
34+
return;
35+
}
3936

40-
setOptions(gifs);
41-
},
42-
[loadNonce, query],
43-
);
37+
setOptions(gifs);
38+
};
4439

4540
const optionElements = options.map(({ small, medium }) => (
4641
<WrappedButton
4742
key={medium}
48-
onClick={(): void => onConfirm({ type: 'giphy', url: medium })}
43+
onClick={() => onConfirm({ type: 'giphy', url: medium })}
4944
>
5045
<img
5146
src={small}

0 commit comments

Comments
 (0)