feat: use vite as bundler
This commit is contained in:
parent
35f7772cbb
commit
b64ae40dcf
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,19 +2,21 @@
|
|||||||
"name": "aes67-daemon-webui",
|
"name": "aes67-daemon-webui",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"serve": "vite preview"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^16.11.0",
|
"react": "^17.0.0",
|
||||||
"react-dom": "^16.11.0",
|
"react-dom": "^17.0.0",
|
||||||
"react-modal": "^3.11.1",
|
"react-modal": "^3.11.1",
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"react-scripts": "0.9.5",
|
"react-scripts": "0.9.5",
|
||||||
"react-toastify": "^5.5.0"
|
"react-toastify": "^5.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {
|
||||||
"scripts": {
|
"@vitejs/plugin-react-refresh": "^1.3.1",
|
||||||
"start": "react-scripts start",
|
"vite": "^2.3.4"
|
||||||
"build": "react-scripts build",
|
|
||||||
"test": "react-scripts test --env=jsdom",
|
|
||||||
"eject": "react-scripts eject"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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