Skip to content

Commit 100a7e3

Browse files
committed
Streams modal
1 parent 4866988 commit 100a7e3

File tree

16 files changed

+533
-50
lines changed

16 files changed

+533
-50
lines changed

frontend/src/components/Form/SSLCertificateField.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ interface Props {
3131
label?: string;
3232
required?: boolean;
3333
allowNew?: boolean;
34+
forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields
3435
}
3536
export function SSLCertificateField({
3637
name = "certificateId",
3738
label = "ssl-certificate",
3839
id = "certificateId",
3940
required,
4041
allowNew,
42+
forHttp = true,
4143
}: Props) {
4244
const { isLoading, isError, error, data } = useCertificates();
4345
const { values, setFieldValue } = useFormikContext();
@@ -55,7 +57,7 @@ export function SSLCertificateField({
5557
dnsProviderCredentials,
5658
propagationSeconds,
5759
} = v;
58-
if (!newValue?.value) {
60+
if (forHttp && !newValue?.value) {
5961
sslForced && setFieldValue("sslForced", false);
6062
http2Support && setFieldValue("http2Support", false);
6163
hstsEnabled && setFieldValue("hstsEnabled", false);
@@ -94,7 +96,7 @@ export function SSLCertificateField({
9496
options?.unshift({
9597
value: 0,
9698
label: "None",
97-
subLabel: "This host will not use HTTPS",
99+
subLabel: forHttp ? "This host will not use HTTPS" : "No certificate assigned",
98100
icon: <IconShield size={14} className="text-red" />,
99101
});
100102
}

frontend/src/components/Form/SSLOptionsFields.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import cn from "classnames";
22
import { Field, useFormikContext } from "formik";
3-
import { DNSProviderFields } from "src/components";
3+
import { DNSProviderFields, DomainNamesField } from "src/components";
44
import { intl } from "src/locale";
55

6-
export function SSLOptionsFields() {
6+
interface Props {
7+
forHttp?: boolean; // the sslForced, http2Support, hstsEnabled, hstsSubdomains fields
8+
forceDNSForNew?: boolean;
9+
requireDomainNames?: boolean; // used for streams
10+
}
11+
export function SSLOptionsFields({ forHttp = true, forceDNSForNew, requireDomainNames }: Props) {
712
const { values, setFieldValue } = useFormikContext();
813
const v: any = values || {};
914

@@ -12,6 +17,10 @@ export function SSLOptionsFields() {
1217
const { sslForced, http2Support, hstsEnabled, hstsSubdomains, meta } = v;
1318
const { dnsChallenge } = meta || {};
1419

20+
if (forceDNSForNew && newCertificate && !dnsChallenge) {
21+
setFieldValue("meta.dnsChallenge", true);
22+
}
23+
1524
const handleToggleChange = (e: any, fieldName: string) => {
1625
setFieldValue(fieldName, e.target.checked);
1726
if (fieldName === "meta.dnsChallenge" && !e.target.checked) {
@@ -24,8 +33,8 @@ export function SSLOptionsFields() {
2433
const toggleClasses = "form-check-input";
2534
const toggleEnabled = cn(toggleClasses, "bg-cyan");
2635

27-
return (
28-
<>
36+
const getHttpOptions = () => (
37+
<div>
2938
<div className="row">
3039
<div className="col-6">
3140
<Field name="sslForced">
@@ -102,6 +111,12 @@ export function SSLOptionsFields() {
102111
</Field>
103112
</div>
104113
</div>
114+
</div>
115+
);
116+
117+
return (
118+
<div>
119+
{forHttp ? getHttpOptions() : null}
105120
{newCertificate ? (
106121
<>
107122
<Field name="meta.dnsChallenge">
@@ -110,7 +125,8 @@ export function SSLOptionsFields() {
110125
<input
111126
className={dnsChallenge ? toggleEnabled : toggleClasses}
112127
type="checkbox"
113-
checked={!!dnsChallenge}
128+
checked={forceDNSForNew ? true : !!dnsChallenge}
129+
disabled={forceDNSForNew}
114130
onChange={(e) => handleToggleChange(e, field.name)}
115131
/>
116132
<span className="form-check-label">
@@ -119,10 +135,10 @@ export function SSLOptionsFields() {
119135
</label>
120136
)}
121137
</Field>
122-
138+
{requireDomainNames ? <DomainNamesField /> : null}
123139
{dnsChallenge ? <DNSProviderFields /> : null}
124140
</>
125141
) : null}
126-
</>
142+
</div>
127143
);
128144
}

frontend/src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export * from "./useHealth";
99
export * from "./useHostReport";
1010
export * from "./useProxyHosts";
1111
export * from "./useRedirectionHosts";
12+
export * from "./useStream";
1213
export * from "./useStreams";
1314
export * from "./useTheme";
1415
export * from "./useUser";

frontend/src/hooks/useStream.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2+
import { createStream, getStream, type Stream, updateStream } from "src/api/backend";
3+
4+
const fetchStream = (id: number | "new") => {
5+
if (id === "new") {
6+
return Promise.resolve({
7+
id: 0,
8+
createdOn: "",
9+
modifiedOn: "",
10+
ownerUserId: 0,
11+
tcpForwarding: true,
12+
udpForwarding: false,
13+
meta: {},
14+
enabled: true,
15+
certificateId: 0,
16+
} as Stream);
17+
}
18+
return getStream(id, ["owner"]);
19+
};
20+
21+
const useStream = (id: number | "new", options = {}) => {
22+
return useQuery<Stream, Error>({
23+
queryKey: ["stream", id],
24+
queryFn: () => fetchStream(id),
25+
staleTime: 60 * 1000, // 1 minute
26+
...options,
27+
});
28+
};
29+
30+
const useSetStream = () => {
31+
const queryClient = useQueryClient();
32+
return useMutation({
33+
mutationFn: (values: Stream) => (values.id ? updateStream(values) : createStream(values)),
34+
onMutate: (values: Stream) => {
35+
if (!values.id) {
36+
return;
37+
}
38+
const previousObject = queryClient.getQueryData(["stream", values.id]);
39+
queryClient.setQueryData(["stream", values.id], (old: Stream) => ({
40+
...old,
41+
...values,
42+
}));
43+
return () => queryClient.setQueryData(["stream", values.id], previousObject);
44+
},
45+
onError: (_, __, rollback: any) => rollback(),
46+
onSuccess: async ({ id }: Stream) => {
47+
queryClient.invalidateQueries({ queryKey: ["stream", id] });
48+
queryClient.invalidateQueries({ queryKey: ["streams"] });
49+
queryClient.invalidateQueries({ queryKey: ["audit-logs"] });
50+
},
51+
});
52+
};
53+
54+
export { useStream, useSetStream };

frontend/src/locale/lang/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@
130130
"setup.title": "Welcome!",
131131
"sign-in": "Sign in",
132132
"ssl-certificate": "SSL Certificate",
133+
"stream.forward-host": "Forward Host",
134+
"stream.forward-port": "Forward Port",
135+
"stream.incoming-port": "Incoming Port",
136+
"stream.new": "New Stream",
133137
"streams.actions-title": "Stream #{id}",
134138
"streams.add": "Add Stream",
135139
"streams.count": "{count} Streams",

frontend/src/locale/src/en.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,18 @@
392392
"ssl-certificate": {
393393
"defaultMessage": "SSL Certificate"
394394
},
395+
"stream.forward-host": {
396+
"defaultMessage": "Forward Host"
397+
},
398+
"stream.forward-port": {
399+
"defaultMessage": "Forward Port"
400+
},
401+
"stream.incoming-port": {
402+
"defaultMessage": "Incoming Port"
403+
},
404+
"stream.new": {
405+
"defaultMessage": "New Stream"
406+
},
395407
"streams.actions-title": {
396408
"defaultMessage": "Stream #{id}"
397409
},

0 commit comments

Comments
 (0)