fix(live-streaming): show warning if stream key seems wrong
Provide a client-side notice if the YouTube live stream key looks like it might be in the wrong format. Normally the stream key looks like 4 groups of 4 numbers and letters, each separated by a dash. The warning does not block submission in case YouTube changes their stream key format.
This commit is contained in:
parent
b57eaed940
commit
920c179f56
@ -65,6 +65,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.form-footer {
|
.form-footer {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 5px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,9 +97,15 @@
|
|||||||
|
|
||||||
.stream-key-form {
|
.stream-key-form {
|
||||||
.helper-link {
|
.helper-link {
|
||||||
display: inline-block;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: 5px;
|
display: inline-block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-error {
|
||||||
|
color:#FFD740;
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -515,6 +515,7 @@
|
|||||||
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
"expandedOn": "The meeting is currently being streamed to YouTube.",
|
||||||
"expandedPending": "The live streaming is being started...",
|
"expandedPending": "The live streaming is being started...",
|
||||||
"failedToStart": "Live Streaming failed to start",
|
"failedToStart": "Live Streaming failed to start",
|
||||||
|
"invalidStreamKey": "Live stream key may be incorrect.",
|
||||||
"off": "Live Streaming stopped",
|
"off": "Live Streaming stopped",
|
||||||
"on": "Live Streaming",
|
"on": "Live Streaming",
|
||||||
"pending": "Starting Live Stream...",
|
"pending": "Starting Live Stream...",
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
|
|
||||||
declare var interfaceConfig: Object;
|
declare var interfaceConfig: Object;
|
||||||
@ -33,14 +34,27 @@ export type Props = {
|
|||||||
value: string
|
value: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of the component.
|
||||||
|
*/
|
||||||
|
type State = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to show the warnings that the passed in value seems like
|
||||||
|
* an improperly formatted stream key.
|
||||||
|
*/
|
||||||
|
showValidationError: boolean
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract React Component for entering a key for starting a YouTube live
|
* An abstract React Component for entering a key for starting a YouTube live
|
||||||
* stream.
|
* stream.
|
||||||
*
|
*
|
||||||
* @extends Component
|
* @extends Component
|
||||||
*/
|
*/
|
||||||
export default class AbstractStreamKeyForm extends Component<Props> {
|
export default class AbstractStreamKeyForm extends Component<Props, State> {
|
||||||
helpURL: string;
|
helpURL: string;
|
||||||
|
_debouncedUpdateValidationErrorVisibility: Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the component.
|
* Constructor for the component.
|
||||||
@ -50,14 +64,45 @@ export default class AbstractStreamKeyForm extends Component<Props> {
|
|||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showValidationError: Boolean(this.props.value)
|
||||||
|
&& !this._validateStreamKey(this.props.value)
|
||||||
|
};
|
||||||
|
|
||||||
this.helpURL = (typeof interfaceConfig !== 'undefined'
|
this.helpURL = (typeof interfaceConfig !== 'undefined'
|
||||||
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|
||||||
|| LIVE_STREAMING_HELP_LINK;
|
|| LIVE_STREAMING_HELP_LINK;
|
||||||
|
|
||||||
|
this._debouncedUpdateValidationErrorVisibility = debounce(
|
||||||
|
this._updateValidationErrorVisibility.bind(this),
|
||||||
|
800,
|
||||||
|
{ leading: false }
|
||||||
|
);
|
||||||
|
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onInputChange = this._onInputChange.bind(this);
|
this._onInputChange = this._onInputChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React Component's componentDidUpdate.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
componentDidUpdate(prevProps: Props) {
|
||||||
|
if (this.props.value !== prevProps.value) {
|
||||||
|
this._debouncedUpdateValidationErrorVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements React Component's componentWillUnmount.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._debouncedUpdateValidationErrorVisibility.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
_onInputChange: Object => void
|
_onInputChange: Object => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,4 +120,38 @@ export default class AbstractStreamKeyForm extends Component<Props> {
|
|||||||
|
|
||||||
this.props.onChange(value);
|
this.props.onChange(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the stream key value seems like a valid stream key and sets the
|
||||||
|
* state for showing or hiding the notification about the stream key seeming
|
||||||
|
* invalid.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
_updateValidationErrorVisibility() {
|
||||||
|
const newShowValidationError = Boolean(this.props.value)
|
||||||
|
&& !this._validateStreamKey(this.props.value);
|
||||||
|
|
||||||
|
if (newShowValidationError !== this.state.showValidationError) {
|
||||||
|
this.setState({
|
||||||
|
showValidationError: newShowValidationError
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a passed in stream key appears to be in a valid format.
|
||||||
|
*
|
||||||
|
* @param {string} streamKey - The stream key to check for valid formatting.
|
||||||
|
* @returns {void}
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
_validateStreamKey(streamKey = '') {
|
||||||
|
const trimmedKey = streamKey.trim();
|
||||||
|
const fourGroupsDashSeparated = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/;
|
||||||
|
const match = fourGroupsDashSeparated.exec(trimmedKey);
|
||||||
|
|
||||||
|
return Boolean(match);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
|||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const { value, t } = this.props;
|
const { t, value } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className = 'stream-key-form'>
|
<div className = 'stream-key-form'>
|
||||||
@ -52,16 +52,22 @@ class StreamKeyForm extends AbstractStreamKeyForm {
|
|||||||
shouldFitContainer = { true }
|
shouldFitContainer = { true }
|
||||||
type = 'text'
|
type = 'text'
|
||||||
value = { this.props.value } />
|
value = { this.props.value } />
|
||||||
{ this.helpURL
|
<div className = 'form-footer'>
|
||||||
? <div className = 'form-footer'>
|
{ this.state.showValidationError
|
||||||
<a
|
? <span className = 'validation-error'>
|
||||||
|
{ t('liveStreaming.invalidStreamKey') }
|
||||||
|
</span>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{ this.helpURL
|
||||||
|
? <a
|
||||||
className = 'helper-link'
|
className = 'helper-link'
|
||||||
onClick = { this._onOpenHelp }>
|
onClick = { this._onOpenHelp }>
|
||||||
{ t('liveStreaming.streamIdHelp') }
|
{ t('liveStreaming.streamIdHelp') }
|
||||||
</a>
|
</a>
|
||||||
</div>
|
: null
|
||||||
: null
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user