commit
						73454073cd
					
				
							
								
								
									
										5
									
								
								webui/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								webui/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -17,3 +17,8 @@ yarn-debug.log* | |||||||
| yarn-error.log* | yarn-error.log* | ||||||
| package-lock.json | package-lock.json | ||||||
| 
 | 
 | ||||||
|  | node_modules | ||||||
|  | .DS_Store | ||||||
|  | dist | ||||||
|  | dist-ssr | ||||||
|  | *.local | ||||||
							
								
								
									
										1623
									
								
								webui/README.md
									
									
									
									
									
								
							
							
						
						
									
										1623
									
								
								webui/README.md
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -3,20 +3,12 @@ | |||||||
|   <head> |   <head> | ||||||
|     <meta charset="utf-8"> |     <meta charset="utf-8"> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> |     <link rel="shortcut icon" href="/src/favicon.ico"> | ||||||
|     <!-- |  | ||||||
|       Notice the use of %PUBLIC_URL% in the tag above. |  | ||||||
|       It will be replaced with the URL of the `public` folder during the build. |  | ||||||
|       Only files inside the `public` folder can be referenced from the HTML. |  | ||||||
| 
 |  | ||||||
|       Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will |  | ||||||
|       work correctly both with client-side routing and a non-root public URL. |  | ||||||
|       Learn how to configure a non-root public URL by running `npm run build`. |  | ||||||
|     --> |  | ||||||
|     <title>AES67 Daemon WebUI</title> |     <title>AES67 Daemon WebUI</title> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <div id="root"></div> |     <div id="root"></div> | ||||||
|  |     <script type="module" src="/src/main.jsx"></script> | ||||||
|     <!-- |     <!-- | ||||||
|       This HTML file is a template. |       This HTML file is a template. | ||||||
|       If you open it directly in the browser, you will see an empty page. |       If you open it directly in the browser, you will see an empty page. | ||||||
| @ -2,20 +2,24 @@ | |||||||
|   "name": "aes67-daemon-webui", |   "name": "aes67-daemon-webui", | ||||||
|   "version": "0.1.0", |   "version": "0.1.0", | ||||||
|   "private": true, |   "private": true, | ||||||
|  |   "engines": { | ||||||
|  |     "node": ">=12.0.0" | ||||||
|  |   }, | ||||||
|  |   "scripts": { | ||||||
|  |     "start": "vite", | ||||||
|  |     "build": "vite build", | ||||||
|  |     "serve": "vite preview" | ||||||
|  |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "react": "^17.0.2", |     "react": "^17.0.2", | ||||||
|     "react-dom": "^17.0.2", |     "react-dom": "^17.0.2", | ||||||
|     "react-modal": "^3.13.1", |     "react-modal": "^3.13.1", | ||||||
|     "react-router-dom": "^5.2.0", |     "react-router-dom": "^5.2.0", | ||||||
|     "react-scripts": "4.0.3", |  | ||||||
|     "react-toastify": "^7.0.4" |     "react-toastify": "^7.0.4" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": {}, |   "devDependencies": { | ||||||
|   "scripts": { |     "@vitejs/plugin-react-refresh": "^1.3.3", | ||||||
|     "start": "react-scripts start", |     "vite": "^2.3.4" | ||||||
|     "build": "react-scripts build", |  | ||||||
|     "test": "react-scripts test --env=jsdom", |  | ||||||
|     "eject": "react-scripts eject" |  | ||||||
|   }, |   }, | ||||||
|   "browserslist": { |   "browserslist": { | ||||||
|     "production": [ |     "production": [ | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  index.js | //  App.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -26,6 +26,8 @@ import 'react-toastify/dist/ReactToastify.css'; | |||||||
| 
 | 
 | ||||||
| import ConfigTabs from './ConfigTabs'; | import ConfigTabs from './ConfigTabs'; | ||||||
| 
 | 
 | ||||||
|  | import './styles.css'; | ||||||
|  | 
 | ||||||
| toast.configure() | toast.configure() | ||||||
| 
 | 
 | ||||||
| function App() { | function App() { | ||||||
| @ -45,6 +47,4 @@ function App() { | |||||||
|   ); |   ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const container = document.createElement('div'); | export default App | ||||||
| document.body.appendChild(container); |  | ||||||
| render( <App/>, container); |  | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Config.js | //  Config.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -19,13 +19,11 @@ | |||||||
| // | // | ||||||
| 
 | 
 | ||||||
| import React, {Component} from 'react'; | import React, {Component} from 'react'; | ||||||
| import { toast } from 'react-toastify';  | import { toast } from 'react-toastify'; | ||||||
| 
 | 
 | ||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| import Loader from './Loader'; | import Loader from './Loader'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| class Config extends Component { | class Config extends Component { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
| @ -107,7 +105,7 @@ class Config extends Component { | |||||||
| 	  })) | 	  })) | ||||||
|       .catch(err => this.setState({isConfigLoading: false})); |       .catch(err => this.setState({isConfigLoading: false})); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   inputIsValid() { |   inputIsValid() { | ||||||
|     return !this.state.playoutDelayErr && |     return !this.state.playoutDelayErr && | ||||||
|       !this.state.maxTicFrameSizeErr && |       !this.state.maxTicFrameSizeErr && | ||||||
| @ -124,22 +122,22 @@ class Config extends Component { | |||||||
|   onSubmit(event) { |   onSubmit(event) { | ||||||
|     event.preventDefault(); |     event.preventDefault(); | ||||||
|     RestAPI.setConfig( |     RestAPI.setConfig( | ||||||
|       this.state.logSeverity,  |       this.state.logSeverity, | ||||||
|       this.state.syslogProto,  |       this.state.syslogProto, | ||||||
|       this.state.syslogServer,  |       this.state.syslogServer, | ||||||
|       this.state.rtpMcastBase,  |       this.state.rtpMcastBase, | ||||||
|       this.state.rtpPort,  |       this.state.rtpPort, | ||||||
|       this.state.rtspPort,  |       this.state.rtspPort, | ||||||
|       this.state.playoutDelay,  |       this.state.playoutDelay, | ||||||
|       this.state.ticFrameSizeAt1fs,  |       this.state.ticFrameSizeAt1fs, | ||||||
|       this.state.sampleRate,  |       this.state.sampleRate, | ||||||
|       this.state.maxTicFrameSize,  |       this.state.maxTicFrameSize, | ||||||
|       this.state.sapMcastAddr, |       this.state.sapMcastAddr, | ||||||
|       this.state.sapInterval, |       this.state.sapInterval, | ||||||
|       this.state.mdnsEnabled) |       this.state.mdnsEnabled) | ||||||
|     .then(response => toast.success('Config updated, daemon restart ...')); |     .then(response => toast.success('Config updated, daemon restart ...')); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   render() { |   render() { | ||||||
|     return ( |     return ( | ||||||
|       <div className='config'> |       <div className='config'> | ||||||
| @ -175,7 +173,7 @@ class Config extends Component { | |||||||
|           </tr> |           </tr> | ||||||
|           <tr> |           <tr> | ||||||
|             <th align="left"> <label>Initial Sample rate</label> </th> |             <th align="left"> <label>Initial Sample rate</label> </th> | ||||||
|             <th align="left">  |             <th align="left"> | ||||||
| 	      <select value={this.state.sampleRate} onChange={e => this.setState({sampleRate: e.target.value})}> | 	      <select value={this.state.sampleRate} onChange={e => this.setState({sampleRate: e.target.value})}> | ||||||
|                 <option value="44100">44.1 kHz</option> |                 <option value="44100">44.1 kHz</option> | ||||||
|                 <option value="48000">48 kHz</option> |                 <option value="48000">48 kHz</option> | ||||||
| @ -237,7 +235,7 @@ class Config extends Component { | |||||||
|         <table><tbody> |         <table><tbody> | ||||||
|           <tr> |           <tr> | ||||||
|             <th align="left"> <label>Syslog protocol</label> </th> |             <th align="left"> <label>Syslog protocol</label> </th> | ||||||
|             <th align="left">  |             <th align="left"> | ||||||
| 	      <select value={this.state.syslogProto} onChange={e => this.setState({syslogProto: e.target.value})}> | 	      <select value={this.state.syslogProto} onChange={e => this.setState({syslogProto: e.target.value})}> | ||||||
|                 <option value="none">none</option> |                 <option value="none">none</option> | ||||||
|                 <option value="">local</option> |                 <option value="">local</option> | ||||||
| @ -251,7 +249,7 @@ class Config extends Component { | |||||||
|           </tr> |           </tr> | ||||||
|           <tr> |           <tr> | ||||||
|             <th align="left"> <label>Log severity</label> </th> |             <th align="left"> <label>Log severity</label> </th> | ||||||
|             <th align="left">  |             <th align="left"> | ||||||
| 	      <select value={this.state.logSeverity} onChange={e => this.setState({logSeverity: e.target.value})}> | 	      <select value={this.state.logSeverity} onChange={e => this.setState({logSeverity: e.target.value})}> | ||||||
|                 <option value="1">debug</option> |                 <option value="1">debug</option> | ||||||
|                 <option value="2">info</option> |                 <option value="2">info</option> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  ConfigTabs.js | //  ConfigTabs.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -28,15 +28,13 @@ import Sources from './Sources'; | |||||||
| import Sinks from './Sinks'; | import Sinks from './Sinks'; | ||||||
| import RemoteSources from './RemoteSources'; | import RemoteSources from './RemoteSources'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| class ConfigTabs extends Component { | class ConfigTabs extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
|     currentTab: PropTypes.string.isRequired |     currentTab: PropTypes.string.isRequired | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|     return (  |     return ( | ||||||
|       <div> |       <div> | ||||||
|         <h1>AES67 Daemon</h1> |         <h1>AES67 Daemon</h1> | ||||||
|         <Tabs currentTab={this.props.currentTab}> |         <Tabs currentTab={this.props.currentTab}> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Loader.js | //  Loader.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  PTP.js | //  PTP.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import {toast} from 'react-toastify'; | |||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| import Loader from './Loader'; | import Loader from './Loader'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class PTPConfig extends Component { | class PTPConfig extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
| @ -141,9 +139,9 @@ class PTP extends Component { | |||||||
|       .then(response => response.json()) |       .then(response => response.json()) | ||||||
|       .then( |       .then( | ||||||
|         data => this.setState({ |         data => this.setState({ | ||||||
|            status: data.status,  |            status: data.status, | ||||||
|            gmid: data.gmid,  |            gmid: data.gmid, | ||||||
|            jitter: parseInt(data.jitter, 10),  |            jitter: parseInt(data.jitter, 10), | ||||||
|            isStatusLoading: false |            isStatusLoading: false | ||||||
|         })) |         })) | ||||||
|       .catch(err => this.setState({isStatusLoading: false})); |       .catch(err => this.setState({isStatusLoading: false})); | ||||||
| @ -155,19 +153,19 @@ class PTP extends Component { | |||||||
|       .then(response => response.json()) |       .then(response => response.json()) | ||||||
|       .then( |       .then( | ||||||
|         data => this.setState({ |         data => this.setState({ | ||||||
|           domain: parseInt(data.domain, 10),  |           domain: parseInt(data.domain, 10), | ||||||
|           dscp: parseInt(data.dscp, 10),  |           dscp: parseInt(data.dscp, 10), | ||||||
|           isConfigLoading: false |           isConfigLoading: false | ||||||
|         })) |         })) | ||||||
|       .catch(err => this.setState({isConfigLoading: false})); |       .catch(err => this.setState({isConfigLoading: false})); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   componentDidMount() { |   componentDidMount() { | ||||||
|     this.fetchStatus(); |     this.fetchStatus(); | ||||||
|     this.fetchConfig(); |     this.fetchConfig(); | ||||||
|     this.interval = setInterval(() => { this.fetchStatus() }, 10000) |     this.interval = setInterval(() => { this.fetchStatus() }, 10000) | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   componentWillUnmount() { |   componentWillUnmount() { | ||||||
|     clearInterval(this.interval); |     clearInterval(this.interval); | ||||||
|   } |   } | ||||||
| @ -175,10 +173,10 @@ class PTP extends Component { | |||||||
|   render() { |   render() { | ||||||
|     return ( |     return ( | ||||||
|       <div className='ptp'> |       <div className='ptp'> | ||||||
|         { this.state.isConfigLoading ? <Loader/> :  |         { this.state.isConfigLoading ? <Loader/> : | ||||||
|            <PTPConfig domain={this.state.domain} dscp={this.state.dscp}/> } |            <PTPConfig domain={this.state.domain} dscp={this.state.dscp}/> } | ||||||
|         <br/> |         <br/> | ||||||
|         { this.state.isStatusLoading ? <Loader/> :  |         { this.state.isStatusLoading ? <Loader/> : | ||||||
|            <PTPStatus status={this.state.status} gmid={this.state.gmid} jitter={this.state.jitter}/> } |            <PTPStatus status={this.state.status} gmid={this.state.gmid} jitter={this.state.jitter}/> } | ||||||
|       </div> |       </div> | ||||||
|     ) |     ) | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  RemoteSource.js | //  RemoteSource.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import RestAPI from './Services'; | |||||||
| import Loader from './Loader'; | import Loader from './Loader'; | ||||||
| import SourceInfo from './SourceInfo'; | import SourceInfo from './SourceInfo'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| class RemoteSourceEntry extends Component { | class RemoteSourceEntry extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
|     source: PropTypes.string.isRequired, |     source: PropTypes.string.isRequired, | ||||||
| @ -42,9 +40,9 @@ class RemoteSourceEntry extends Component { | |||||||
| 
 | 
 | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       rtp_address: 'n/a', |       rtp_address: 'n/a', | ||||||
|       port: 'n/a'  |       port: 'n/a' | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -91,7 +89,7 @@ class RemoteSourceList extends Component { | |||||||
|     return ( |     return ( | ||||||
|       <div id='remote-sources-table'> |       <div id='remote-sources-table'> | ||||||
|         <table className="table-stream"><tbody> |         <table className="table-stream"><tbody> | ||||||
|           {this.props.sources.length > 0 ?  |           {this.props.sources.length > 0 ? | ||||||
|             <tr className='tr-stream'> |             <tr className='tr-stream'> | ||||||
|               <th>Source</th> |               <th>Source</th> | ||||||
|               <th>Address</th> |               <th>Address</th> | ||||||
| @ -118,11 +116,11 @@ class RemoteSourceList extends Component { | |||||||
| class RemoteSources extends Component { | class RemoteSources extends Component { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       sources: [],  |       sources: [], | ||||||
|       isLoading: false,  |       isLoading: false, | ||||||
|       infoIsOpen: false,  |       infoIsOpen: false, | ||||||
|       infoTitle: ''  |       infoTitle: '' | ||||||
|     }; |     }; | ||||||
|     this.onInfoClick = this.onInfoClick.bind(this); |     this.onInfoClick = this.onInfoClick.bind(this); | ||||||
|     this.onReloadClick = this.onReloadClick.bind(this); |     this.onReloadClick = this.onReloadClick.bind(this); | ||||||
| @ -152,7 +150,7 @@ class RemoteSources extends Component { | |||||||
|     this.setState({infoIsOpen: false}); |     this.setState({infoIsOpen: false}); | ||||||
|     this.fetchRemoteSources(); |     this.fetchRemoteSources(); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   onInfoClick(id) { |   onInfoClick(id) { | ||||||
|     const source = this.state.sources.find(s => s.id === id); |     const source = this.state.sources.find(s => s.id === id); | ||||||
|     this.openInfo("Announced Source Info", source, true); |     this.openInfo("Announced Source Info", source, true); | ||||||
| @ -179,14 +177,14 @@ class RemoteSources extends Component { | |||||||
|     )); |     )); | ||||||
|     return ( |     return ( | ||||||
|       <div id='sources'> |       <div id='sources'> | ||||||
|        { this.state.isLoading ? <Loader/>  |        { this.state.isLoading ? <Loader/> | ||||||
| 	   : <RemoteSourceList | 	   : <RemoteSourceList | ||||||
|                onReloadClick={this.onReloadClick} |                onReloadClick={this.onReloadClick} | ||||||
|                sources={sources} /> } |                sources={sources} /> } | ||||||
|        { this.state.infoIsOpen ? |        { this.state.infoIsOpen ? | ||||||
|         <SourceInfo infoIsOpen={this.state.infoIsOpen} |         <SourceInfo infoIsOpen={this.state.infoIsOpen} | ||||||
|           closeInfo={this.closeInfo} |           closeInfo={this.closeInfo} | ||||||
|           infoTitle={this.state.infoTitle}  |           infoTitle={this.state.infoTitle} | ||||||
| 	  id={this.state.source.id} | 	  id={this.state.source.id} | ||||||
| 	  source={this.state.source.source} | 	  source={this.state.source.source} | ||||||
| 	  name={this.state.source.name} | 	  name={this.state.source.name} | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  SinkEdit.js | //  SinkEdit.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import Modal from 'react-modal'; | |||||||
| 
 | 
 | ||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| const editCustomStyles = { | const editCustomStyles = { | ||||||
|   content : { |   content : { | ||||||
|     top:  '50%', |     top:  '50%', | ||||||
| @ -102,9 +100,9 @@ class SinkEdit extends Component { | |||||||
|       this.state.source ? this.state.source : '', |       this.state.source ? this.state.source : '', | ||||||
|       this.state.sdp ? this.state.sdp : '', |       this.state.sdp ? this.state.sdp : '', | ||||||
|       this.state.ignoreRefclkGmid, |       this.state.ignoreRefclkGmid, | ||||||
|       this.state.map,  |       this.state.map, | ||||||
|       this.props.isEdit) |       this.props.isEdit) | ||||||
|     .then(function(response) {  |     .then(function(response) { | ||||||
|       this.props.applyEdit(); |       this.props.applyEdit(); | ||||||
|       toast.success(message); |       toast.success(message); | ||||||
|     }.bind(this)); |     }.bind(this)); | ||||||
| @ -148,8 +146,8 @@ class SinkEdit extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   inputIsValid() { |   inputIsValid() { | ||||||
|     return !this.state.nameErr &&  |     return !this.state.nameErr && | ||||||
|       !this.state.sourceErr &&  |       !this.state.sourceErr && | ||||||
|       (this.state.useSdp || this.state.source) && |       (this.state.useSdp || this.state.source) && | ||||||
|       (!this.state.useSdp || this.state.sdp); |       (!this.state.useSdp || this.state.sdp); | ||||||
|   } |   } | ||||||
| @ -157,7 +155,7 @@ class SinkEdit extends Component { | |||||||
|   render()  { |   render()  { | ||||||
|     return ( |     return ( | ||||||
|       <div id='sink-edit'> |       <div id='sink-edit'> | ||||||
|         <Modal ariaHideApp={false}  |         <Modal ariaHideApp={false} | ||||||
|           isOpen={this.props.editIsOpen} |           isOpen={this.props.editIsOpen} | ||||||
|           onRequestClose={this.props.closeEdit} |           onRequestClose={this.props.closeEdit} | ||||||
|           style={editCustomStyles} |           style={editCustomStyles} | ||||||
| @ -185,7 +183,7 @@ class SinkEdit extends Component { | |||||||
|               <th align="left"> |               <th align="left"> | ||||||
|                 <select value={this.state.sdp} onChange={this.onChangeRemoteSourceSDP} disabled={this.state.useSdp ? undefined : true}> |                 <select value={this.state.sdp} onChange={this.onChangeRemoteSourceSDP} disabled={this.state.useSdp ? undefined : true}> | ||||||
|                   <option key='' value=''> -- select a remote source SDP -- </option> |                   <option key='' value=''> -- select a remote source SDP -- </option> | ||||||
|                   {  |                   { | ||||||
|                     this.state.sources.map((v) => <option key={v.id} value={v.sdp}>{v.source + ' from ' + v.address + ' - ' + v.name}</option>) |                     this.state.sources.map((v) => <option key={v.id} value={v.sdp}>{v.source + ' from ' + v.address + ' - ' + v.name}</option>) | ||||||
| 		  } | 		  } | ||||||
|                 </select> |                 </select> | ||||||
| @ -197,7 +195,7 @@ class SinkEdit extends Component { | |||||||
|             </tr> |             </tr> | ||||||
|             <tr> |             <tr> | ||||||
|               <th align="left"> <label>Delay (samples) </label> </th> |               <th align="left"> <label>Delay (samples) </label> </th> | ||||||
|               <th align="left">  |               <th align="left"> | ||||||
| 	        <select value={this.state.delay} onChange={e => this.setState({delay: e.target.value})}> | 	        <select value={this.state.delay} onChange={e => this.setState({delay: e.target.value})}> | ||||||
|                   <option value="192">192 - 4ms@48KHz</option> |                   <option value="192">192 - 4ms@48KHz</option> | ||||||
|                   <option value="384">384 - 8ms@48KHz</option> |                   <option value="384">384 - 8ms@48KHz</option> | ||||||
| @ -219,8 +217,8 @@ class SinkEdit extends Component { | |||||||
|               <th align="left">Audio Channels map</th> |               <th align="left">Audio Channels map</th> | ||||||
|               <th align="left"> |               <th align="left"> | ||||||
|                 <select value={this.state.map[0]} onChange={this.onChangeChannelsMap}> |                 <select value={this.state.map[0]} onChange={this.onChangeChannelsMap}> | ||||||
|                   { this.state.channels > 1 ?  |                   { this.state.channels > 1 ? | ||||||
|                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Input ' + parseInt(v + 1, 10) + ' -> ALSA Input ' +  parseInt(v + this.state.channels, 10)}</option>) :  |                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Input ' + parseInt(v + 1, 10) + ' -> ALSA Input ' +  parseInt(v + this.state.channels, 10)}</option>) : | ||||||
|                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Input ' + parseInt(v + 1, 10)}</option>) |                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Input ' + parseInt(v + 1, 10)}</option>) | ||||||
| 		  } | 		  } | ||||||
|                 </select> |                 </select> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  SinkRemove.js | //  SinkRemove.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import Modal from 'react-modal'; | |||||||
| 
 | 
 | ||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| const removeCustomStyles = { | const removeCustomStyles = { | ||||||
|   content : { |   content : { | ||||||
|     top:  '50%', |     top:  '50%', | ||||||
| @ -58,7 +56,7 @@ class SinkRemove extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   removeSink(message) { |   removeSink(message) { | ||||||
|     RestAPI.removeSink(this.props.sink.id).then(function(response) {  |     RestAPI.removeSink(this.props.sink.id).then(function(response) { | ||||||
|       toast.success(message); |       toast.success(message); | ||||||
|       this.props.applyEdit(); |       this.props.applyEdit(); | ||||||
|     }.bind(this)); |     }.bind(this)); | ||||||
| @ -75,7 +73,7 @@ class SinkRemove extends Component { | |||||||
|   render()  { |   render()  { | ||||||
|     return ( |     return ( | ||||||
|       <div id='sink-remove'> |       <div id='sink-remove'> | ||||||
|         <Modal ariaHideApp={false}  |         <Modal ariaHideApp={false} | ||||||
|           isOpen={this.props.removeIsOpen} |           isOpen={this.props.removeIsOpen} | ||||||
|           onRequestClose={this.props.closeEdit} |           onRequestClose={this.props.closeEdit} | ||||||
|           style={removeCustomStyles} |           style={removeCustomStyles} | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Sinks.js | //  Sinks.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -26,8 +26,6 @@ import Loader from './Loader'; | |||||||
| import SinkEdit from './SinkEdit'; | import SinkEdit from './SinkEdit'; | ||||||
| import SinkRemove from './SinkRemove'; | import SinkRemove from './SinkRemove'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| class SinkEntry extends Component { | class SinkEntry extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
|     id: PropTypes.number.isRequired, |     id: PropTypes.number.isRequired, | ||||||
| @ -39,10 +37,10 @@ class SinkEntry extends Component { | |||||||
| 
 | 
 | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       min_time: 'n/a', |       min_time: 'n/a', | ||||||
|       flags: 'n/a', |       flags: 'n/a', | ||||||
|       errors: 'n/a'  |       errors: 'n/a' | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -76,8 +74,8 @@ class SinkEntry extends Component { | |||||||
|           flags += (flags ? ',' : '') + 'all muted'; |           flags += (flags ? ',' : '') + 'all muted'; | ||||||
|         if (status.sink_flags._muted) |         if (status.sink_flags._muted) | ||||||
|           flags += (flags ? ',' : '') + 'muted'; |           flags += (flags ? ',' : '') + 'muted'; | ||||||
|         this.setState({  |         this.setState({ | ||||||
|           min_time: status.sink_min_time + ' ms',  |           min_time: status.sink_min_time + ' ms', | ||||||
|           flags: flags ? flags : 'idle', |           flags: flags ? flags : 'idle', | ||||||
|           errors: errors ? errors : 'none' |           errors: errors ? errors : 'none' | ||||||
|         }); |         }); | ||||||
| @ -119,7 +117,7 @@ class SinkList extends Component { | |||||||
|     return ( |     return ( | ||||||
|       <div id='sinks-table'> |       <div id='sinks-table'> | ||||||
|         <table className="table-stream"><tbody> |         <table className="table-stream"><tbody> | ||||||
|           {this.props.sinks.length > 0 ?  |           {this.props.sinks.length > 0 ? | ||||||
|             <tr className='tr-stream'> |             <tr className='tr-stream'> | ||||||
|               <th>ID</th> |               <th>ID</th> | ||||||
|               <th>Name</th> |               <th>Name</th> | ||||||
| @ -137,7 +135,7 @@ class SinkList extends Component { | |||||||
|         <span className='pointer-area' onClick={this.handleReloadClick}> <img width='30' height='30' src='/reload.png' alt=''/> </span> |         <span className='pointer-area' onClick={this.handleReloadClick}> <img width='30' height='30' src='/reload.png' alt=''/> </span> | ||||||
|             |             | ||||||
|         {this.props.sinks.length < 64 ? |         {this.props.sinks.length < 64 ? | ||||||
| 	  <span className='pointer-area' onClick={this.handleAddClick}> <img width='30' height='30' src='/plus.png' alt=''/> </span>  | 	  <span className='pointer-area' onClick={this.handleAddClick}> <img width='30' height='30' src='/plus.png' alt=''/> </span> | ||||||
|           : undefined} |           : undefined} | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
| @ -147,14 +145,14 @@ class SinkList extends Component { | |||||||
| class Sinks extends Component { | class Sinks extends Component { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       sinks: [],  |       sinks: [], | ||||||
|       sink: {},  |       sink: {}, | ||||||
|       isLoading: false,  |       isLoading: false, | ||||||
|       isEdit: false,  |       isEdit: false, | ||||||
|       editIsOpen: false,  |       editIsOpen: false, | ||||||
|       removeIsOpen: false,  |       removeIsOpen: false, | ||||||
|       editTitle: ''  |       editTitle: '' | ||||||
|     }; |     }; | ||||||
|     this.onEditClick = this.onEditClick.bind(this); |     this.onEditClick = this.onEditClick.bind(this); | ||||||
|     this.onTrashClick = this.onTrashClick.bind(this); |     this.onTrashClick = this.onTrashClick.bind(this); | ||||||
| @ -191,13 +189,13 @@ class Sinks extends Component { | |||||||
|   onReloadClick() { |   onReloadClick() { | ||||||
|     this.fetchSinks(); |     this.fetchSinks(); | ||||||
|   } |   } | ||||||
|   | 
 | ||||||
|   closeEdit() { |   closeEdit() { | ||||||
|     this.setState({editIsOpen: false}); |     this.setState({editIsOpen: false}); | ||||||
|     this.setState({removeIsOpen: false}); |     this.setState({removeIsOpen: false}); | ||||||
|     this.fetchSinks(); |     this.fetchSinks(); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   onEditClick(id) { |   onEditClick(id) { | ||||||
|     const sink = this.state.sinks.find(s => s.id === id); |     const sink = this.state.sinks.find(s => s.id === id); | ||||||
|     this.openEdit("Edit Sink " + id, sink, true); |     this.openEdit("Edit Sink " + id, sink, true); | ||||||
| @ -209,15 +207,15 @@ class Sinks extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onAddClick() { |   onAddClick() { | ||||||
|     let id;  |     let id; | ||||||
|     /* find first free id */ |     /* find first free id */ | ||||||
|     for (id = 0; id < 63; id++) { |     for (id = 0; id < 63; id++) { | ||||||
|       if (this.state.sinks[id] === undefined ||  |       if (this.state.sinks[id] === undefined || | ||||||
|           this.state.sinks[id].id !== id) { |           this.state.sinks[id].id !== id) { | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const defaultSink = {  |     const defaultSink = { | ||||||
|       'id': id, |       'id': id, | ||||||
|       'name': 'ALSA Sink ' + id, |       'name': 'ALSA Sink ' + id, | ||||||
|       'io': 'Audio Device', |       'io': 'Audio Device', | ||||||
| @ -230,7 +228,7 @@ class Sinks extends Component { | |||||||
|     }; |     }; | ||||||
|     this.openEdit('Add Sink ' + id, defaultSink, false); |     this.openEdit('Add Sink ' + id, defaultSink, false); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   render() { |   render() { | ||||||
|     this.state.sinks.sort((a, b) => (a.id > b.id) ? 1 : -1); |     this.state.sinks.sort((a, b) => (a.id > b.id) ? 1 : -1); | ||||||
|     const sinks = this.state.sinks.map((sink) => ( |     const sinks = this.state.sinks.map((sink) => ( | ||||||
| @ -244,15 +242,15 @@ class Sinks extends Component { | |||||||
|     )); |     )); | ||||||
|     return ( |     return ( | ||||||
|       <div id='sinks'> |       <div id='sinks'> | ||||||
|        { this.state.isLoading ? <Loader/>  |        { this.state.isLoading ? <Loader/> | ||||||
| 	   : <SinkList onAddClick={this.onAddClick}  | 	   : <SinkList onAddClick={this.onAddClick} | ||||||
|                onReloadClick={this.onReloadClick} |                onReloadClick={this.onReloadClick} | ||||||
|                sinks={sinks} /> } |                sinks={sinks} /> } | ||||||
|        { this.state.editIsOpen ? |        { this.state.editIsOpen ? | ||||||
|         <SinkEdit editIsOpen={this.state.editIsOpen} |         <SinkEdit editIsOpen={this.state.editIsOpen} | ||||||
|           closeEdit={this.closeEdit} |           closeEdit={this.closeEdit} | ||||||
|           applyEdit={this.applyEdit} |           applyEdit={this.applyEdit} | ||||||
|           editTitle={this.state.editTitle}  |           editTitle={this.state.editTitle} | ||||||
| 	  isEdit={this.state.isEdit} | 	  isEdit={this.state.isEdit} | ||||||
| 	  sink={this.state.sink} /> | 	  sink={this.state.sink} /> | ||||||
|            : undefined } |            : undefined } | ||||||
| @ -260,7 +258,7 @@ class Sinks extends Component { | |||||||
|         <SinkRemove removeIsOpen={this.state.removeIsOpen} |         <SinkRemove removeIsOpen={this.state.removeIsOpen} | ||||||
|           closeEdit={this.closeEdit} |           closeEdit={this.closeEdit} | ||||||
|           applyEdit={this.applyEdit} |           applyEdit={this.applyEdit} | ||||||
| 	  sink={this.state.sink}  | 	  sink={this.state.sink} | ||||||
| 	  key={this.state.sink.id} /> | 	  key={this.state.sink.id} /> | ||||||
|            : undefined } |            : undefined } | ||||||
|       </div> |       </div> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  SourceEdit.js | //  SourceEdit.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import Modal from 'react-modal'; | |||||||
| 
 | 
 | ||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| const editCustomStyles = { | const editCustomStyles = { | ||||||
|   content : { |   content : { | ||||||
|     top:  '50%', |     top:  '50%', | ||||||
| @ -38,7 +36,7 @@ const editCustomStyles = { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const max_packet_size = 1440; //bytes  | const max_packet_size = 1440; //bytes | ||||||
| 
 | 
 | ||||||
| class SourceEdit extends Component { | class SourceEdit extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
| @ -114,7 +112,7 @@ class SourceEdit extends Component { | |||||||
|       this.state.refclkPtpTraceable, |       this.state.refclkPtpTraceable, | ||||||
|       this.state.map, |       this.state.map, | ||||||
|       this.props.isEdit) |       this.props.isEdit) | ||||||
|     .then(function(response) {  |     .then(function(response) { | ||||||
|       toast.success(message); |       toast.success(message); | ||||||
|       this.props.applyEdit(); |       this.props.applyEdit(); | ||||||
|     }.bind(this)); |     }.bind(this)); | ||||||
| @ -127,7 +125,7 @@ class SourceEdit extends Component { | |||||||
|   onCancel() { |   onCancel() { | ||||||
|     this.props.closeEdit(); |     this.props.closeEdit(); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   getMaxChannels(codec, samples) { |   getMaxChannels(codec, samples) { | ||||||
|     let maxChannels = Math.floor(max_packet_size / (samples * (codec === 'L16' ? 2 : 3))); |     let maxChannels = Math.floor(max_packet_size / (samples * (codec === 'L16' ? 2 : 3))); | ||||||
|     return maxChannels > 64 ? 64 : maxChannels; |     return maxChannels > 64 ? 64 : maxChannels; | ||||||
| @ -144,7 +142,7 @@ class SourceEdit extends Component { | |||||||
|     let maxChannels = this.getMaxChannels(this.state.codec, this.state.maxSamplesPerPacket); |     let maxChannels = this.getMaxChannels(this.state.codec, this.state.maxSamplesPerPacket); | ||||||
|     this.setState({ codec: codec, maxChannels: maxChannels, channelsErr: this.state.channels > maxChannels }); |     this.setState({ codec: codec, maxChannels: maxChannels, channelsErr: this.state.channels > maxChannels }); | ||||||
|   } |   } | ||||||
|   | 
 | ||||||
|   onChangeChannels(e) { |   onChangeChannels(e) { | ||||||
|     if (e.currentTarget.checkValidity()) { |     if (e.currentTarget.checkValidity()) { | ||||||
|       let channels = parseInt(e.target.value, 10); |       let channels = parseInt(e.target.value, 10); | ||||||
| @ -194,7 +192,7 @@ class SourceEdit extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getMaxSamplesPerPacket() { |   getMaxSamplesPerPacket() { | ||||||
|     return (this.props.source.max_samples_per_packet > (this.props.ticFrameSizeAt1fs * this.getnFS())) ?  |     return (this.props.source.max_samples_per_packet > (this.props.ticFrameSizeAt1fs * this.getnFS())) ? | ||||||
|             (this.props.ticFrameSizeAt1fs * this.getnFS()) : this.props.source.max_samples_per_packet; |             (this.props.ticFrameSizeAt1fs * this.getnFS()) : this.props.source.max_samples_per_packet; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -202,7 +200,7 @@ class SourceEdit extends Component { | |||||||
|     let duration = (samples * 1000000) / this.props.sampleRate; |     let duration = (samples * 1000000) / this.props.sampleRate; | ||||||
|     if (duration >= 1000) { |     if (duration >= 1000) { | ||||||
|       duration /= 1000; |       duration /= 1000; | ||||||
|       if (duration == Math.round(duration))  |       if (duration == Math.round(duration)) | ||||||
|         return Math.round(duration).toString() + 'ms'; |         return Math.round(duration).toString() + 'ms'; | ||||||
|       else |       else | ||||||
|         return (Math.round(duration * 1000) / 1000).toString() + 'ms'; |         return (Math.round(duration * 1000) / 1000).toString() + 'ms'; | ||||||
| @ -222,7 +220,7 @@ class SourceEdit extends Component { | |||||||
|   render()  { |   render()  { | ||||||
|     return ( |     return ( | ||||||
|       <div id='source-edit'> |       <div id='source-edit'> | ||||||
|         <Modal ariaHideApp={false}  |         <Modal ariaHideApp={false} | ||||||
|           isOpen={this.props.editIsOpen} |           isOpen={this.props.editIsOpen} | ||||||
|           onRequestClose={this.props.closeEdit} |           onRequestClose={this.props.closeEdit} | ||||||
|           style={editCustomStyles} |           style={editCustomStyles} | ||||||
| @ -243,7 +241,7 @@ class SourceEdit extends Component { | |||||||
|             </tr> |             </tr> | ||||||
|             <tr> |             <tr> | ||||||
|               <th align="left"> <label>Max samples per packet </label> </th> |               <th align="left"> <label>Max samples per packet </label> </th> | ||||||
|               <th align="left">  |               <th align="left"> | ||||||
| 	        <select value={this.state.maxSamplesPerPacket} onChange={this.onChangeMaxSamplesPerPacket}> | 	        <select value={this.state.maxSamplesPerPacket} onChange={this.onChangeMaxSamplesPerPacket}> | ||||||
|                   <option value="6" disabled={this.checkMaxSamplesPerPacket(6) ? undefined : true}>6 - {this.getPacketDuration(6)}</option> |                   <option value="6" disabled={this.checkMaxSamplesPerPacket(6) ? undefined : true}>6 - {this.getPacketDuration(6)}</option> | ||||||
|                   <option value="12" disabled={this.checkMaxSamplesPerPacket(12) ? undefined : true}>12 - {this.getPacketDuration(12)}</option> |                   <option value="12" disabled={this.checkMaxSamplesPerPacket(12) ? undefined : true}>12 - {this.getPacketDuration(12)}</option> | ||||||
| @ -256,7 +254,7 @@ class SourceEdit extends Component { | |||||||
|             </tr> |             </tr> | ||||||
|             <tr> |             <tr> | ||||||
|               <th align="left"> <label>Codec</label> </th> |               <th align="left"> <label>Codec</label> </th> | ||||||
|               <th align="left">  |               <th align="left"> | ||||||
| 	        <select value={this.state.codec} onChange={this.onChangeCodec}> | 	        <select value={this.state.codec} onChange={this.onChangeCodec}> | ||||||
|                   <option value="L16">L16</option> |                   <option value="L16">L16</option> | ||||||
|                   <option value="L24">L24</option> |                   <option value="L24">L24</option> | ||||||
| @ -299,8 +297,8 @@ class SourceEdit extends Component { | |||||||
|               <th align="left">Audio Channels map</th> |               <th align="left">Audio Channels map</th> | ||||||
|               <th align="left"> |               <th align="left"> | ||||||
|                 <select value={this.state.map[0]} onChange={this.onChangeChannelsMap}> |                 <select value={this.state.map[0]} onChange={this.onChangeChannelsMap}> | ||||||
|                   { this.state.channels > 1 ?  |                   { this.state.channels > 1 ? | ||||||
|                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Output ' + parseInt(v + 1, 10) + ' -> ALSA Output ' +  parseInt(v + this.state.channels, 10)}</option>) :  |                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Output ' + parseInt(v + 1, 10) + ' -> ALSA Output ' +  parseInt(v + this.state.channels, 10)}</option>) : | ||||||
|                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Output ' + parseInt(v + 1, 10)}</option>) |                       this.state.audioMap.map((v) => <option key={v} value={v}>{'ALSA Output ' + parseInt(v + 1, 10)}</option>) | ||||||
| 		  } | 		  } | ||||||
|                 </select> |                 </select> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  SourceInfo.js | //  SourceInfo.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -22,8 +22,6 @@ import React, {Component} from 'react'; | |||||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||||
| import Modal from 'react-modal'; | import Modal from 'react-modal'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| const infoCustomStyles = { | const infoCustomStyles = { | ||||||
|   content : { |   content : { | ||||||
|     top:  '50%', |     top:  '50%', | ||||||
| @ -59,11 +57,11 @@ class SourceInfo extends Component { | |||||||
|   onClose() { |   onClose() { | ||||||
|     this.props.closeInfo(); |     this.props.closeInfo(); | ||||||
|   } |   } | ||||||
|   | 
 | ||||||
|   render()  { |   render()  { | ||||||
|     return ( |     return ( | ||||||
|       <div id='source-info'> |       <div id='source-info'> | ||||||
|         <Modal ariaHideApp={false}  |         <Modal ariaHideApp={false} | ||||||
|           isOpen={this.props.infoIsOpen} |           isOpen={this.props.infoIsOpen} | ||||||
|           onRequestClose={this.props.closeInfo} |           onRequestClose={this.props.closeInfo} | ||||||
|           style={infoCustomStyles} |           style={infoCustomStyles} | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  SourceRemove.js | //  SourceRemove.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -25,8 +25,6 @@ import Modal from 'react-modal'; | |||||||
| 
 | 
 | ||||||
| import RestAPI from './Services'; | import RestAPI from './Services'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| const removeCustomStyles = { | const removeCustomStyles = { | ||||||
|   content : { |   content : { | ||||||
|     top:  '50%', |     top:  '50%', | ||||||
| @ -58,7 +56,7 @@ class SourceRemove extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   removeSource(message) { |   removeSource(message) { | ||||||
|     RestAPI.removeSource(this.props.source.id).then(function(response) {  |     RestAPI.removeSource(this.props.source.id).then(function(response) { | ||||||
|       toast.success(message); |       toast.success(message); | ||||||
|       this.props.applyEdit(); |       this.props.applyEdit(); | ||||||
|     }.bind(this)); |     }.bind(this)); | ||||||
| @ -75,7 +73,7 @@ class SourceRemove extends Component { | |||||||
|   render()  { |   render()  { | ||||||
|     return ( |     return ( | ||||||
|       <div id='source-remove'> |       <div id='source-remove'> | ||||||
|         <Modal ariaHideApp={false}  |         <Modal ariaHideApp={false} | ||||||
|           isOpen={this.props.removeIsOpen} |           isOpen={this.props.removeIsOpen} | ||||||
|           onRequestClose={this.props.closeEdit} |           onRequestClose={this.props.closeEdit} | ||||||
|           style={removeCustomStyles} |           style={removeCustomStyles} | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Sources.js | //  Sources.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -27,8 +27,6 @@ import SourceEdit from './SourceEdit'; | |||||||
| import SourceRemove from './SourceRemove'; | import SourceRemove from './SourceRemove'; | ||||||
| import SourceInfo from './SourceInfo'; | import SourceInfo from './SourceInfo'; | ||||||
| 
 | 
 | ||||||
| require('./styles.css'); |  | ||||||
| 
 |  | ||||||
| class SourceEntry extends Component { | class SourceEntry extends Component { | ||||||
|   static propTypes = { |   static propTypes = { | ||||||
|     id: PropTypes.number.isRequired, |     id: PropTypes.number.isRequired, | ||||||
| @ -41,10 +39,10 @@ class SourceEntry extends Component { | |||||||
| 
 | 
 | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       address: 'n/a', |       address: 'n/a', | ||||||
|       port: 'n/a', |       port: 'n/a', | ||||||
|       sdp: ''  |       sdp: '' | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -108,7 +106,7 @@ class SourceList extends Component { | |||||||
|     return ( |     return ( | ||||||
|       <div id='sources-table'> |       <div id='sources-table'> | ||||||
|         <table className="table-stream"><tbody> |         <table className="table-stream"><tbody> | ||||||
|           {this.props.sources.length > 0 ?  |           {this.props.sources.length > 0 ? | ||||||
|             <tr className='tr-stream'> |             <tr className='tr-stream'> | ||||||
|               <th>ID</th> |               <th>ID</th> | ||||||
|               <th>Name</th> |               <th>Name</th> | ||||||
| @ -125,7 +123,7 @@ class SourceList extends Component { | |||||||
|         <span className='pointer-area' onClick={this.handleReloadClick}> <img width='30' height='30' src='/reload.png' alt=''/> </span> |         <span className='pointer-area' onClick={this.handleReloadClick}> <img width='30' height='30' src='/reload.png' alt=''/> </span> | ||||||
|             |             | ||||||
|         {this.props.sources.length < 64 ? |         {this.props.sources.length < 64 ? | ||||||
| 	  <span className='pointer-area' onClick={this.handleAddClick}> <img width='30' height='30' src='/plus.png' alt=''/> </span>  | 	  <span className='pointer-area' onClick={this.handleAddClick}> <img width='30' height='30' src='/plus.png' alt=''/> </span> | ||||||
|           : undefined} |           : undefined} | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
| @ -135,19 +133,19 @@ class SourceList extends Component { | |||||||
| class Sources extends Component { | class Sources extends Component { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|     this.state = {  |     this.state = { | ||||||
|       sources: [],  |       sources: [], | ||||||
|       source: {},  |       source: {}, | ||||||
|       isLoading: false,  |       isLoading: false, | ||||||
|       isConfigLoading: false,  |       isConfigLoading: false, | ||||||
|       isEdit: false,  |       isEdit: false, | ||||||
|       isInfo: false,  |       isInfo: false, | ||||||
|       editIsOpen: false,  |       editIsOpen: false, | ||||||
|       infoIsOpen: false,  |       infoIsOpen: false, | ||||||
|       removeIsOpen: false, |       removeIsOpen: false, | ||||||
|       ticFrameSizeAt1fs: '', |       ticFrameSizeAt1fs: '', | ||||||
|       sampleRate: '', |       sampleRate: '', | ||||||
|       editTitle: ''  |       editTitle: '' | ||||||
|     }; |     }; | ||||||
|     this.onInfoClick = this.onInfoClick.bind(this); |     this.onInfoClick = this.onInfoClick.bind(this); | ||||||
|     this.onEditClick = this.onEditClick.bind(this); |     this.onEditClick = this.onEditClick.bind(this); | ||||||
| @ -192,7 +190,7 @@ class Sources extends Component { | |||||||
|     this.closeEdit(); |     this.closeEdit(); | ||||||
|     this.fetchSources(); |     this.fetchSources(); | ||||||
|   } |   } | ||||||
|   | 
 | ||||||
|   closeEdit() { |   closeEdit() { | ||||||
|     this.setState({editIsOpen: false}); |     this.setState({editIsOpen: false}); | ||||||
|     this.setState({removeIsOpen: false}); |     this.setState({removeIsOpen: false}); | ||||||
| @ -202,7 +200,7 @@ class Sources extends Component { | |||||||
|   closeInfo() { |   closeInfo() { | ||||||
|     this.setState({infoIsOpen: false}); |     this.setState({infoIsOpen: false}); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   onInfoClick(id, sdp) { |   onInfoClick(id, sdp) { | ||||||
|     const source = this.state.sources.find(s => s.id === id); |     const source = this.state.sources.find(s => s.id === id); | ||||||
|     this.openInfo("Local Source Info", source, sdp, true); |     this.openInfo("Local Source Info", source, sdp, true); | ||||||
| @ -223,15 +221,15 @@ class Sources extends Component { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onAddClick() { |   onAddClick() { | ||||||
|     let id;  |     let id; | ||||||
|     /* find first free id */ |     /* find first free id */ | ||||||
|     for (id = 0; id < 63; id++) { |     for (id = 0; id < 63; id++) { | ||||||
|       if (this.state.sources[id] === undefined ||  |       if (this.state.sources[id] === undefined || | ||||||
|           this.state.sources[id].id !== id) { |           this.state.sources[id].id !== id) { | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     const defaultSource = {  |     const defaultSource = { | ||||||
|       'id': id, |       'id': id, | ||||||
|       'enabled': true, |       'enabled': true, | ||||||
|       'name': 'ALSA Source ' + id, |       'name': 'ALSA Source ' + id, | ||||||
| @ -246,7 +244,7 @@ class Sources extends Component { | |||||||
|     }; |     }; | ||||||
|     this.openEdit('Add Source ' + id, defaultSource, false); |     this.openEdit('Add Source ' + id, defaultSource, false); | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   render() { |   render() { | ||||||
|     this.state.sources.sort((a, b) => (a.id > b.id) ? 1 : -1); |     this.state.sources.sort((a, b) => (a.id > b.id) ? 1 : -1); | ||||||
|     const sources = this.state.sources.map((source) => ( |     const sources = this.state.sources.map((source) => ( | ||||||
| @ -261,14 +259,14 @@ class Sources extends Component { | |||||||
|     )); |     )); | ||||||
|     return ( |     return ( | ||||||
|       <div id='sources'> |       <div id='sources'> | ||||||
|        { this.state.isLoading || this.state.isConfigLoading ? <Loader/>  |        { this.state.isLoading || this.state.isConfigLoading ? <Loader/> | ||||||
| 	   : <SourceList onAddClick={this.onAddClick}  | 	   : <SourceList onAddClick={this.onAddClick} | ||||||
|                onReloadClick={this.onReloadClick} |                onReloadClick={this.onReloadClick} | ||||||
|                sources={sources} /> } |                sources={sources} /> } | ||||||
|        { this.state.infoIsOpen ? |        { this.state.infoIsOpen ? | ||||||
|         <SourceInfo infoIsOpen={this.state.infoIsOpen} |         <SourceInfo infoIsOpen={this.state.infoIsOpen} | ||||||
|           closeInfo={this.closeInfo} |           closeInfo={this.closeInfo} | ||||||
|           infoTitle={this.state.infoTitle}  |           infoTitle={this.state.infoTitle} | ||||||
| 	  isInfo={this.state.isInfo} | 	  isInfo={this.state.isInfo} | ||||||
| 	  id={this.state.source.id.toString()} | 	  id={this.state.source.id.toString()} | ||||||
| 	  name={this.state.source.name} | 	  name={this.state.source.name} | ||||||
| @ -279,7 +277,7 @@ class Sources extends Component { | |||||||
|         <SourceEdit editIsOpen={this.state.editIsOpen} |         <SourceEdit editIsOpen={this.state.editIsOpen} | ||||||
|           closeEdit={this.closeEdit} |           closeEdit={this.closeEdit} | ||||||
|           applyEdit={this.applyEdit} |           applyEdit={this.applyEdit} | ||||||
|           editTitle={this.state.editTitle}  |           editTitle={this.state.editTitle} | ||||||
| 	  isEdit={this.state.isEdit} | 	  isEdit={this.state.isEdit} | ||||||
|           ticFrameSizeAt1fs={this.state.ticFrameSizeAt1fs} |           ticFrameSizeAt1fs={this.state.ticFrameSizeAt1fs} | ||||||
|           sampleRate={this.state.sampleRate} |           sampleRate={this.state.sampleRate} | ||||||
| @ -289,7 +287,7 @@ class Sources extends Component { | |||||||
|         <SourceRemove removeIsOpen={this.state.removeIsOpen} |         <SourceRemove removeIsOpen={this.state.removeIsOpen} | ||||||
|           closeEdit={this.closeEdit} |           closeEdit={this.closeEdit} | ||||||
|           applyEdit={this.applyEdit} |           applyEdit={this.applyEdit} | ||||||
| 	  source={this.state.source}  | 	  source={this.state.source} | ||||||
| 	  key={this.state.source.id} /> | 	  key={this.state.source.id} /> | ||||||
|            : undefined } |            : undefined } | ||||||
|       </div> |       </div> | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Tab.js | //  Tab.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -51,7 +51,7 @@ class Tab extends Component { | |||||||
|       className += ' tab-list-active'; |       className += ' tab-list-active'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return (  |     return ( | ||||||
|       <li className={className} onClick={onClick}>{label}</li> |       <li className={className} onClick={onClick}>{label}</li> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @ -1,5 +1,5 @@ | |||||||
| // | // | ||||||
| //  Tabs.js | //  Tabs.jsx | ||||||
| // | // | ||||||
| //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | //  Copyright (c) 2019 2020 Andrea Bondavalli. All rights reserved. | ||||||
| // | // | ||||||
| @ -46,11 +46,11 @@ class Tabs extends Component { | |||||||
|       state: { activeTab, } |       state: { activeTab, } | ||||||
|     } = this; |     } = this; | ||||||
| 
 | 
 | ||||||
|     return (  |     return ( | ||||||
|       <div className="tabs"> |       <div className="tabs"> | ||||||
|         <ol className="tab-list"> { children.map((child) => {  |         <ol className="tab-list"> { children.map((child) => { | ||||||
|           const { label } = child.props; |           const { label } = child.props; | ||||||
|           return (  |           return ( | ||||||
|             <Tab activeTab={ activeTab } |             <Tab activeTab={ activeTab } | ||||||
|                  key={ label } |                  key={ label } | ||||||
|                  label={ label } |                  label={ label } | ||||||
| @ -58,11 +58,11 @@ class Tabs extends Component { | |||||||
|             /> |             /> | ||||||
|           ); }) |           ); }) | ||||||
|         } |         } | ||||||
|         </ol>  |         </ol> | ||||||
|         <div className="tab-content"> { children.map((child) => { |         <div className="tab-content"> { children.map((child) => { | ||||||
|           if (child.props.label !== activeTab) return undefined; |           if (child.props.label !== activeTab) return undefined; | ||||||
|           return child.props.children; |           return child.props.children; | ||||||
|         }) }  |         }) } | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
							
								
								
									
										11
									
								
								webui/src/main.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								webui/src/main.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import ReactDOM from 'react-dom' | ||||||
|  | import './styles.css' | ||||||
|  | import App from './App' | ||||||
|  | 
 | ||||||
|  | ReactDOM.render( | ||||||
|  |   <React.StrictMode> | ||||||
|  |     <App /> | ||||||
|  |   </React.StrictMode>, | ||||||
|  |   document.getElementById('root') | ||||||
|  | ) | ||||||
							
								
								
									
										7
									
								
								webui/vite.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webui/vite.config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | import { defineConfig } from 'vite' | ||||||
|  | import reactRefresh from '@vitejs/plugin-react-refresh' | ||||||
|  | 
 | ||||||
|  | // https://vitejs.dev/config/
 | ||||||
|  | export default defineConfig({ | ||||||
|  |   plugins: [reactRefresh()] | ||||||
|  | }) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user