Introduce internationalisation
This commit is contained in:
parent
1c4f76e3b8
commit
2efa8b057e
|
@ -4,6 +4,7 @@ import Droplist, { Item, Group } from '@atlaskit/droplist';
|
||||||
import HelpIcon from '@atlaskit/icon/glyph/question-circle';
|
import HelpIcon from '@atlaskit/icon/glyph/question-circle';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import { openExternalLink } from '../../utils';
|
import { openExternalLink } from '../../utils';
|
||||||
|
@ -20,7 +21,7 @@ type State = {
|
||||||
/**
|
/**
|
||||||
* Help button for Navigation Bar.
|
* Help button for Navigation Bar.
|
||||||
*/
|
*/
|
||||||
export default class HelpButton extends Component< *, State> {
|
class HelpButton extends Component<*, State> {
|
||||||
/**
|
/**
|
||||||
* Initializes a new {@code HelpButton} instance.
|
* Initializes a new {@code HelpButton} instance.
|
||||||
*
|
*
|
||||||
|
@ -87,6 +88,8 @@ export default class HelpButton extends Component< *, State> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Droplist
|
<Droplist
|
||||||
isOpen = { this.state.droplistOpen }
|
isOpen = { this.state.droplistOpen }
|
||||||
|
@ -94,27 +97,29 @@ export default class HelpButton extends Component< *, State> {
|
||||||
onOpenChange = { this._onOpenChange }
|
onOpenChange = { this._onOpenChange }
|
||||||
position = 'right bottom'
|
position = 'right bottom'
|
||||||
trigger = { <HelpIcon /> }>
|
trigger = { <HelpIcon /> }>
|
||||||
<Group heading = 'Help'>
|
<Group heading = { t('help') } >
|
||||||
<Item onActivate = { this._onTermsClick }>
|
<Item onActivate = { this._onTermsClick }>
|
||||||
Terms
|
{ t('termsLink') }
|
||||||
</Item>
|
</Item>
|
||||||
<Item onActivate = { this._onPrivacyClick }>
|
<Item onActivate = { this._onPrivacyClick }>
|
||||||
Privacy
|
{ t('privacyLink') }
|
||||||
</Item>
|
</Item>
|
||||||
<Item onActivate = { this._onSendFeedbackClick }>
|
<Item onActivate = { this._onSendFeedbackClick }>
|
||||||
Send Feedback
|
{ t('sendFeedbackLink') }
|
||||||
</Item>
|
</Item>
|
||||||
<Item onActivate = { this._onAboutClick }>
|
<Item onActivate = { this._onAboutClick }>
|
||||||
About
|
{ t('aboutLink') }
|
||||||
</Item>
|
</Item>
|
||||||
<Item onActivate = { this._onSourceClick }>
|
<Item onActivate = { this._onSourceClick }>
|
||||||
Source
|
{ t('sourceLink') }
|
||||||
</Item>
|
</Item>
|
||||||
<Item>
|
<Item>
|
||||||
Version: { version }
|
{ t('versionLabel', { version }) }
|
||||||
</Item>
|
</Item>
|
||||||
</Group>
|
</Group>
|
||||||
</Droplist>
|
</Droplist>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTranslation()(HelpButton);
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { closeDrawer } from '../../navbar';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Always on Top Windows Spotlight Component.
|
|
||||||
*/
|
|
||||||
class AlwaysOnTopWindowSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code StartMutedTogglesSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'always-on-top-window' } >
|
|
||||||
You can toggle whether you want to enable the "always-on-top" window,
|
|
||||||
which is displayed when the main window loses focus.
|
|
||||||
This will be applied to all conferences.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
|
|
||||||
dispatch(continueOnboarding());
|
|
||||||
|
|
||||||
// FIXME: find a better way to do this.
|
|
||||||
setTimeout(() => {
|
|
||||||
dispatch(closeDrawer());
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(AlwaysOnTopWindowSpotlight);
|
|
|
@ -1,70 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Conference URL Spotlight Component.
|
|
||||||
*/
|
|
||||||
class ConferenceURLSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code ComponentURLSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'bottom center'
|
|
||||||
target = { 'conference-url' } >
|
|
||||||
Enter the name (or full URL) of the room you want to join. You
|
|
||||||
may make a name up, just let others know so they enter the same
|
|
||||||
name.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(ConferenceURLSpotlight);
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Email Setting Spotlight Component.
|
|
||||||
*/
|
|
||||||
class EmailSettingSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code EmailSettingSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'email-setting' } >
|
|
||||||
The email you enter here will be part of your user profile.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(EmailSettingSpotlight);
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name Setting Spotlight Component.
|
|
||||||
*/
|
|
||||||
class NameSettingSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code NameSettingSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'name-setting' } >
|
|
||||||
This will be your display name, others will see you with this
|
|
||||||
name.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(NameSettingSpotlight);
|
|
||||||
|
|
|
@ -38,9 +38,9 @@ class Onboarding extends Component<Props, *> {
|
||||||
const steps = onboardingSteps[section];
|
const steps = onboardingSteps[section];
|
||||||
|
|
||||||
if (_activeOnboarding && steps.includes(_activeOnboarding)) {
|
if (_activeOnboarding && steps.includes(_activeOnboarding)) {
|
||||||
const ActiveOnboarding = onboardingComponents[_activeOnboarding];
|
const { type: ActiveOnboarding, ...props } = onboardingComponents[_activeOnboarding];
|
||||||
|
|
||||||
return <ActiveOnboarding />;
|
return <ActiveOnboarding { ...props } />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
import { Modal } from '@atlaskit/onboarding';
|
import { Modal } from '@atlaskit/onboarding';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
import { compose } from 'redux';
|
||||||
|
|
||||||
import OnboardingModalImage from '../../../images/onboarding.png';
|
import OnboardingModalImage from '../../../images/onboarding.png';
|
||||||
|
|
||||||
|
@ -18,6 +20,11 @@ type Props = {
|
||||||
* Redux dispatch.
|
* Redux dispatch.
|
||||||
*/
|
*/
|
||||||
dispatch: Dispatch<*>;
|
dispatch: Dispatch<*>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translation function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,21 +50,23 @@ class OnboardingModal extends Component<Props, *> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
actions = { [
|
actions = { [
|
||||||
{
|
{
|
||||||
onClick: this._next,
|
onClick: this._next,
|
||||||
text: 'Start Tour'
|
text: t('onboarding.startTour')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onClick: this._skip,
|
onClick: this._skip,
|
||||||
text: 'Skip'
|
text: t('onboarding.skip')
|
||||||
}
|
}
|
||||||
] }
|
] }
|
||||||
heading = { `Welcome to ${config.appName}` }
|
heading = { t('onboarding.welcome', { appName: config.appName }) }
|
||||||
image = { OnboardingModalImage } >
|
image = { OnboardingModalImage } >
|
||||||
<p> Let us show you around!</p>
|
<p> { t('onboarding.letUsShowYouAround') }</p>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -86,4 +95,4 @@ class OnboardingModal extends Component<Props, *> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect()(OnboardingModal);
|
export default compose(connect(), withTranslation())(OnboardingModal);
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { Spotlight } from '@atlaskit/onboarding';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
|
import { continueOnboarding } from '../actions';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redux dispatch.
|
||||||
|
*/
|
||||||
|
dispatch: Dispatch<*>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spotlight dialog placement.
|
||||||
|
*/
|
||||||
|
dialogPlacement: String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when "next" clicked.
|
||||||
|
*/
|
||||||
|
onNext: Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translation function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spotlight target.
|
||||||
|
*/
|
||||||
|
target: String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spotlight text.
|
||||||
|
*/
|
||||||
|
text: String;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const OnboardingSpotlight = (props: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spotlight
|
||||||
|
actions = { [
|
||||||
|
{
|
||||||
|
onClick: () => {
|
||||||
|
props.dispatch(continueOnboarding());
|
||||||
|
props.onNext && props.onNext(props);
|
||||||
|
},
|
||||||
|
text: t('onboarding.next')
|
||||||
|
}
|
||||||
|
] }
|
||||||
|
dialogPlacement = { props.dialogPlacement }
|
||||||
|
target = { props.target } >
|
||||||
|
{ t(props.text) }
|
||||||
|
</Spotlight>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default connect()(OnboardingSpotlight);
|
|
@ -1,69 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server Setting Spotlight Component.
|
|
||||||
*/
|
|
||||||
class ServerSettingSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code ServerSettingSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'server-setting' } >
|
|
||||||
This will be the server where your conferences will take place.
|
|
||||||
You can use your own, but you don't need to!
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(ServerSettingSpotlight);
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server Setting Spotlight Component.
|
|
||||||
*/
|
|
||||||
class ServerTimeoutSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code ServerSettingSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'right top'
|
|
||||||
target = { 'server-timeout' } >
|
|
||||||
Timeout to join a meeting, if the meeting hasn't been joined before the timeout hits, it's cancelled.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(ServerTimeoutSpotlight);
|
|
|
@ -1,68 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { openDrawer } from '../../navbar';
|
|
||||||
import { SettingsDrawer } from '../../settings';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings Drawer Spotlight Component.
|
|
||||||
*/
|
|
||||||
class SettingsDrawerSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code SettingsDrawerSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'settings-drawer-button' }
|
|
||||||
targetOnClick = { this._next }>
|
|
||||||
Click here to open the settings drawer.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component and opens Settings Drawer and shows
|
|
||||||
* onboarding.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(openDrawer(SettingsDrawer));
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(SettingsDrawerSpotlight);
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Spotlight } from '@atlaskit/onboarding';
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { continueOnboarding } from '../actions';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start Muted Toggles Spotlight Component.
|
|
||||||
*/
|
|
||||||
class StartMutedTogglesSpotlight extends Component<Props, *> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code StartMutedTogglesSpotlight} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._next = this._next.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Spotlight
|
|
||||||
actions = { [
|
|
||||||
{
|
|
||||||
onClick: this._next,
|
|
||||||
text: 'Next'
|
|
||||||
}
|
|
||||||
] }
|
|
||||||
dialogPlacement = 'top right'
|
|
||||||
target = { 'start-muted-toggles' } >
|
|
||||||
You can toggle if you want to start with your audio or video
|
|
||||||
muted here. This will be applied to all conferences.
|
|
||||||
</Spotlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_next: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the spotlight component.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_next() {
|
|
||||||
this.props.dispatch(continueOnboarding());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect()(StartMutedTogglesSpotlight);
|
|
||||||
|
|
|
@ -1,10 +1,3 @@
|
||||||
export { default as ConferenceURLSpotlight } from './ConferenceURLSpotlight';
|
export { default as OnboardingSpotlight } from './OnboardingSpotlight';
|
||||||
export { default as EmailSettingSpotlight } from './EmailSettingSpotlight';
|
|
||||||
export { default as NameSettingSpotlight } from './NameSettingSpotlight';
|
|
||||||
export { default as Onboarding } from './Onboarding';
|
export { default as Onboarding } from './Onboarding';
|
||||||
export { default as OnboardingModal } from './OnboardingModal';
|
export { default as OnboardingModal } from './OnboardingModal';
|
||||||
export { default as ServerSettingSpotlight } from './ServerSettingSpotlight';
|
|
||||||
export { default as ServerTimeoutSpotlight } from './ServerTimeoutSpotlight';
|
|
||||||
export { default as SettingsDrawerSpotlight } from './SettingsDrawerSpotlight';
|
|
||||||
export { default as StartMutedTogglesSpotlight } from './StartMutedTogglesSpotlight';
|
|
||||||
export { default as AlwaysOnTopWindowSpotlight } from './AlwaysOnTopWindowSpotlight';
|
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import { OnboardingModal, OnboardingSpotlight } from './components';
|
||||||
import {
|
import { openDrawer, closeDrawer } from '../navbar';
|
||||||
OnboardingModal,
|
import { SettingsDrawer } from '../settings';
|
||||||
ConferenceURLSpotlight,
|
|
||||||
SettingsDrawerSpotlight,
|
|
||||||
NameSettingSpotlight,
|
|
||||||
EmailSettingSpotlight,
|
|
||||||
StartMutedTogglesSpotlight,
|
|
||||||
ServerSettingSpotlight,
|
|
||||||
ServerTimeoutSpotlight,
|
|
||||||
AlwaysOnTopWindowSpotlight
|
|
||||||
} from './components';
|
|
||||||
|
|
||||||
export const advenaceSettingsSteps = [
|
export const advenaceSettingsSteps = [
|
||||||
'server-setting',
|
'server-setting',
|
||||||
|
@ -33,13 +24,57 @@ export const onboardingSteps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onboardingComponents = {
|
export const onboardingComponents = {
|
||||||
'onboarding-modal': OnboardingModal,
|
'onboarding-modal': { type: OnboardingModal },
|
||||||
'conference-url': ConferenceURLSpotlight,
|
'conference-url': {
|
||||||
'settings-drawer-button': SettingsDrawerSpotlight,
|
type: OnboardingSpotlight,
|
||||||
'name-setting': NameSettingSpotlight,
|
dialogPlacement: 'bottom center',
|
||||||
'email-setting': EmailSettingSpotlight,
|
target: 'conference-url',
|
||||||
'start-muted-toggles': StartMutedTogglesSpotlight,
|
text: 'onboarding.conferenceUrl'
|
||||||
'server-setting': ServerSettingSpotlight,
|
},
|
||||||
'server-timeout': ServerTimeoutSpotlight,
|
'settings-drawer-button': {
|
||||||
'always-on-top-window': AlwaysOnTopWindowSpotlight
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'settings-drawer-button',
|
||||||
|
text: 'onboarding.settingsDrawerButton',
|
||||||
|
onNext: (props: OnboardingSpotlight.props) => props.dispatch(openDrawer(SettingsDrawer))
|
||||||
|
},
|
||||||
|
'name-setting': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'name-setting',
|
||||||
|
text: 'onboarding.nameSetting'
|
||||||
|
},
|
||||||
|
'email-setting': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'email-setting',
|
||||||
|
text: 'onboarding.emailSetting'
|
||||||
|
},
|
||||||
|
'start-muted-toggles': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'start-muted-toggles',
|
||||||
|
text: 'onboarding.startMutedToggles'
|
||||||
|
},
|
||||||
|
'server-setting': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'server-setting',
|
||||||
|
text: 'onboarding.serverSetting'
|
||||||
|
},
|
||||||
|
'server-timeout': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'server-timeout',
|
||||||
|
text: 'onboarding.serverTimeout'
|
||||||
|
},
|
||||||
|
'always-on-top-window': {
|
||||||
|
type: OnboardingSpotlight,
|
||||||
|
dialogPlacement: 'top right',
|
||||||
|
target: 'always-on-top-window',
|
||||||
|
text: 'onboarding.alwaysOnTop',
|
||||||
|
onNext: (props: OnboardingSpotlight.props) => setTimeout(() => {
|
||||||
|
props.dispatch(closeDrawer());
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import { setWindowAlwaysOnTop } from '../actions';
|
|
||||||
|
|
||||||
import ToggleWithLabel from './ToggleWithLabel';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Window Always on Top value in (redux) state.
|
|
||||||
*/
|
|
||||||
_alwaysOnTopWindowEnabled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Window always open on top placed in Settings Drawer.
|
|
||||||
*/
|
|
||||||
class AlwaysOnTopWindowToggle extends Component<Props> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code AlwaysOnTopWindowToggle} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this._onAlwaysOnTopWindowToggleChange
|
|
||||||
= this._onAlwaysOnTopWindowToggleChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ToggleWithLabel
|
|
||||||
isDefaultChecked = { this.props._alwaysOnTopWindowEnabled }
|
|
||||||
label = 'Always on Top Window'
|
|
||||||
onChange = { this._onAlwaysOnTopWindowToggleChange }
|
|
||||||
value = { this.props._alwaysOnTopWindowEnabled } />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onAlwaysOnTopWindowToggleChange: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles alwaysOnTopWindowEnabled.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onAlwaysOnTopWindowToggleChange() {
|
|
||||||
const { _alwaysOnTopWindowEnabled } = this.props;
|
|
||||||
const newState = !_alwaysOnTopWindowEnabled;
|
|
||||||
|
|
||||||
this.props.dispatch(setWindowAlwaysOnTop(newState));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps (parts of) the redux state to the React props.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The redux state.
|
|
||||||
* @returns {{
|
|
||||||
* _alwaysOnTopWindowEnabled: boolean,
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state: Object) {
|
|
||||||
return {
|
|
||||||
_alwaysOnTopWindowEnabled: state.settings.alwaysOnTopWindowEnabled
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(AlwaysOnTopWindowToggle);
|
|
|
@ -3,7 +3,9 @@
|
||||||
import { FieldTextStateless } from '@atlaskit/field-text';
|
import { FieldTextStateless } from '@atlaskit/field-text';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { compose } from 'redux';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
@ -22,6 +24,11 @@ type Props = {
|
||||||
* Default Jitsi Meet Server Timeout in (redux) store.
|
* Default Jitsi Meet Server Timeout in (redux) store.
|
||||||
*/
|
*/
|
||||||
_serverTimeout: number;
|
_serverTimeout: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translation function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -64,6 +71,8 @@ class ServerTimeoutField extends Component<Props, State> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit = { this._onServerTimeoutSubmit }>
|
<Form onSubmit = { this._onServerTimeoutSubmit }>
|
||||||
<FieldTextStateless
|
<FieldTextStateless
|
||||||
|
@ -71,7 +80,7 @@ class ServerTimeoutField extends Component<Props, State> {
|
||||||
= { 'Invalid Timeout' }
|
= { 'Invalid Timeout' }
|
||||||
isInvalid = { !this.state.isValid }
|
isInvalid = { !this.state.isValid }
|
||||||
isValidationHidden = { this.state.isValid }
|
isValidationHidden = { this.state.isValid }
|
||||||
label = 'Server Timeout (in seconds)'
|
label = { t('settings.serverTimeout') }
|
||||||
onBlur = { this._onServerTimeoutSubmit }
|
onBlur = { this._onServerTimeoutSubmit }
|
||||||
onChange = { this._onServerTimeoutChange }
|
onChange = { this._onServerTimeoutChange }
|
||||||
placeholder = { config.defaultServerTimeout }
|
placeholder = { config.defaultServerTimeout }
|
||||||
|
@ -138,4 +147,4 @@ function _mapStateToProps(state: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(ServerTimeoutField);
|
export default compose(connect(_mapStateToProps), withTranslation())(ServerTimeoutField);
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
import { FieldTextStateless } from '@atlaskit/field-text';
|
import { FieldTextStateless } from '@atlaskit/field-text';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
import { compose } from 'redux';
|
||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import { getExternalApiURL } from '../../utils';
|
import { getExternalApiURL } from '../../utils';
|
||||||
|
@ -23,6 +25,11 @@ type Props = {
|
||||||
* Default Jitsi Meet Server URL in (redux) store.
|
* Default Jitsi Meet Server URL in (redux) store.
|
||||||
*/
|
*/
|
||||||
_serverURL: string;
|
_serverURL: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translation function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -65,14 +72,15 @@ class ServerURLField extends Component<Props, State> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit = { this._onServerURLSubmit }>
|
<Form onSubmit = { this._onServerURLSubmit }>
|
||||||
<FieldTextStateless
|
<FieldTextStateless
|
||||||
invalidMessage
|
invalidMessage = { t('settings.invalidServer') }
|
||||||
= { 'Invalid Server URL or external API not enabled' }
|
|
||||||
isInvalid = { !this.state.isValid }
|
isInvalid = { !this.state.isValid }
|
||||||
isValidationHidden = { this.state.isValid }
|
isValidationHidden = { this.state.isValid }
|
||||||
label = 'Server URL'
|
label = { t('settings.serverUrl') }
|
||||||
onBlur = { this._onServerURLSubmit }
|
onBlur = { this._onServerURLSubmit }
|
||||||
onChange = { this._onServerURLChange }
|
onChange = { this._onServerURLChange }
|
||||||
placeholder = { config.defaultServerURL }
|
placeholder = { config.defaultServerURL }
|
||||||
|
@ -150,4 +158,4 @@ function _mapStateToProps(state: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(ServerURLField);
|
export default compose(connect(_mapStateToProps), withTranslation())(ServerURLField);
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
|
import ToggleWithLabel from './ToggleWithLabel';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redux dispatch.
|
||||||
|
*/
|
||||||
|
dispatch: Dispatch<*>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The label for the toggle.
|
||||||
|
*/
|
||||||
|
label: String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the setting.
|
||||||
|
*/
|
||||||
|
settingName: String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to produce setting change events.
|
||||||
|
*/
|
||||||
|
settingChangeEvent: Function;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps (parts of) the redux state to the React props.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state.
|
||||||
|
* @param {Object} ownProps - The props of the redux wrapper component.
|
||||||
|
* @returns {Object} A props object including the current value of the setting.
|
||||||
|
*/
|
||||||
|
const mapStateToProps = (state, ownProps: Props) => {
|
||||||
|
return {
|
||||||
|
value: state.settings[ownProps.settingName],
|
||||||
|
...ownProps
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component to control a single boolean redux setting.
|
||||||
|
*
|
||||||
|
* @param {Object} props - The props provided by mapStateToProps.
|
||||||
|
* @returns {Object} A rendered toggle component with correct state.
|
||||||
|
*/
|
||||||
|
function SettingToggle(props: Object) {
|
||||||
|
const onChange = useCallback(
|
||||||
|
() => props.dispatch(props.settingChangeEvent(!props.value)));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToggleWithLabel
|
||||||
|
isDefaultChecked = { props.value }
|
||||||
|
label = { props.label }
|
||||||
|
onChange = { onChange }
|
||||||
|
value = { props.value } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(SettingToggle);
|
|
@ -7,18 +7,22 @@ import { SpotlightTarget } from '@atlaskit/onboarding';
|
||||||
import Panel from '@atlaskit/panel';
|
import Panel from '@atlaskit/panel';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
import { compose } from 'redux';
|
||||||
|
|
||||||
import { closeDrawer, DrawerContainer, Logo } from '../../navbar';
|
import { closeDrawer, DrawerContainer, Logo } from '../../navbar';
|
||||||
import { Onboarding, advenaceSettingsSteps, startOnboarding } from '../../onboarding';
|
import { Onboarding, advenaceSettingsSteps, startOnboarding } from '../../onboarding';
|
||||||
import { Form, SettingsContainer, TogglesContainer } from '../styled';
|
import { Form, SettingsContainer, TogglesContainer } from '../styled';
|
||||||
import { setEmail, setName } from '../actions';
|
import {
|
||||||
|
setEmail, setName, setWindowAlwaysOnTop,
|
||||||
|
setStartWithAudioMuted, setStartWithVideoMuted
|
||||||
|
} from '../actions';
|
||||||
|
|
||||||
import AlwaysOnTopWindowToggle from './AlwaysOnTopWindowToggle';
|
import SettingToggle from './SettingToggle';
|
||||||
import ServerURLField from './ServerURLField';
|
import ServerURLField from './ServerURLField';
|
||||||
import ServerTimeoutField from './ServerTimeoutField';
|
import ServerTimeoutField from './ServerTimeoutField';
|
||||||
import StartMutedToggles from './StartMutedToggles';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
@ -46,6 +50,11 @@ type Props = {
|
||||||
* Name of the user.
|
* Name of the user.
|
||||||
*/
|
*/
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translation function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,9 +101,11 @@ class SettingsDrawer extends Component<Props, *> {
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AkCustomDrawer
|
<AkCustomDrawer
|
||||||
backIcon = { <ArrowLeft label = 'Back' /> }
|
backIcon = { <ArrowLeft label = { t('settings.back') } /> }
|
||||||
isOpen = { this.props.isOpen }
|
isOpen = { this.props.isOpen }
|
||||||
onBackButton = { this._onBackButton }
|
onBackButton = { this._onBackButton }
|
||||||
primaryIcon = { <Logo /> } >
|
primaryIcon = { <Logo /> } >
|
||||||
|
@ -104,7 +115,7 @@ class SettingsDrawer extends Component<Props, *> {
|
||||||
name = 'name-setting'>
|
name = 'name-setting'>
|
||||||
<Form onSubmit = { this._onNameFormSubmit }>
|
<Form onSubmit = { this._onNameFormSubmit }>
|
||||||
<FieldText
|
<FieldText
|
||||||
label = 'Name'
|
label = { t('settings.name') }
|
||||||
onBlur = { this._onNameBlur }
|
onBlur = { this._onNameBlur }
|
||||||
shouldFitContainer = { true }
|
shouldFitContainer = { true }
|
||||||
type = 'text'
|
type = 'text'
|
||||||
|
@ -115,7 +126,7 @@ class SettingsDrawer extends Component<Props, *> {
|
||||||
name = 'email-setting'>
|
name = 'email-setting'>
|
||||||
<Form onSubmit = { this._onEmailFormSubmit }>
|
<Form onSubmit = { this._onEmailFormSubmit }>
|
||||||
<FieldText
|
<FieldText
|
||||||
label = 'Email'
|
label = { t('settings.email') }
|
||||||
onBlur = { this._onEmailBlur }
|
onBlur = { this._onEmailBlur }
|
||||||
shouldFitContainer = { true }
|
shouldFitContainer = { true }
|
||||||
type = 'text'
|
type = 'text'
|
||||||
|
@ -125,11 +136,18 @@ class SettingsDrawer extends Component<Props, *> {
|
||||||
<TogglesContainer>
|
<TogglesContainer>
|
||||||
<SpotlightTarget
|
<SpotlightTarget
|
||||||
name = 'start-muted-toggles'>
|
name = 'start-muted-toggles'>
|
||||||
<StartMutedToggles />
|
<SettingToggle
|
||||||
|
label = { t('settings.startWithAudioMuted') }
|
||||||
|
settingChangeEvent = { setStartWithAudioMuted }
|
||||||
|
settingName = 'startWithAudioMuted' />
|
||||||
|
<SettingToggle
|
||||||
|
label = { t('settings.startWithVideoMuted') }
|
||||||
|
settingChangeEvent = { setStartWithVideoMuted }
|
||||||
|
settingName = 'startWithVideoMuted' />
|
||||||
</SpotlightTarget>
|
</SpotlightTarget>
|
||||||
</TogglesContainer>
|
</TogglesContainer>
|
||||||
<Panel
|
<Panel
|
||||||
header = 'Advanced Settings'
|
header = { t('settings.advancedSettings') }
|
||||||
isDefaultExpanded = { this.props._isOnboardingAdvancedSettings }>
|
isDefaultExpanded = { this.props._isOnboardingAdvancedSettings }>
|
||||||
<SpotlightTarget name = 'server-setting'>
|
<SpotlightTarget name = 'server-setting'>
|
||||||
<ServerURLField />
|
<ServerURLField />
|
||||||
|
@ -140,7 +158,10 @@ class SettingsDrawer extends Component<Props, *> {
|
||||||
<TogglesContainer>
|
<TogglesContainer>
|
||||||
<SpotlightTarget
|
<SpotlightTarget
|
||||||
name = 'always-on-top-window'>
|
name = 'always-on-top-window'>
|
||||||
<AlwaysOnTopWindowToggle />
|
<SettingToggle
|
||||||
|
label = { t('settings.alwaysOnTopWindow') }
|
||||||
|
settingChangeEvent = { setWindowAlwaysOnTop }
|
||||||
|
settingName = 'alwaysOnTopWindowEnabled' />
|
||||||
</SpotlightTarget>
|
</SpotlightTarget>
|
||||||
</TogglesContainer>
|
</TogglesContainer>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
@ -236,4 +257,4 @@ function _mapStateToProps(state: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(SettingsDrawer);
|
export default compose(connect(_mapStateToProps), withTranslation())(SettingsDrawer);
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import type { Dispatch } from 'redux';
|
|
||||||
|
|
||||||
import {
|
|
||||||
setStartWithAudioMuted,
|
|
||||||
setStartWithVideoMuted
|
|
||||||
} from '../actions';
|
|
||||||
|
|
||||||
import ToggleWithLabel from './ToggleWithLabel';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redux dispatch.
|
|
||||||
*/
|
|
||||||
dispatch: Dispatch<*>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start with Audio Muted value in (redux) state.
|
|
||||||
*/
|
|
||||||
_startWithAudioMuted: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start with Video Muted value in (redux) state.
|
|
||||||
*/
|
|
||||||
_startWithVideoMuted: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start with Audio Muted value in (local) state.
|
|
||||||
*/
|
|
||||||
startWithAudioMuted: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start with Video Muted value in (local) state.
|
|
||||||
*/
|
|
||||||
startWithVideoMuted: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start Muted toggles for audio and video placed in Settings Drawer.
|
|
||||||
*/
|
|
||||||
class StartMutedToggles extends Component<Props, State> {
|
|
||||||
/**
|
|
||||||
* Initializes a new {@code StartMutedToggles} instance.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
startWithAudioMuted: false,
|
|
||||||
startWithVideoMuted: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this._onAudioToggleChange = this._onAudioToggleChange.bind(this);
|
|
||||||
this._onVideoToggleChange = this._onVideoToggleChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This updates the startWithAudioMuted and startWithVideoMuted in (local)
|
|
||||||
* state when there is a change in redux store.
|
|
||||||
*
|
|
||||||
* @param {Props} props - New props of the component.
|
|
||||||
* @returns {State} - New state of the component.
|
|
||||||
*/
|
|
||||||
static getDerivedStateFromProps(props) {
|
|
||||||
return {
|
|
||||||
startWithAudioMuted: props._startWithAudioMuted,
|
|
||||||
startWithVideoMuted: props._startWithVideoMuted
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function of component.
|
|
||||||
*
|
|
||||||
* @returns {ReactElement}
|
|
||||||
*/
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ToggleWithLabel
|
|
||||||
isDefaultChecked = { this.props._startWithAudioMuted }
|
|
||||||
label = 'Start with Audio muted'
|
|
||||||
onChange = { this._onAudioToggleChange }
|
|
||||||
value = { this.state.startWithAudioMuted } />
|
|
||||||
<ToggleWithLabel
|
|
||||||
isDefaultChecked = { this.props._startWithVideoMuted }
|
|
||||||
label = 'Start with Video muted'
|
|
||||||
onChange = { this._onVideoToggleChange }
|
|
||||||
value = { this.state.startWithVideoMuted } />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onAudioToggleChange: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles startWithAudioMuted.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onAudioToggleChange() {
|
|
||||||
const { startWithAudioMuted } = this.state;
|
|
||||||
|
|
||||||
this.props.dispatch(setStartWithAudioMuted(!startWithAudioMuted));
|
|
||||||
}
|
|
||||||
|
|
||||||
_onVideoToggleChange: (*) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles startWithVideoMuted.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onVideoToggleChange() {
|
|
||||||
const { startWithVideoMuted } = this.state;
|
|
||||||
|
|
||||||
this.props.dispatch(setStartWithVideoMuted(!startWithVideoMuted));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps (parts of) the redux state to the React props.
|
|
||||||
*
|
|
||||||
* @param {Object} state - The redux state.
|
|
||||||
* @returns {{
|
|
||||||
* _startWithAudioMuted: boolean,
|
|
||||||
* _startWithVideoMuted: boolean
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _mapStateToProps(state: Object) {
|
|
||||||
return {
|
|
||||||
_startWithAudioMuted: state.settings.startWithAudioMuted,
|
|
||||||
_startWithVideoMuted: state.settings.startWithVideoMuted
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(_mapStateToProps)(StartMutedToggles);
|
|
|
@ -8,6 +8,8 @@ import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||||
|
|
||||||
import { generateRoomWithoutSeparator } from 'js-utils/random';
|
import { generateRoomWithoutSeparator } from 'js-utils/random';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { withTranslation } from 'react-i18next';
|
||||||
|
import { compose } from 'redux';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { push } from 'react-router-redux';
|
import { push } from 'react-router-redux';
|
||||||
|
@ -19,7 +21,6 @@ import { createConferenceObjectFromURL } from '../../utils';
|
||||||
|
|
||||||
import { Body, FieldWrapper, Form, Header, Label, Wrapper } from '../styled';
|
import { Body, FieldWrapper, Form, Header, Label, Wrapper } from '../styled';
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +32,11 @@ type Props = {
|
||||||
* React Router location object.
|
* React Router location object.
|
||||||
*/
|
*/
|
||||||
location: Object;
|
location: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I18next translate function.
|
||||||
|
*/
|
||||||
|
t: Function;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -252,12 +258,13 @@ class Welcome extends Component<Props, State> {
|
||||||
_renderHeader() {
|
_renderHeader() {
|
||||||
const locationState = this.props.location.state;
|
const locationState = this.props.location.state;
|
||||||
const locationError = locationState && locationState.error;
|
const locationError = locationState && locationState.error;
|
||||||
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header>
|
<Header>
|
||||||
<SpotlightTarget name = 'conference-url'>
|
<SpotlightTarget name = 'conference-url'>
|
||||||
<Form onSubmit = { this._onFormSubmit }>
|
<Form onSubmit = { this._onFormSubmit }>
|
||||||
<Label>{ 'Enter a name for your conference or a Jitsi URL' } </Label>
|
<Label>{ t('enterConferenceNameOrUrl') } </Label>
|
||||||
<FieldWrapper>
|
<FieldWrapper>
|
||||||
<FieldTextStateless
|
<FieldTextStateless
|
||||||
autoFocus = { true }
|
autoFocus = { true }
|
||||||
|
@ -272,7 +279,7 @@ class Welcome extends Component<Props, State> {
|
||||||
appearance = 'primary'
|
appearance = 'primary'
|
||||||
onClick = { this._onJoin }
|
onClick = { this._onJoin }
|
||||||
type = 'button'>
|
type = 'button'>
|
||||||
GO
|
{ t('go') }
|
||||||
</Button>
|
</Button>
|
||||||
</FieldWrapper>
|
</FieldWrapper>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -306,4 +313,4 @@ class Welcome extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect()(Welcome);
|
export default compose(connect(), withTranslation())(Welcome);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
const languages = {
|
||||||
|
en: { translation: require('./lang/en.json') }
|
||||||
|
};
|
||||||
|
|
||||||
|
const detectedLocale = window.jitsiNodeAPI.getLocale();
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(initReactI18next)
|
||||||
|
.init({
|
||||||
|
resources: languages,
|
||||||
|
lng: detectedLocale,
|
||||||
|
fallbackLng: 'en',
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false // not needed for react as it escapes by default
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
moment.locale(detectedLocale);
|
||||||
|
|
||||||
|
export default i18n;
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"enterConferenceNameOrUrl": "Enter a name for your conference or a Jitsi URL",
|
||||||
|
"go": "GO",
|
||||||
|
"help": "Help",
|
||||||
|
"termsLink": "Terms",
|
||||||
|
"privacyLink": "Privacy",
|
||||||
|
"sendFeedbackLink": "Send Feedback",
|
||||||
|
"aboutLink": "About",
|
||||||
|
"sourceLink": "Source Code",
|
||||||
|
"versionLabel": "Version: {{version}}",
|
||||||
|
"onboarding": {
|
||||||
|
"startTour": "Start Tour",
|
||||||
|
"skip": "Skip",
|
||||||
|
"welcome": "Welcome to {{appName}}",
|
||||||
|
"letUsShowYouAround": "Let us show you around!",
|
||||||
|
"next": "Next",
|
||||||
|
"conferenceUrl": "Enter the name (or full URL) of the room you want to join. You may make a name up, just let others know so they enter the same name.",
|
||||||
|
"settingsDrawerButton": "Click here to open the settings drawer.",
|
||||||
|
"nameSetting": "This will be your display name, others will see you with this name.",
|
||||||
|
"emailSetting": "The email you enter here will be part of your user profile.",
|
||||||
|
"startMutedToggles": "You can toggle if you want to start with your audio or video muted here. This will be applied to all conferences.",
|
||||||
|
"serverSetting": "This will be the server where your conferences will take place. You can use your own, but you don't need to!",
|
||||||
|
"serverTimeout": "Timeout to join a meeting, if the meeting hasn't been joined before the timeout hits, it's cancelled.",
|
||||||
|
"alwaysOnTop": "You can toggle whether you want to enable the \"always-on-top\" window, which is displayed when the main window loses focus. This will be applied to all conferences."
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"back": "Back",
|
||||||
|
"name": "Name",
|
||||||
|
"email": "Email",
|
||||||
|
"advancedSettings": "Advanced Settings",
|
||||||
|
"alwaysOnTopWindow": "Always on Top Window",
|
||||||
|
"startWithAudioMuted": "Start with Audio muted",
|
||||||
|
"startWithVideoMuted": "Start with Video muted",
|
||||||
|
"invalidServer": "Invalid Server URL or external API not enabled",
|
||||||
|
"serverUrl": "Server URL",
|
||||||
|
"serverTimeout": "Server Timeout (in seconds)"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
<style>
|
<style>
|
||||||
body, html {
|
body, html {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
*/
|
*/
|
||||||
import '@atlaskit/css-reset';
|
import '@atlaskit/css-reset';
|
||||||
|
|
||||||
|
import Spinner from '@atlaskit/spinner';
|
||||||
import { SpotlightManager } from '@atlaskit/onboarding';
|
import { SpotlightManager } from '@atlaskit/onboarding';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component, Suspense } from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { PersistGate } from 'redux-persist/integration/react';
|
import { PersistGate } from 'redux-persist/integration/react';
|
||||||
|
@ -15,6 +16,8 @@ import { PersistGate } from 'redux-persist/integration/react';
|
||||||
import { App } from './features/app';
|
import { App } from './features/app';
|
||||||
import { persistor, store } from './features/redux';
|
import { persistor, store } from './features/redux';
|
||||||
|
|
||||||
|
import './i18n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component encapsulating App component with redux store using provider.
|
* Component encapsulating App component with redux store using provider.
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +34,9 @@ class Root extends Component<*> {
|
||||||
loading = { null }
|
loading = { null }
|
||||||
persistor = { persistor }>
|
persistor = { persistor }>
|
||||||
<SpotlightManager>
|
<SpotlightManager>
|
||||||
<App />
|
<Suspense fallback = { <Spinner /> } >
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
</SpotlightManager>
|
</SpotlightManager>
|
||||||
</PersistGate>
|
</PersistGate>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const createElectronStorage = require('redux-persist-electron-storage');
|
const createElectronStorage = require('redux-persist-electron-storage');
|
||||||
const { ipcRenderer, shell } = require('electron');
|
const { ipcRenderer, shell, remote } = require('electron');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ window.jitsiNodeAPI = {
|
||||||
openExternalLink,
|
openExternalLink,
|
||||||
jitsiMeetElectronUtils,
|
jitsiMeetElectronUtils,
|
||||||
shellOpenExternal: shell.openExternal,
|
shellOpenExternal: shell.openExternal,
|
||||||
|
getLocale: remote.app.getLocale,
|
||||||
ipc: {
|
ipc: {
|
||||||
on: (channel, listener) => {
|
on: (channel, listener) => {
|
||||||
if (!whitelistedIpcChannels.includes(channel)) {
|
if (!whitelistedIpcChannels.includes(channel)) {
|
||||||
|
|
|
@ -9624,6 +9624,14 @@
|
||||||
"terser": "^4.6.3"
|
"terser": "^4.6.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"html-parse-stringify2": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
|
||||||
|
"requires": {
|
||||||
|
"void-elements": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"html-webpack-plugin": {
|
"html-webpack-plugin": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.4.tgz",
|
||||||
|
@ -9692,6 +9700,14 @@
|
||||||
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=",
|
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"i18next": {
|
||||||
|
"version": "19.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.4.5.tgz",
|
||||||
|
"integrity": "sha512-aLvSsURoupi3x9IndmV6+m3IGhzLzhYv7Gw+//K3ovdliyGcFRV0I1MuddI0Bk/zR7BG1U+kJOjeHFUcUIdEgg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -12170,14 +12186,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.6.3",
|
"version": "16.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.8.0.tgz",
|
||||||
"integrity": "sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw==",
|
"integrity": "sha512-g+nikW2D48kqgWSPwNo0NH9tIGG3DsQFlrtrQ1kj6W77z5ahyIHG0w8kPpz4Sdj6gyLnz0lEd/xsjOoGge2MYQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"scheduler": "^0.11.2"
|
"scheduler": "^0.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-addons-text-content": {
|
"react-addons-text-content": {
|
||||||
|
@ -12203,14 +12219,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "16.6.3",
|
"version": "16.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.0.tgz",
|
||||||
"integrity": "sha512-8ugJWRCWLGXy+7PmNh8WJz3g1TaTUt1XyoIcFN+x0Zbkoz+KKdUyx1AQLYJdbFXjuF41Nmjn5+j//rxvhFjgSQ==",
|
"integrity": "sha512-dBzoAGYZpW9Yggp+CzBPC7q1HmWSeRc93DWrwbskmG1eHJWznZB/p0l/Sm+69leIGUS91AXPB/qB3WcPnKx8Sw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"scheduler": "^0.11.2"
|
"scheduler": "^0.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-focus-lock": {
|
"react-focus-lock": {
|
||||||
|
@ -12233,6 +12249,15 @@
|
||||||
"prop-types": "^15.6.1"
|
"prop-types": "^15.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-i18next": {
|
||||||
|
"version": "11.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.5.1.tgz",
|
||||||
|
"integrity": "sha512-2VSx+dClvmCJTgrw9Nrof4EkggMlzo4s/YZPEUAdI7gU2HTksapkGtFPARzpeTk+3k1zY+Xl6pLHc0LYvsRWAQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.3.1",
|
||||||
|
"html-parse-stringify2": "2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.10.2",
|
"version": "16.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz",
|
||||||
|
@ -12863,9 +12888,9 @@
|
||||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
},
|
},
|
||||||
"scheduler": {
|
"scheduler": {
|
||||||
"version": "0.11.3",
|
"version": "0.13.6",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz",
|
||||||
"integrity": "sha512-i9X9VRRVZDd3xZw10NY5Z2cVMbdYg6gqFecfj79USv1CFN+YrJ3gIPRKf1qlY+Sxly4djoKdfx1T+m9dnRB8kQ==",
|
"integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
|
@ -14382,6 +14407,11 @@
|
||||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"void-elements": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
|
||||||
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||||
|
|
|
@ -116,12 +116,14 @@
|
||||||
"electron-updater": "4.2.5",
|
"electron-updater": "4.2.5",
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"history": "4.10.1",
|
"history": "4.10.1",
|
||||||
|
"i18next": "19.4.5",
|
||||||
"jitsi-meet-electron-utils": "github:jitsi/jitsi-meet-electron-utils#v2.0.7",
|
"jitsi-meet-electron-utils": "github:jitsi/jitsi-meet-electron-utils#v2.0.7",
|
||||||
"js-utils": "github:jitsi/js-utils#cf11996bd866fdb47326c59a5d3bc24be17282d4",
|
"js-utils": "github:jitsi/js-utils#cf11996bd866fdb47326c59a5d3bc24be17282d4",
|
||||||
"moment": "2.23.0",
|
"moment": "2.23.0",
|
||||||
"mousetrap": "1.6.2",
|
"mousetrap": "1.6.2",
|
||||||
"react": "16.6.3",
|
"react": "16.8.0",
|
||||||
"react-dom": "16.6.3",
|
"react-dom": "16.8.0",
|
||||||
|
"react-i18next": "11.5.1",
|
||||||
"react-redux": "5.1.1",
|
"react-redux": "5.1.1",
|
||||||
"react-router-redux": "5.0.0-alpha.9",
|
"react-router-redux": "5.0.0-alpha.9",
|
||||||
"redux": "4.0.1",
|
"redux": "4.0.1",
|
||||||
|
|
Loading…
Reference in New Issue