1- import { useState , useRef } from "react"
2-
3- const NODE_API_URL = import . meta. env . VITE_API_URL || window . location . origin
1+ import { useState , useRef , useEffect } from "react"
42
53function AddNodeModal ( { isOpen, onClose, onCreate } ) {
64 const [ step , setStep ] = useState ( 1 )
75 const [ loading , setLoading ] = useState ( false )
86 const [ error , setError ] = useState ( null )
97 const [ credentials , setCredentials ] = useState ( null )
10- const [ deploymentMode , setDeploymentMode ] = useState ( "docker " )
8+ const [ os , setOs ] = useState ( "linux " )
119 const inputRef = useRef ( null )
1210
11+ useEffect ( ( ) => {
12+ const ua = navigator . userAgent . toLowerCase ( )
13+ if ( ua . includes ( 'win' ) ) setOs ( 'windows' )
14+ else if ( ua . includes ( 'mac' ) ) setOs ( 'macos' )
15+ else setOs ( 'linux' )
16+ } , [ ] )
17+
1318 async function handleCreateClick ( ) {
1419 const name = inputRef . current ?. value
1520
@@ -32,24 +37,14 @@ function AddNodeModal({ isOpen, onClose, onCreate }) {
3237 }
3338 }
3439
35- const handleCopy = ( text ) => {
36- navigator . clipboard . writeText ( text )
37- }
38-
39- const handleCopyDockerCommand = ( ) => {
40- const cmd = `docker exec opensentry-cloudnode opensentry-cloudnode \\
41- --node-id ${ credentials . node_id } \\
42- --api-key ${ credentials . api_key } \\
43- --api-url ${ NODE_API_URL } `
44- navigator . clipboard . writeText ( cmd )
40+ const installCommands = {
41+ linux : 'curl -fsSL https://opensentry-command.fly.dev/install.sh | bash' ,
42+ macos : 'curl -fsSL https://opensentry-command.fly.dev/install.sh | bash' ,
43+ windows : 'irm https://opensentry-command.fly.dev/install.ps1 | iex' ,
4544 }
4645
47- const handleCopyNativeCommand = ( ) => {
48- const cmd = `cargo run -- \\
49- --node-id ${ credentials . node_id } \\
50- --api-key ${ credentials . api_key } \\
51- --api-url ${ NODE_API_URL } `
52- navigator . clipboard . writeText ( cmd )
46+ const handleCopy = ( text ) => {
47+ navigator . clipboard . writeText ( text )
5348 }
5449
5550 const handleClose = ( ) => {
@@ -160,80 +155,34 @@ function AddNodeModal({ isOpen, onClose, onCreate }) {
160155
161156 < div className = "command-section" >
162157 < h4 > Deploy Your Node</ h4 >
163-
164- < div className = "deployment-tabs" >
165- < button
166- className = { `deployment-tab ${ deploymentMode === "docker" ? "active" : "" } ` }
167- onClick = { ( ) => setDeploymentMode ( "docker" ) }
168- >
169- Docker (Recommended)
170- </ button >
171- < button
172- className = { `deployment-tab ${ deploymentMode === "native" ? "active" : "" } ` }
173- onClick = { ( ) => setDeploymentMode ( "native" ) }
174- >
175- Native Binary
176- </ button >
177- </ div >
178158
179- { deploymentMode === "docker" && (
180- < div className = "deployment-content" >
181- < p className = "deployment-description" >
182- Containerized deployment with FFmpeg included. Best for production use.
183- </ p >
184- < div className = "command-box" >
185- < h5 > 1. Create .env file:</ h5 >
186- < code style = { { whiteSpace : "pre-wrap" } } > { `OPENSENTRY_NODE_ID=${ credentials . node_id }
187- OPENSENTRY_API_KEY=${ credentials . api_key }
188- OPENSENTRY_API_URL=${ NODE_API_URL } ` } </ code >
189- < button
190- className = "btn btn-small"
191- onClick = { ( ) => handleCopy ( `OPENSENTRY_NODE_ID=${ credentials . node_id } \nOPENSENTRY_API_KEY=${ credentials . api_key } \nOPENSENTRY_API_URL=${ NODE_API_URL } ` ) }
192- >
193- Copy
194- </ button >
195- </ div >
196- < div className = "command-box" >
197- < h5 > 2. Pull and run:</ h5 >
198- < code style = { { whiteSpace : "pre-wrap" } } > { `docker pull opensentry-cloudnode:latest
199- docker run -d \\
200- --name opensentry-cloudnode \\
201- --device /dev/video0 \\
202- --env-file .env \\
203- -p 8080:8080 \\
204- opensentry-cloudnode:latest` } </ code >
205- < button
206- className = "btn btn-small"
207- onClick = { ( ) => handleCopy ( `docker pull opensentry-cloudnode:latest\ndocker run -d \\\n --name opensentry-cloudnode \\\n --device /dev/video0 \\\n --env-file .env \\\n -p 8080:8080 \\\n opensentry-cloudnode:latest` ) }
208- >
209- Copy
210- </ button >
159+ < div className = "deployment-content" >
160+ < div className = "command-box" >
161+ < h5 > 1. Install CloudNode:</ h5 >
162+ < div className = "install-tabs" >
163+ < div className = "install-tab-buttons" >
164+ < button className = { `install-tab-btn${ os === 'linux' ? ' active' : '' } ` } onClick = { ( ) => setOs ( 'linux' ) } > Linux</ button >
165+ < button className = { `install-tab-btn${ os === 'macos' ? ' active' : '' } ` } onClick = { ( ) => setOs ( 'macos' ) } > macOS</ button >
166+ < button className = { `install-tab-btn${ os === 'windows' ? ' active' : '' } ` } onClick = { ( ) => setOs ( 'windows' ) } > Windows</ button >
167+ </ div >
211168 </ div >
169+ < code > { installCommands [ os ] } </ code >
170+ < button className = "btn btn-small" onClick = { ( ) => handleCopy ( installCommands [ os ] ) } > Copy</ button >
212171 </ div >
213- ) }
214-
215- { deploymentMode === "native" && (
216- < div className = "deployment-content" >
217- < p className = "deployment-description" >
218- Run directly with Cargo. Requires FFmpeg installed separately. Good for development.
219- </ p >
220- < div className = "command-box" >
221- < code style = { { whiteSpace : "pre-wrap" } } > { `cargo run -- \\
222- --node-id ${ credentials . node_id } \\
223- --api-key ${ credentials . api_key } \\
224- --api-url ${ NODE_API_URL } ` } </ code >
225- < button
226- className = "btn btn-small copy-command-btn"
227- onClick = { handleCopyNativeCommand }
228- >
229- Copy Command
230- </ button >
231- </ div >
232- < div className = "command-note" >
233- < strong > Note:</ strong > Requires Rust and FFmpeg to be installed.
234- </ div >
172+ < div className = "command-box" >
173+ < h5 > 2. Run the setup wizard:</ h5 >
174+ < code > { os === 'windows' ? 'opensentry-cloudnode.exe setup' : 'opensentry-cloudnode setup' } </ code >
175+ < button className = "btn btn-small" onClick = { ( ) => handleCopy ( os === 'windows' ? 'opensentry-cloudnode.exe setup' : 'opensentry-cloudnode setup' ) } > Copy</ button >
235176 </ div >
236- ) }
177+ < div className = "command-note" >
178+ < strong > Tip:</ strong > The setup wizard will ask for your Node ID and API Key shown above.
179+ </ div >
180+ < div className = "command-box" >
181+ < h5 > 3. Start CloudNode:</ h5 >
182+ < code > { os === 'windows' ? 'opensentry-cloudnode.exe' : './opensentry-cloudnode' } </ code >
183+ < button className = "btn btn-small" onClick = { ( ) => handleCopy ( os === 'windows' ? 'opensentry-cloudnode.exe' : './opensentry-cloudnode' ) } > Copy</ button >
184+ </ div >
185+ </ div >
237186 </ div >
238187
239188 < div className = "modal-actions" >
0 commit comments