Skip to content

Commit 0e90f0b

Browse files
committed
add load connections form
1 parent b5b827a commit 0e90f0b

15 files changed

+2397
-1056
lines changed

api.proto

+35-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ service Config {
1919
rpc Export(ExportRequest) returns (ConfigData);
2020
// Import imports previously serialized records
2121
rpc Import(ImportRequest) returns (ImportResponse);
22+
// FetchRoutes fetches all the routes from the routes portal.
23+
rpc FetchRoutes(FetchRoutesRequest) returns (FetchRoutesResponse);
2224
}
2325

2426
// Record represents a single tunnel record in the configuration
@@ -28,6 +30,7 @@ message Record {
2830
repeated string tags = 2;
2931
// connection data may be omitted if i.e. just manipulating the tags data
3032
optional Connection conn = 3;
33+
optional string source = 4;
3134
}
3235

3336
message Records { repeated Record records = 1; }
@@ -85,7 +88,8 @@ service Listener {
8588
// StatusUpdates opens a stream to listen to connection status updates
8689
// a client has to subscribe and continuously
8790
// listen to the broadcasted updates
88-
rpc StatusUpdates(StatusUpdatesRequest) returns (stream ConnectionStatusUpdate);
91+
rpc StatusUpdates(StatusUpdatesRequest)
92+
returns (stream ConnectionStatusUpdate);
8993
}
9094

9195
message ListenerUpdateRequest {
@@ -104,6 +108,28 @@ message ListenerStatusResponse { map<string, ListenerStatus> listeners = 1; }
104108

105109
message StatusUpdatesRequest { string connection_id = 1; }
106110

111+
message FetchRoutesRequest {
112+
string server_url = 1;
113+
oneof tls_options {
114+
bool disable_tls_verification = 2;
115+
bytes ca_cert = 3;
116+
}
117+
optional Certificate client_cert = 4;
118+
optional ClientCertFromStore client_cert_from_store = 5;
119+
}
120+
121+
message FetchRoutesResponse { repeated PortalRoute routes = 1; }
122+
123+
message PortalRoute {
124+
string id = 1;
125+
string name = 2;
126+
string type = 3;
127+
string from = 4;
128+
string description = 5;
129+
optional string connect_command = 6;
130+
string logo_url = 7;
131+
}
132+
107133
// ConnectionStatusUpdates represent connection state changes
108134
message ConnectionStatusUpdate {
109135
// record this event relates to
@@ -211,10 +237,18 @@ message ClientCertFromStore {
211237
optional string subject_filter = 2;
212238
}
213239

240+
enum Protocol {
241+
UNKNOWN = 0;
242+
TCP = 1;
243+
UDP = 2;
244+
}
245+
214246
// Connection
215247
message Connection {
216248
// name is a user friendly connection name that a user may define
217249
optional string name = 1;
250+
// the protocol to use for the connection
251+
optional Protocol protocol = 10;
218252
// remote_addr is a remote pomerium host:port
219253
string remote_addr = 2;
220254
// listen_address, if not provided, will assign a random port each time

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
"source-map-support": "^0.5.19",
292292
"ts-proto": "^1.166.2",
293293
"typescript-eslint": "^0.0.1-alpha.0",
294+
"usehooks-ts": "^3.1.0",
294295
"validator": "^13.11.0"
295296
},
296297
"devEngines": {

src/App.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import SnackbarCloseButton from './renderer/components/SnackbarCloseButton';
2222
import ConnectForm from './renderer/pages/ConnectForm';
2323
import ConnectionView from './renderer/pages/ConnectionView';
2424
import Layout from './renderer/pages/Layout';
25+
import LoadForm from './renderer/pages/LoadForm';
2526
import ManageConnections from './renderer/pages/ManageConnections';
2627
import { THEMES } from './shared/constants';
2728
import createCustomTheme, { ThemeConfig } from './shared/theme';
@@ -74,6 +75,7 @@ const App: FC = () => {
7475
element={<Navigate to="/manage" replace />}
7576
/>
7677
<Route path="/manage" element={<ManageConnections />} />
78+
<Route path="/loadForm" element={<LoadForm />} />
7779
<Route
7880
path="/view_connection/:connectionID"
7981
element={<ConnectionView />}

src/main.dev.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ import {
4747
ExportFile,
4848
LISTENER_LOG,
4949
GET_ALL_RECORDS,
50+
FETCH_ROUTES,
51+
FetchRoutesResponseArgs,
52+
GetRecordsResponseArgs,
5053
} from './shared/constants';
5154
import {
5255
ConnectionStatusUpdate,
@@ -57,6 +60,7 @@ import {
5760
Record as ListenerRecord,
5861
Selector,
5962
StatusUpdatesRequest,
63+
FetchRoutesRequest,
6064
} from './shared/pb/api';
6165
import Helper from './trayMenu/helper';
6266

@@ -175,10 +179,8 @@ async function init(): Promise<void> {
175179
ipcMain.on(GET_RECORDS, (evt, selector: Selector) => {
176180
const sendTo = evt?.sender ? evt.sender : mainWindow?.webContents;
177181
configClient.list(selector, (err, res) => {
178-
sendTo?.send(GET_RECORDS, {
179-
err,
180-
res,
181-
});
182+
const args: GetRecordsResponseArgs = { err, res };
183+
sendTo?.send(GET_RECORDS, args);
182184
if (!err && res) {
183185
if (selector.all) {
184186
trayMenuHelper.setRecords(res.records);
@@ -200,10 +202,8 @@ async function init(): Promise<void> {
200202
tags: [],
201203
} as Selector,
202204
(err, res) => {
203-
sendTo?.send(GET_ALL_RECORDS, {
204-
err,
205-
res,
206-
});
205+
const args: GetRecordsResponseArgs = { err, res };
206+
sendTo?.send(GET_ALL_RECORDS, args);
207207
if (!err && res) {
208208
trayMenuHelper.setRecords(res.records);
209209
menu.tray.setContextMenu(trayMenuHelper.createContextMenu());
@@ -337,6 +337,13 @@ async function init(): Promise<void> {
337337
// empty function otherwise causes fatal error on cancel !!!
338338
updateStream.on('error', () => {});
339339
});
340+
ipcMain.on(FETCH_ROUTES, (evt, args) => {
341+
const sendTo = evt?.sender ? evt.sender : mainWindow?.webContents;
342+
configClient.fetchRoutes(args as FetchRoutesRequest, (err, res) => {
343+
const args: FetchRoutesResponseArgs = { err, res };
344+
sendTo?.send(FETCH_ROUTES, args);
345+
});
346+
});
340347
menu.app.on('web-contents-created', () => {
341348
contextMenu();
342349
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {
2+
Accordion,
3+
AccordionDetails,
4+
AccordionSummary,
5+
Typography,
6+
} from '@mui/material';
7+
import React, { FC } from 'react';
8+
import { ChevronDown } from 'react-feather';
9+
10+
export type AdvancedSettingsAccordionProps = React.PropsWithChildren<{}>;
11+
const AdvancedSettingsAccordion: FC<AdvancedSettingsAccordionProps> = ({
12+
children,
13+
}) => {
14+
return (
15+
<Accordion
16+
sx={{
17+
backgroundColor: 'background.paper',
18+
marginTop: 2,
19+
paddingLeft: 2,
20+
paddingRight: 2,
21+
borderRadius: 4,
22+
'&:before': {
23+
display: 'none',
24+
},
25+
}}
26+
square={false}
27+
>
28+
<AccordionSummary
29+
expandIcon={<ChevronDown />}
30+
aria-controls="advanced-settings-content"
31+
id="advanced-settings-header"
32+
>
33+
<Typography variant="h5">Advanced Settings</Typography>
34+
</AccordionSummary>
35+
<AccordionDetails>{children}</AccordionDetails>
36+
</Accordion>
37+
);
38+
};
39+
export default AdvancedSettingsAccordion;
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Autocomplete } from '@mui/material';
2+
import { ipcRenderer } from 'electron';
3+
import React, { FC, useEffect, useState } from 'react';
4+
5+
import { GET_UNIQUE_TAGS } from '../../shared/constants';
6+
import { formatTag } from '../../shared/validators';
7+
import TextField from './TextField';
8+
9+
export type TagSelectorProps = {
10+
tags: string[];
11+
onChangeTags: (tags: string[]) => void;
12+
};
13+
const TagSelector: FC<TagSelectorProps> = ({ tags, onChangeTags }) => {
14+
const [tagOptions, setTagOptions] = useState([] as string[]);
15+
16+
useEffect(() => {
17+
ipcRenderer.once(GET_UNIQUE_TAGS, (_, args) => {
18+
if (args.tags && !args.err) {
19+
setTagOptions(args.tags);
20+
}
21+
});
22+
ipcRenderer.send(GET_UNIQUE_TAGS);
23+
}, []);
24+
25+
const saveTags = (arr: string[]): void => onChangeTags(arr.map(formatTag));
26+
27+
return (
28+
<>
29+
<Autocomplete
30+
multiple
31+
id="tags-outlined"
32+
options={tagOptions}
33+
value={tags || []}
34+
onChange={(_, arr) => {
35+
console.log('CHANGE TAGS');
36+
saveTags(arr);
37+
}}
38+
renderInput={(params) => (
39+
<TextField
40+
{...params}
41+
variant="outlined"
42+
label="Tags..."
43+
placeholder="Tags"
44+
onKeyDown={(e) => {
45+
const element = e.target as HTMLInputElement;
46+
const { value } = element;
47+
if (e.key === 'Enter' && value.trim()) {
48+
saveTags(tags.concat(value));
49+
}
50+
}}
51+
/>
52+
)}
53+
/>
54+
</>
55+
);
56+
};
57+
export default TagSelector;

src/renderer/pages/ConnectForm.tsx

+10-66
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
/* eslint-disable react/jsx-props-no-spreading */
22
import {
3-
Accordion,
4-
AccordionDetails,
5-
AccordionSummary,
6-
Autocomplete,
73
Button,
84
CardContent,
95
Container,
@@ -13,7 +9,7 @@ import {
139
import { ipcRenderer } from 'electron';
1410
import { useSnackbar } from 'notistack';
1511
import React, { FC, useEffect, useState } from 'react';
16-
import { CheckCircle, ChevronDown } from 'react-feather';
12+
import { CheckCircle } from 'react-feather';
1713
import { useParams } from 'react-router-dom';
1814

1915
import {
@@ -25,10 +21,11 @@ import {
2521
VIEW_CONNECTION_LIST,
2622
} from '../../shared/constants';
2723
import { Connection, Record, Selector } from '../../shared/pb/api';
28-
import { formatTag } from '../../shared/validators';
2924
import AdvancedConnectionSettings from '../components/AdvancedConnectionSettings';
25+
import AdvancedSettingsAccordion from '../components/AdvancedSettingsAccordion';
3026
import BeforeBackActionDialog from '../components/BeforeBackActionDialog';
3127
import StyledCard from '../components/StyledCard';
28+
import TagSelector from '../components/TagSelector';
3229
import TextField from '../components/TextField';
3330

3431
interface Props {
@@ -51,7 +48,6 @@ const ConnectForm: FC<Props> = () => {
5148
const [tags, setTags] = useState<string[]>([]);
5249
const [connection, setConnection] = useState(initialConnData);
5350
const [originalConnection, setOriginalConnection] = useState(initialConnData);
54-
const [tagOptions, setTagOptions] = useState([] as string[]);
5551
const handleSubmit = (evt: React.FormEvent): void => {
5652
evt.preventDefault();
5753
};
@@ -72,12 +68,6 @@ const ConnectForm: FC<Props> = () => {
7268
setOriginalConnection(conn || initialConnData);
7369
}
7470
});
75-
ipcRenderer.once(GET_UNIQUE_TAGS, (_, args) => {
76-
if (args.tags && !args.err) {
77-
setTagOptions(args.tags);
78-
}
79-
});
80-
ipcRenderer.send(GET_UNIQUE_TAGS);
8171

8272
if (connectionID) {
8373
ipcRenderer.send(GET_RECORDS, {
@@ -99,8 +89,6 @@ const ConnectForm: FC<Props> = () => {
9989
});
10090
};
10191

102-
const saveTags = (arr: string[]): void => setTags(arr.map(formatTag));
103-
10492
const saveDestination = (value: string): void => {
10593
setConnection({
10694
...connection,
@@ -209,62 +197,18 @@ const ConnectForm: FC<Props> = () => {
209197
/>
210198
</Grid>
211199
<Grid item xs={12}>
212-
<Autocomplete
213-
multiple
214-
id="tags-outlined"
215-
options={tagOptions}
216-
value={tags || []}
217-
onChange={(_, arr) => {
218-
saveTags(arr);
219-
}}
220-
renderInput={(params) => (
221-
<TextField
222-
{...params}
223-
variant="outlined"
224-
label="Tags..."
225-
placeholder="Tags"
226-
onKeyDown={(e) => {
227-
const element = e.target as HTMLInputElement;
228-
const { value } = element;
229-
if (e.key === 'Enter' && value.trim()) {
230-
saveTags(tags.concat(value));
231-
}
232-
}}
233-
/>
234-
)}
235-
/>
200+
<TagSelector tags={tags} onChangeTags={setTags} />
236201
</Grid>
237202
</Grid>
238203
</CardContent>
239204
</StyledCard>
240205

241-
<Accordion
242-
sx={{
243-
backgroundColor: 'background.paper',
244-
marginTop: 2,
245-
paddingLeft: 2,
246-
paddingRight: 2,
247-
borderRadius: 4,
248-
'&:before': {
249-
display: 'none',
250-
},
251-
}}
252-
square={false}
253-
>
254-
<AccordionSummary
255-
expandIcon={<ChevronDown />}
256-
aria-controls="advanced-settings-content"
257-
id="advanced-settings-header"
258-
>
259-
<Typography variant="h5">Advanced Settings</Typography>
260-
</AccordionSummary>
261-
<AccordionDetails>
262-
<AdvancedConnectionSettings
263-
connection={connection}
264-
onChangeConnection={setConnection}
265-
/>
266-
</AccordionDetails>
267-
</Accordion>
206+
<AdvancedSettingsAccordion>
207+
<AdvancedConnectionSettings
208+
connection={connection}
209+
onChangeConnection={setConnection}
210+
/>
211+
</AdvancedSettingsAccordion>
268212

269213
<Grid
270214
container

0 commit comments

Comments
 (0)