@@ -14,17 +14,17 @@ import notifications from "@/notifications";
1414import { DEVICE_API } from "@/ui.config" ;
1515import { useJsonRpc } from "@/hooks/useJsonRpc" ;
1616import { isOnDevice } from "@/main" ;
17+ import { TextAreaWithLabel } from "@components/TextArea" ;
1718
1819import { LocalDevice } from "./devices.$id" ;
1920import { SettingsItem } from "./devices.$id.settings" ;
2021import { CloudState } from "./adopt" ;
21- import { TextAreaWithLabel } from "@components/TextArea" ;
2222
2323export interface TLSState {
2424 mode : "self-signed" | "custom" | "disabled" ;
2525 certificate ?: string ;
2626 privateKey ?: string ;
27- } ;
27+ }
2828
2929export const loader = async ( ) => {
3030 if ( isOnDevice ) {
@@ -147,9 +147,37 @@ export default function SettingsAccessIndexRoute() {
147147 }
148148 } ;
149149
150+ // Function to update TLS state - accepts a mode parameter
151+ const updateTlsState = useCallback (
152+ ( mode : string , cert ?: string , key ?: string ) => {
153+ const state = { mode } as TLSState ;
154+ if ( cert && key ) {
155+ state . certificate = cert ;
156+ state . privateKey = key ;
157+ }
158+
159+ send ( "setTLSState" , { state } , resp => {
160+ if ( "error" in resp ) {
161+ notifications . error (
162+ `Failed to update TLS settings: ${ resp . error . data || "Unknown error" } ` ,
163+ ) ;
164+ return ;
165+ }
166+
167+ notifications . success ( "TLS settings updated successfully" ) ;
168+ } ) ;
169+ } ,
170+ [ send ] ,
171+ ) ;
172+
150173 // Handle TLS mode change
151174 const handleTlsModeChange = ( value : string ) => {
152175 setTlsMode ( value ) ;
176+
177+ // For "disabled" and "self-signed" modes, immediately apply the settings
178+ if ( value !== "custom" ) {
179+ updateTlsState ( value ) ;
180+ }
153181 } ;
154182
155183 const handleTlsCertChange = ( value : string ) => {
@@ -160,21 +188,10 @@ export default function SettingsAccessIndexRoute() {
160188 setTlsKey ( value ) ;
161189 } ;
162190
163- const handleTlsUpdate = useCallback ( ( ) => {
164- const state = { mode : tlsMode } as TLSState ;
165- if ( tlsMode !== "disabled" ) {
166- state . certificate = tlsCert ;
167- state . privateKey = tlsKey ;
168- }
169- send ( "setTLSState" , { state } , resp => {
170- if ( "error" in resp ) {
171- notifications . error ( `Failed to update TLS settings: ${ resp . error . data || "Unknown error" } ` ) ;
172- return ;
173- }
174-
175- notifications . success ( "TLS settings updated successfully" ) ;
176- } ) ;
177- } , [ send , tlsMode , tlsCert , tlsKey ] ) ;
191+ // Update the custom TLS settings button click handler
192+ const handleCustomTlsUpdate = ( ) => {
193+ updateTlsState ( tlsMode , tlsCert , tlsKey ) ;
194+ } ;
178195
179196 // Fetch device ID and cloud state on component mount
180197 useEffect ( ( ) => {
@@ -203,11 +220,9 @@ export default function SettingsAccessIndexRoute() {
203220 />
204221 < >
205222 < SettingsItem
206- title = "HTTPS/TLS Mode"
207- description = { < >
208- Select the TLS mode for your device < sup > experimental</ sup > < br />
209- < small > The feature might not work as expected, please report any issues if you encounter any.</ small >
210- </ > }
223+ title = "HTTPS Mode"
224+ badge = "Experimental"
225+ description = "Configure secure HTTPS access to your device"
211226 >
212227 < SelectMenuBasic
213228 size = "SM"
@@ -227,13 +242,15 @@ export default function SettingsAccessIndexRoute() {
227242 < div className = "space-y-4" >
228243 < SettingsItem
229244 title = "TLS Certificate"
230- description = "Enter your TLS certificate here, if intermediate or root CA is used, you can paste the entire chain here too "
245+ description = "Paste your TLS certificate below. For certificate chains, include the entire chain (leaf, intermediate, and root certificates). "
231246 />
232247 < div className = "space-y-4" >
233248 < TextAreaWithLabel
234249 label = "Certificate"
235250 rows = { 3 }
236- placeholder = { "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" }
251+ placeholder = {
252+ "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
253+ }
237254 value = { tlsCert }
238255 onChange = { e => handleTlsCertChange ( e . target . value ) }
239256 />
@@ -243,32 +260,28 @@ export default function SettingsAccessIndexRoute() {
243260 < div className = "space-y-4" >
244261 < TextAreaWithLabel
245262 label = "Private Key"
263+ description = "For security reasons, it will not be displayed after saving."
246264 rows = { 3 }
247- placeholder = { "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" }
265+ placeholder = {
266+ "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
267+ }
248268 value = { tlsKey }
249269 onChange = { e => handleTlsKeyChange ( e . target . value ) }
250270 />
251- < p className = "text-xs text-slate-600 dark:text-slate-400" >
252- Private key won't be shown again after saving.
253- </ p >
254271 </ div >
255272 </ div >
256273 </ div >
274+ < div className = "flex items-center gap-x-2" >
275+ < Button
276+ size = "SM"
277+ theme = "primary"
278+ text = "Update TLS Settings"
279+ onClick = { handleCustomTlsUpdate }
280+ />
281+ </ div >
257282 </ div >
258283 ) }
259284
260-
261- < div className = "space-y-4" >
262- < div className = "flex items-center gap-x-2" >
263- < Button
264- size = "SM"
265- theme = "light"
266- text = "Update TLS Settings"
267- onClick = { handleTlsUpdate }
268- />
269- </ div >
270- </ div >
271-
272285 < SettingsItem
273286 title = "Authentication Mode"
274287 description = { `Current mode: ${ loaderData . authMode === "password" ? "Password protected" : "No password" } ` }
0 commit comments