Skip to content

Commit c0c4c22

Browse files
committed
add async functions to better handle loading status
1 parent 0e90f0b commit c0c4c22

File tree

3 files changed

+103
-69
lines changed

3 files changed

+103
-69
lines changed

src/renderer/components/TagSelector.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ const TagSelector: FC<TagSelectorProps> = ({ tags, onChangeTags }) => {
3232
options={tagOptions}
3333
value={tags || []}
3434
onChange={(_, arr) => {
35-
console.log('CHANGE TAGS');
3635
saveTags(arr);
3736
}}
3837
renderInput={(params) => (

src/renderer/pages/LoadForm.tsx

+66-68
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { ipcRenderer } from 'electron';
1414
import { defaults, isEqual } from 'lodash';
1515
import { enqueueSnackbar } from 'notistack';
16-
import React, { FC, useEffect } from 'react';
16+
import React, { FC, useEffect, useState } from 'react';
1717
import { useLocalStorage } from 'usehooks-ts';
1818

1919
import {
@@ -26,6 +26,7 @@ import {
2626
TOAST_LENGTH,
2727
VIEW_CONNECTION_LIST,
2828
} from '../../shared/constants';
29+
import { fetchRoutes, getAllRecords, saveRecord } from '../../shared/ipc';
2930
import {
3031
Connection,
3132
FetchRoutesRequest,
@@ -64,52 +65,47 @@ function portalRouteToRecord(
6465
);
6566
}
6667

67-
function reconcileConnections(baseRecord: Record, portalRoutes: PortalRoute[]) {
68-
ipcRenderer.once(GET_ALL_RECORDS, (_, args) => {
69-
const { err, res }: GetRecordsResponseArgs = args;
70-
if (err) {
71-
enqueueSnackbar(err.message, {
72-
variant: 'error',
73-
autoHideDuration: TOAST_LENGTH,
74-
});
75-
return;
76-
}
68+
async function reconcileConnections(
69+
baseRecord: Record,
70+
portalRoutes: PortalRoute[],
71+
) {
72+
const res = await getAllRecords();
7773

78-
const currentRecords = new Map<string, Record>(
79-
res?.records
80-
?.filter((r) => r.source?.startsWith('portal-route-'))
81-
?.map((r) => [r.source || '', r]) || [],
82-
);
83-
const newRecords = new Map<string, Record>(
84-
portalRoutes
85-
?.filter((pr) => pr.type === 'tcp' || pr.type === 'udp')
86-
?.map((pr) => portalRouteToRecord(baseRecord, pr))
87-
?.map((r) => [r.source || '', r]) || [],
88-
);
74+
const currentRecords = new Map<string, Record>(
75+
res?.records
76+
?.filter((r) => r.source?.startsWith('portal-route-'))
77+
?.map((r) => [r.source || '', r]) || [],
78+
);
79+
const newRecords = new Map<string, Record>(
80+
portalRoutes
81+
?.filter((pr) => pr.type === 'tcp' || pr.type === 'udp')
82+
?.map((pr) => portalRouteToRecord(baseRecord, pr))
83+
?.map((r) => [r.source || '', r]) || [],
84+
);
8985

90-
// remove current records which have been deleted
91-
for (const [k, r] of currentRecords) {
92-
if (!newRecords.has(k)) {
93-
ipcRenderer.send(DELETE, {
94-
ids: [r.id],
95-
});
96-
}
86+
// remove current records which have been deleted
87+
for (const [k, r] of currentRecords) {
88+
if (!newRecords.has(k)) {
89+
ipcRenderer.send(DELETE, {
90+
ids: [r.id],
91+
});
9792
}
93+
}
9894

99-
// add or update new records which have changed
100-
for (const [k, r] of newRecords) {
101-
const cr = currentRecords.get(k);
102-
if (!cr) {
103-
ipcRenderer.send(SAVE_RECORD, r);
104-
return;
105-
}
106-
const nr = defaults(r, cr);
107-
if (!isEqual(nr, cr)) {
108-
ipcRenderer.send(SAVE_RECORD, nr);
109-
}
95+
// add or update new records which have changed
96+
for (const [k, r] of newRecords) {
97+
const cr = currentRecords.get(k);
98+
if (!cr) {
99+
await saveRecord(r);
100+
return;
101+
}
102+
const nr = defaults(r, cr);
103+
if (!isEqual(nr, cr)) {
104+
await saveRecord(nr);
110105
}
111-
});
112-
ipcRenderer.send(GET_ALL_RECORDS);
106+
}
107+
108+
await getAllRecords();
113109
}
114110

115111
export type LoadFormProps = {};
@@ -125,6 +121,7 @@ const LoadForm: FC<LoadFormProps> = ({}) => {
125121
},
126122
);
127123
const [tags, setTags] = useLocalStorage('LoadForm/tags', (): string[] => []);
124+
const [loading, setLoading] = useState(false);
128125

129126
const onChangeUrl = (evt: React.ChangeEvent<HTMLInputElement>) => {
130127
setServerUrl(evt.target.value);
@@ -136,33 +133,34 @@ const LoadForm: FC<LoadFormProps> = ({}) => {
136133
const onClickLoad = (evt: React.MouseEvent) => {
137134
evt.preventDefault();
138135

139-
if (serverUrl) {
140-
const req: FetchRoutesRequest = {
141-
serverUrl,
142-
disableTlsVerification: connection.disableTlsVerification,
143-
caCert: connection.caCert,
144-
clientCert: connection.clientCert,
145-
clientCertFromStore: connection.clientCertFromStore,
146-
};
147-
ipcRenderer.once(FETCH_ROUTES, (_, args) => {
148-
const { err, res }: FetchRoutesResponseArgs = args;
149-
if (err) {
150-
enqueueSnackbar(err.message, {
151-
variant: 'error',
152-
autoHideDuration: TOAST_LENGTH,
136+
(async () => {
137+
try {
138+
setLoading(true);
139+
if (serverUrl) {
140+
const res = await fetchRoutes({
141+
serverUrl,
142+
disableTlsVerification: connection.disableTlsVerification,
143+
caCert: connection.caCert,
144+
clientCert: connection.clientCert,
145+
clientCertFromStore: connection.clientCertFromStore,
153146
});
154-
return;
147+
await reconcileConnections(
148+
{
149+
tags,
150+
conn: connection,
151+
},
152+
res?.routes || [],
153+
);
155154
}
156-
reconcileConnections(
157-
{
158-
tags,
159-
conn: connection,
160-
},
161-
res?.routes || [],
162-
);
163-
});
164-
ipcRenderer.send(FETCH_ROUTES, req);
165-
}
155+
} catch (e) {
156+
enqueueSnackbar(`${(e as any)?.message || e}`, {
157+
variant: 'error',
158+
autoHideDuration: TOAST_LENGTH,
159+
});
160+
} finally {
161+
setLoading(false);
162+
}
163+
})();
166164
};
167165
const onSubmit = (evt: React.FormEvent) => {
168166
evt.preventDefault();
@@ -241,7 +239,7 @@ const LoadForm: FC<LoadFormProps> = ({}) => {
241239
type="button"
242240
variant="contained"
243241
color="primary"
244-
disabled={!serverUrl}
242+
disabled={!serverUrl || loading}
245243
onClick={onClickLoad}
246244
>
247245
Load

src/shared/ipc.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ipcRenderer } from 'electron';
2+
3+
import { FETCH_ROUTES, GET_ALL_RECORDS, SAVE_RECORD } from './constants';
4+
import {
5+
FetchRoutesRequest,
6+
FetchRoutesResponse,
7+
Record,
8+
Records,
9+
} from './pb/api';
10+
11+
function invoke(name: string, ...args: any[]): Promise<any> {
12+
return new Promise((resolve, reject) => {
13+
ipcRenderer.once(name, (_evt, args) => {
14+
const { res, err } = args;
15+
if (err) {
16+
reject(err);
17+
} else {
18+
resolve(res);
19+
}
20+
});
21+
ipcRenderer.send(name, ...args);
22+
});
23+
}
24+
25+
export async function fetchRoutes(
26+
request: FetchRoutesRequest,
27+
): Promise<FetchRoutesResponse> {
28+
return invoke(FETCH_ROUTES, request);
29+
}
30+
31+
export async function getAllRecords(): Promise<Records> {
32+
return invoke(GET_ALL_RECORDS);
33+
}
34+
35+
export async function saveRecord(record: Record): Promise<Record> {
36+
return invoke(SAVE_RECORD, record);
37+
}

0 commit comments

Comments
 (0)