Merge branches 'develop' and 't3chguy/remove_bluebird' of github.com:matrix-org/matrix-react-sdk into t3chguy/remove_bluebird
This commit is contained in:
commit
d3f872bf7a
24 changed files with 262 additions and 107 deletions
|
@ -133,6 +133,7 @@
|
||||||
"eslint": "^5.12.0",
|
"eslint": "^5.12.0",
|
||||||
"eslint-config-google": "^0.7.1",
|
"eslint-config-google": "^0.7.1",
|
||||||
"eslint-plugin-babel": "^5.2.1",
|
"eslint-plugin-babel": "^5.2.1",
|
||||||
|
"eslint-plugin-jest": "^23.0.4",
|
||||||
"eslint-plugin-flowtype": "^2.30.0",
|
"eslint-plugin-flowtype": "^2.30.0",
|
||||||
"eslint-plugin-react": "^7.7.0",
|
"eslint-plugin-react": "^7.7.0",
|
||||||
"eslint-plugin-react-hooks": "^2.0.1",
|
"eslint-plugin-react-hooks": "^2.0.1",
|
||||||
|
|
|
@ -23,10 +23,6 @@ limitations under the License.
|
||||||
padding-left: 84px;
|
padding-left: 84px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MessageComposer_wrapper.mx_MessageComposer_hasE2EIcon {
|
|
||||||
padding-left: 109px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_MessageComposer_replaced_wrapper {
|
.mx_MessageComposer_replaced_wrapper {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
@ -78,10 +74,10 @@ limitations under the License.
|
||||||
.mx_MessageComposer_e2eIcon.mx_E2EIcon {
|
.mx_MessageComposer_e2eIcon.mx_E2EIcon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 60px;
|
left: 60px;
|
||||||
|
width: 16px;
|
||||||
&::after {
|
height: 16px;
|
||||||
background-color: $composer-e2e-icon-color;
|
margin-right: 0; // Counteract the E2EIcon class
|
||||||
}
|
margin-left: 3px; // Counteract the E2EIcon class
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MessageComposer_noperm_error {
|
.mx_MessageComposer_noperm_error {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -57,7 +57,7 @@ import { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils";
|
||||||
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
|
||||||
import DMRoomMap from '../../utils/DMRoomMap';
|
import DMRoomMap from '../../utils/DMRoomMap';
|
||||||
import { countRoomsWithNotif } from '../../RoomNotifs';
|
import { countRoomsWithNotif } from '../../RoomNotifs';
|
||||||
import { setTheme } from "../../theme";
|
import { ThemeWatcher } from "../../theme";
|
||||||
import { storeRoomAliasInCache } from '../../RoomAliasCache';
|
import { storeRoomAliasInCache } from '../../RoomAliasCache';
|
||||||
import { defer } from "../../utils/promise";
|
import { defer } from "../../utils/promise";
|
||||||
|
|
||||||
|
@ -268,7 +268,8 @@ export default createReactClass({
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
this._themeWatchRef = SettingsStore.watchSetting("theme", null, this._onThemeChanged);
|
this._themeWatcher = new ThemeWatcher();
|
||||||
|
this._themeWatcher.start();
|
||||||
|
|
||||||
this.focusComposer = false;
|
this.focusComposer = false;
|
||||||
|
|
||||||
|
@ -355,7 +356,7 @@ export default createReactClass({
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
Lifecycle.stopMatrixClient();
|
Lifecycle.stopMatrixClient();
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
SettingsStore.unwatchSetting(this._themeWatchRef);
|
this._themeWatcher.stop();
|
||||||
window.removeEventListener("focus", this.onFocus);
|
window.removeEventListener("focus", this.onFocus);
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
this.state.resizeNotifier.removeListener("middlePanelResized", this._dispatchTimelineResize);
|
this.state.resizeNotifier.removeListener("middlePanelResized", this._dispatchTimelineResize);
|
||||||
|
@ -378,13 +379,6 @@ export default createReactClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onThemeChanged: function(settingName, roomId, atLevel, newValue) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'set_theme',
|
|
||||||
value: newValue,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
startPageChangeTimer() {
|
startPageChangeTimer() {
|
||||||
// Tor doesn't support performance
|
// Tor doesn't support performance
|
||||||
if (!performance || !performance.mark) return null;
|
if (!performance || !performance.mark) return null;
|
||||||
|
@ -666,9 +660,6 @@ export default createReactClass({
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'set_theme':
|
|
||||||
setTheme(payload.value);
|
|
||||||
break;
|
|
||||||
case 'on_logging_in':
|
case 'on_logging_in':
|
||||||
// We are now logging in, so set the state to reflect that
|
// We are now logging in, so set the state to reflect that
|
||||||
// NB. This does not touch 'ready' since if our dispatches
|
// NB. This does not touch 'ready' since if our dispatches
|
||||||
|
|
|
@ -34,7 +34,7 @@ import dis from '../../../dispatcher';
|
||||||
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||||
|
|
||||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||||
const ENABLE_REACT_PERF = false;
|
const ENABLE_REACT_PERF = false;
|
||||||
|
@ -69,8 +69,11 @@ export default class AppTile extends React.Component {
|
||||||
* @return {Object} Updated component state to be set with setState
|
* @return {Object} Updated component state to be set with setState
|
||||||
*/
|
*/
|
||||||
_getNewState(newProps) {
|
_getNewState(newProps) {
|
||||||
const widgetPermissionId = [newProps.room.roomId, encodeURIComponent(newProps.url)].join('_');
|
// This is a function to make the impact of calling SettingsStore slightly less
|
||||||
const hasPermissionToLoad = localStorage.getItem(widgetPermissionId);
|
const hasPermissionToLoad = () => {
|
||||||
|
const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", newProps.room.roomId);
|
||||||
|
return !!currentlyAllowedWidgets[newProps.eventId];
|
||||||
|
};
|
||||||
|
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
return {
|
return {
|
||||||
|
@ -78,10 +81,9 @@ export default class AppTile extends React.Component {
|
||||||
// True while the iframe content is loading
|
// True while the iframe content is loading
|
||||||
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
||||||
widgetUrl: this._addWurlParams(newProps.url),
|
widgetUrl: this._addWurlParams(newProps.url),
|
||||||
widgetPermissionId: widgetPermissionId,
|
|
||||||
// Assume that widget has permission to load if we are the user who
|
// Assume that widget has permission to load if we are the user who
|
||||||
// added it to the room, or if explicitly granted by the user
|
// added it to the room, or if explicitly granted by the user
|
||||||
hasPermissionToLoad: hasPermissionToLoad === 'true' || newProps.userId === newProps.creatorUserId,
|
hasPermissionToLoad: newProps.userId === newProps.creatorUserId || hasPermissionToLoad(),
|
||||||
error: null,
|
error: null,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
widgetPageTitle: newProps.widgetPageTitle,
|
widgetPageTitle: newProps.widgetPageTitle,
|
||||||
|
@ -446,24 +448,38 @@ export default class AppTile extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO -- Store permission in account data so that it is persisted across multiple devices */
|
|
||||||
_grantWidgetPermission() {
|
_grantWidgetPermission() {
|
||||||
console.warn('Granting permission to load widget - ', this.state.widgetUrl);
|
const roomId = this.props.room.roomId;
|
||||||
localStorage.setItem(this.state.widgetPermissionId, true);
|
console.info("Granting permission for widget to load: " + this.props.eventId);
|
||||||
this.setState({hasPermissionToLoad: true});
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
// Now that we have permission, fetch the IM token
|
current[this.props.eventId] = true;
|
||||||
this.setScalarToken();
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
|
this.setState({hasPermissionToLoad: true});
|
||||||
|
|
||||||
|
// Fetch a token for the integration manager, now that we're allowed to
|
||||||
|
this.setScalarToken();
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
// We don't really need to do anything about this - the user will just hit the button again.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_revokeWidgetPermission() {
|
_revokeWidgetPermission() {
|
||||||
console.warn('Revoking permission to load widget - ', this.state.widgetUrl);
|
const roomId = this.props.room.roomId;
|
||||||
localStorage.removeItem(this.state.widgetPermissionId);
|
console.info("Revoking permission for widget to load: " + this.props.eventId);
|
||||||
this.setState({hasPermissionToLoad: false});
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
|
current[this.props.eventId] = false;
|
||||||
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
|
this.setState({hasPermissionToLoad: false});
|
||||||
|
|
||||||
// Force the widget to be non-persistent
|
// Force the widget to be non-persistent (able to be deleted/forgotten)
|
||||||
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
PersistedElement.destroyElement(this._persistKey);
|
PersistedElement.destroyElement(this._persistKey);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
// We don't really need to do anything about this - the user will just hit the button again.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatAppTileName() {
|
formatAppTileName() {
|
||||||
|
@ -720,6 +736,7 @@ AppTile.displayName ='AppTile';
|
||||||
|
|
||||||
AppTile.propTypes = {
|
AppTile.propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
|
eventId: PropTypes.string, // required for room widgets
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
room: PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
|
|
|
@ -67,13 +67,15 @@ module.exports = createReactClass({
|
||||||
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
|
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
|
||||||
});
|
});
|
||||||
const app = WidgetUtils.makeAppConfig(
|
const app = WidgetUtils.makeAppConfig(
|
||||||
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(), persistentWidgetInRoomId,
|
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),
|
||||||
|
persistentWidgetInRoomId, appEvent.getId(),
|
||||||
);
|
);
|
||||||
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, persistentWidgetInRoomId);
|
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, persistentWidgetInRoomId);
|
||||||
const AppTile = sdk.getComponent('elements.AppTile');
|
const AppTile = sdk.getComponent('elements.AppTile');
|
||||||
return <AppTile
|
return <AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
id={app.id}
|
||||||
|
eventId={app.eventId}
|
||||||
url={app.url}
|
url={app.url}
|
||||||
name={app.name}
|
name={app.name}
|
||||||
type={app.type}
|
type={app.type}
|
||||||
|
|
|
@ -43,7 +43,8 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent {
|
||||||
if (room) {
|
if (room) {
|
||||||
const senders = [];
|
const senders = [];
|
||||||
for (const reactionEvent of reactionEvents) {
|
for (const reactionEvent of reactionEvents) {
|
||||||
const { name } = room.getMember(reactionEvent.getSender());
|
const member = room.getMember(reactionEvent.getSender());
|
||||||
|
const name = member ? member.name : reactionEvent.getSender();
|
||||||
senders.push(name);
|
senders.push(name);
|
||||||
}
|
}
|
||||||
const shortName = unicodeToShortcode(content);
|
const shortName = unicodeToShortcode(content);
|
||||||
|
|
|
@ -107,7 +107,9 @@ module.exports = createReactClass({
|
||||||
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
|
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
|
||||||
);
|
);
|
||||||
return widgets.map((ev) => {
|
return widgets.map((ev) => {
|
||||||
return WidgetUtils.makeAppConfig(ev.getStateKey(), ev.getContent(), ev.getSender());
|
return WidgetUtils.makeAppConfig(
|
||||||
|
ev.getStateKey(), ev.getContent(), ev.getSender(), ev.getRoomId(), ev.getId(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -159,6 +161,7 @@ module.exports = createReactClass({
|
||||||
return (<AppTile
|
return (<AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
id={app.id}
|
||||||
|
eventId={app.eventId}
|
||||||
url={app.url}
|
url={app.url}
|
||||||
name={app.name}
|
name={app.name}
|
||||||
type={app.type}
|
type={app.type}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import RoomViewStore from '../../../stores/RoomViewStore';
|
||||||
import Stickerpicker from './Stickerpicker';
|
import Stickerpicker from './Stickerpicker';
|
||||||
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
|
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
|
||||||
import ContentMessages from '../../../ContentMessages';
|
import ContentMessages from '../../../ContentMessages';
|
||||||
import classNames from 'classnames';
|
|
||||||
import E2EIcon from './E2EIcon';
|
import E2EIcon from './E2EIcon';
|
||||||
|
|
||||||
function ComposerAvatar(props) {
|
function ComposerAvatar(props) {
|
||||||
|
@ -353,13 +352,9 @@ export default class MessageComposer extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrapperClasses = classNames({
|
|
||||||
mx_MessageComposer_wrapper: true,
|
|
||||||
mx_MessageComposer_hasE2EIcon: !!this.props.e2eStatus,
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_MessageComposer">
|
<div className="mx_MessageComposer">
|
||||||
<div className={wrapperClasses}>
|
<div className="mx_MessageComposer_wrapper">
|
||||||
<div className="mx_MessageComposer_row">
|
<div className="mx_MessageComposer_row">
|
||||||
{ controls }
|
{ controls }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -460,13 +460,9 @@ export default class SlateMessageComposer extends React.Component {
|
||||||
|
|
||||||
const showFormatBar = this.state.showFormatting && this.state.inputState.isRichTextEnabled;
|
const showFormatBar = this.state.showFormatting && this.state.inputState.isRichTextEnabled;
|
||||||
|
|
||||||
const wrapperClasses = classNames({
|
|
||||||
mx_MessageComposer_wrapper: true,
|
|
||||||
mx_MessageComposer_hasE2EIcon: !!this.props.e2eStatus,
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_MessageComposer">
|
<div className="mx_MessageComposer">
|
||||||
<div className={wrapperClasses}>
|
<div className="mx_MessageComposer_wrapper">
|
||||||
<div className="mx_MessageComposer_row">
|
<div className="mx_MessageComposer_row">
|
||||||
{ controls }
|
{ controls }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import LanguageDropdown from "../../../elements/LanguageDropdown";
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||||
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
|
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {enumerateThemes} from "../../../../../theme";
|
import {enumerateThemes, ThemeWatcher} from "../../../../../theme";
|
||||||
import PlatformPeg from "../../../../../PlatformPeg";
|
import PlatformPeg from "../../../../../PlatformPeg";
|
||||||
import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
||||||
import sdk from "../../../../..";
|
import sdk from "../../../../..";
|
||||||
|
@ -50,6 +50,7 @@ export default class GeneralUserSettingsTab extends React.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
language: languageHandler.getCurrentLanguage(),
|
language: languageHandler.getCurrentLanguage(),
|
||||||
theme: SettingsStore.getValueAt(SettingLevel.ACCOUNT, "theme"),
|
theme: SettingsStore.getValueAt(SettingLevel.ACCOUNT, "theme"),
|
||||||
|
useSystemTheme: SettingsStore.getValueAt(SettingLevel.DEVICE, "use_system_theme"),
|
||||||
haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()),
|
haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()),
|
||||||
serverSupportsSeparateAddAndBind: null,
|
serverSupportsSeparateAddAndBind: null,
|
||||||
idServerHasUnsignedTerms: false,
|
idServerHasUnsignedTerms: false,
|
||||||
|
@ -177,16 +178,25 @@ export default class GeneralUserSettingsTab extends React.Component {
|
||||||
// so remember what the value was before we tried to set it so we can revert
|
// so remember what the value was before we tried to set it so we can revert
|
||||||
const oldTheme = SettingsStore.getValue('theme');
|
const oldTheme = SettingsStore.getValue('theme');
|
||||||
SettingsStore.setValue("theme", null, SettingLevel.ACCOUNT, newTheme).catch(() => {
|
SettingsStore.setValue("theme", null, SettingLevel.ACCOUNT, newTheme).catch(() => {
|
||||||
dis.dispatch({action: 'set_theme', value: oldTheme});
|
dis.dispatch({action: 'recheck_theme'});
|
||||||
this.setState({theme: oldTheme});
|
this.setState({theme: oldTheme});
|
||||||
});
|
});
|
||||||
this.setState({theme: newTheme});
|
this.setState({theme: newTheme});
|
||||||
// The settings watcher doesn't fire until the echo comes back from the
|
// The settings watcher doesn't fire until the echo comes back from the
|
||||||
// server, so to make the theme change immediately we need to manually
|
// server, so to make the theme change immediately we need to manually
|
||||||
// do the dispatch now
|
// do the dispatch now
|
||||||
dis.dispatch({action: 'set_theme', value: newTheme});
|
// XXX: The local echoed value appears to be unreliable, in particular
|
||||||
|
// when settings custom themes(!) so adding forceTheme to override
|
||||||
|
// the value from settings.
|
||||||
|
dis.dispatch({action: 'recheck_theme', forceTheme: newTheme});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_onUseSystemThemeChanged = (checked) => {
|
||||||
|
this.setState({useSystemTheme: checked});
|
||||||
|
dis.dispatch({action: 'recheck_theme'});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_onPasswordChangeError = (err) => {
|
_onPasswordChangeError = (err) => {
|
||||||
// TODO: Figure out a design that doesn't involve replacing the current dialog
|
// TODO: Figure out a design that doesn't involve replacing the current dialog
|
||||||
let errMsg = err.error || "";
|
let errMsg = err.error || "";
|
||||||
|
@ -297,11 +307,24 @@ export default class GeneralUserSettingsTab extends React.Component {
|
||||||
|
|
||||||
_renderThemeSection() {
|
_renderThemeSection() {
|
||||||
const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
|
const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
|
||||||
|
|
||||||
|
const themeWatcher = new ThemeWatcher();
|
||||||
|
let systemThemeSection;
|
||||||
|
if (themeWatcher.isSystemThemeSupported()) {
|
||||||
|
systemThemeSection = <div>
|
||||||
|
<SettingsFlag name="use_system_theme" level={SettingLevel.DEVICE}
|
||||||
|
onChange={this._onUseSystemThemeChanged}
|
||||||
|
/>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_themeSection">
|
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_themeSection">
|
||||||
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
|
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
|
||||||
|
{systemThemeSection}
|
||||||
<Field id="theme" label={_t("Theme")} element="select"
|
<Field id="theme" label={_t("Theme")} element="select"
|
||||||
value={this.state.theme} onChange={this._onThemeChange}>
|
value={this.state.theme} onChange={this._onThemeChange}
|
||||||
|
disabled={this.state.useSystemTheme}
|
||||||
|
>
|
||||||
{Object.entries(enumerateThemes()).map(([theme, text]) => {
|
{Object.entries(enumerateThemes()).map(([theme, text]) => {
|
||||||
return <option key={theme} value={theme}>{text}</option>;
|
return <option key={theme} value={theme}>{text}</option>;
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -364,6 +364,7 @@
|
||||||
"Automatically replace plain text Emoji": "Automatically replace plain text Emoji",
|
"Automatically replace plain text Emoji": "Automatically replace plain text Emoji",
|
||||||
"Mirror local video feed": "Mirror local video feed",
|
"Mirror local video feed": "Mirror local video feed",
|
||||||
"Enable Community Filter Panel": "Enable Community Filter Panel",
|
"Enable Community Filter Panel": "Enable Community Filter Panel",
|
||||||
|
"Match system dark mode setting": "Match system dark mode setting",
|
||||||
"Allow Peer-to-Peer for 1:1 calls": "Allow Peer-to-Peer for 1:1 calls",
|
"Allow Peer-to-Peer for 1:1 calls": "Allow Peer-to-Peer for 1:1 calls",
|
||||||
"Send analytics data": "Send analytics data",
|
"Send analytics data": "Send analytics data",
|
||||||
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",
|
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",
|
||||||
|
|
|
@ -281,6 +281,11 @@ export const SETTINGS = {
|
||||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
|
"use_system_theme": {
|
||||||
|
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
||||||
|
default: true,
|
||||||
|
displayName: _td("Match system dark mode setting"),
|
||||||
|
},
|
||||||
"webRtcAllowPeerToPeer": {
|
"webRtcAllowPeerToPeer": {
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
|
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
|
||||||
displayName: _td('Allow Peer-to-Peer for 1:1 calls'),
|
displayName: _td('Allow Peer-to-Peer for 1:1 calls'),
|
||||||
|
|
149
src/theme.js
149
src/theme.js
|
@ -19,8 +19,75 @@ import {_t} from "./languageHandler";
|
||||||
|
|
||||||
export const DEFAULT_THEME = "light";
|
export const DEFAULT_THEME = "light";
|
||||||
import Tinter from "./Tinter";
|
import Tinter from "./Tinter";
|
||||||
|
import dis from "./dispatcher";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
|
|
||||||
|
export class ThemeWatcher {
|
||||||
|
static _instance = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._themeWatchRef = null;
|
||||||
|
this._systemThemeWatchRef = null;
|
||||||
|
this._dispatcherRef = null;
|
||||||
|
|
||||||
|
// we have both here as each may either match or not match, so by having both
|
||||||
|
// we can get the tristate of dark/light/unsupported
|
||||||
|
this._preferDark = global.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
this._preferLight = global.matchMedia("(prefers-color-scheme: light)");
|
||||||
|
|
||||||
|
this._currentTheme = this.getEffectiveTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this._themeWatchRef = SettingsStore.watchSetting("theme", null, this._onChange);
|
||||||
|
this._systemThemeWatchRef = SettingsStore.watchSetting("use_system_theme", null, this._onChange);
|
||||||
|
this._preferDark.addEventListener('change', this._onChange);
|
||||||
|
this._preferLight.addEventListener('change', this._onChange);
|
||||||
|
this._dispatcherRef = dis.register(this._onAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this._preferDark.removeEventListener('change', this._onChange);
|
||||||
|
this._preferLight.removeEventListener('change', this._onChange);
|
||||||
|
SettingsStore.unwatchSetting(this._systemThemeWatchRef);
|
||||||
|
SettingsStore.unwatchSetting(this._themeWatchRef);
|
||||||
|
dis.unregister(this._dispatcherRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onChange = () => {
|
||||||
|
this.recheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onAction = (payload) => {
|
||||||
|
if (payload.action === 'recheck_theme') {
|
||||||
|
// XXX forceTheme
|
||||||
|
this.recheck(payload.forceTheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: forceTheme param aded here as local echo appears to be unreliable
|
||||||
|
// https://github.com/vector-im/riot-web/issues/11443
|
||||||
|
recheck(forceTheme) {
|
||||||
|
const oldTheme = this._currentTheme;
|
||||||
|
this._currentTheme = forceTheme === undefined ? this.getEffectiveTheme() : forceTheme;
|
||||||
|
if (oldTheme !== this._currentTheme) {
|
||||||
|
setTheme(this._currentTheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getEffectiveTheme() {
|
||||||
|
if (SettingsStore.getValue('use_system_theme')) {
|
||||||
|
if (this._preferDark.matches) return 'dark';
|
||||||
|
if (this._preferLight.matches) return 'light';
|
||||||
|
}
|
||||||
|
return SettingsStore.getValue('theme');
|
||||||
|
}
|
||||||
|
|
||||||
|
isSystemThemeSupported() {
|
||||||
|
return this._preferDark.matches || this._preferLight.matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function enumerateThemes() {
|
export function enumerateThemes() {
|
||||||
const BUILTIN_THEMES = {
|
const BUILTIN_THEMES = {
|
||||||
"light": _t("Light theme"),
|
"light": _t("Light theme"),
|
||||||
|
@ -60,30 +127,17 @@ function getCustomTheme(themeName) {
|
||||||
return customTheme;
|
return customTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the underlying theme name for the given theme. This is usually the theme or
|
|
||||||
* CSS resource that the theme relies upon to load.
|
|
||||||
* @param {string} theme The theme name to get the base of.
|
|
||||||
* @returns {string} The base theme (typically "light" or "dark").
|
|
||||||
*/
|
|
||||||
export function getBaseTheme(theme) {
|
|
||||||
if (!theme) return "light";
|
|
||||||
if (theme.startsWith("custom-")) {
|
|
||||||
const customTheme = getCustomTheme(theme.substr(7));
|
|
||||||
return customTheme.is_dark ? "dark-custom" : "light-custom";
|
|
||||||
}
|
|
||||||
|
|
||||||
return theme; // it's probably a base theme
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever someone changes the theme
|
* Called whenever someone changes the theme
|
||||||
|
* Async function that returns once the theme has been set
|
||||||
|
* (ie. the CSS has been loaded)
|
||||||
*
|
*
|
||||||
* @param {string} theme new theme
|
* @param {string} theme new theme
|
||||||
*/
|
*/
|
||||||
export function setTheme(theme) {
|
export async function setTheme(theme) {
|
||||||
if (!theme) {
|
if (!theme) {
|
||||||
theme = SettingsStore.getValue("theme");
|
const themeWatcher = new ThemeWatcher();
|
||||||
|
theme = themeWatcher.getEffectiveTheme();
|
||||||
}
|
}
|
||||||
let stylesheetName = theme;
|
let stylesheetName = theme;
|
||||||
if (theme.startsWith("custom-")) {
|
if (theme.startsWith("custom-")) {
|
||||||
|
@ -122,38 +176,41 @@ export function setTheme(theme) {
|
||||||
|
|
||||||
styleElements[stylesheetName].disabled = false;
|
styleElements[stylesheetName].disabled = false;
|
||||||
|
|
||||||
const switchTheme = function() {
|
return new Promise((resolve) => {
|
||||||
// we re-enable our theme here just in case we raced with another
|
const switchTheme = function() {
|
||||||
// theme set request as per https://github.com/vector-im/riot-web/issues/5601.
|
// we re-enable our theme here just in case we raced with another
|
||||||
// We could alternatively lock or similar to stop the race, but
|
// theme set request as per https://github.com/vector-im/riot-web/issues/5601.
|
||||||
// this is probably good enough for now.
|
// We could alternatively lock or similar to stop the race, but
|
||||||
styleElements[stylesheetName].disabled = false;
|
// this is probably good enough for now.
|
||||||
Object.values(styleElements).forEach((a) => {
|
styleElements[stylesheetName].disabled = false;
|
||||||
if (a == styleElements[stylesheetName]) return;
|
Object.values(styleElements).forEach((a) => {
|
||||||
a.disabled = true;
|
if (a == styleElements[stylesheetName]) return;
|
||||||
});
|
a.disabled = true;
|
||||||
Tinter.setTheme(theme);
|
});
|
||||||
};
|
Tinter.setTheme(theme);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
// turns out that Firefox preloads the CSS for link elements with
|
// turns out that Firefox preloads the CSS for link elements with
|
||||||
// the disabled attribute, but Chrome doesn't.
|
// the disabled attribute, but Chrome doesn't.
|
||||||
|
|
||||||
let cssLoaded = false;
|
let cssLoaded = false;
|
||||||
|
|
||||||
styleElements[stylesheetName].onload = () => {
|
styleElements[stylesheetName].onload = () => {
|
||||||
switchTheme();
|
switchTheme();
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let i = 0; i < document.styleSheets.length; i++) {
|
for (let i = 0; i < document.styleSheets.length; i++) {
|
||||||
const ss = document.styleSheets[i];
|
const ss = document.styleSheets[i];
|
||||||
if (ss && ss.href === styleElements[stylesheetName].href) {
|
if (ss && ss.href === styleElements[stylesheetName].href) {
|
||||||
cssLoaded = true;
|
cssLoaded = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (cssLoaded) {
|
if (cssLoaded) {
|
||||||
styleElements[stylesheetName].onload = undefined;
|
styleElements[stylesheetName].onload = undefined;
|
||||||
switchTheme();
|
switchTheme();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,7 @@ export default class WidgetUtils {
|
||||||
return client.setAccountData('m.widgets', userWidgets);
|
return client.setAccountData('m.widgets', userWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static makeAppConfig(appId, app, senderUserId, roomId) {
|
static makeAppConfig(appId, app, senderUserId, roomId, eventId) {
|
||||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
const user = MatrixClientPeg.get().getUser(myUserId);
|
const user = MatrixClientPeg.get().getUser(myUserId);
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -419,6 +419,7 @@ export default class WidgetUtils {
|
||||||
app.creatorUserId = senderUserId;
|
app.creatorUserId = senderUserId;
|
||||||
|
|
||||||
app.id = appId;
|
app.id = appId;
|
||||||
|
app.eventId = eventId;
|
||||||
app.name = app.name || app.type;
|
app.name = app.name || app.type;
|
||||||
|
|
||||||
if (app.data) {
|
if (app.data) {
|
||||||
|
|
72
yarn.lock
72
yarn.lock
|
@ -244,6 +244,11 @@
|
||||||
"@types/istanbul-lib-coverage" "*"
|
"@types/istanbul-lib-coverage" "*"
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
|
"@types/json-schema@^7.0.3":
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
|
||||||
|
integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
|
||||||
|
|
||||||
"@types/minimatch@*":
|
"@types/minimatch@*":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
|
@ -293,6 +298,28 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
|
"@typescript-eslint/experimental-utils@^2.5.0":
|
||||||
|
version "2.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.8.0.tgz#208b4164d175587e9b03ce6fea97d55f19c30ca9"
|
||||||
|
integrity sha512-jZ05E4SxCbbXseQGXOKf3ESKcsGxT8Ucpkp1jiVp55MGhOvZB2twmWKf894PAuVQTCgbPbJz9ZbRDqtUWzP8xA==
|
||||||
|
dependencies:
|
||||||
|
"@types/json-schema" "^7.0.3"
|
||||||
|
"@typescript-eslint/typescript-estree" "2.8.0"
|
||||||
|
eslint-scope "^5.0.0"
|
||||||
|
|
||||||
|
"@typescript-eslint/typescript-estree@2.8.0":
|
||||||
|
version "2.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.8.0.tgz#fcc3fe6532840085d29b75432c8a59895876aeca"
|
||||||
|
integrity sha512-ksvjBDTdbAQ04cR5JyFSDX113k66FxH1tAXmi+dj6hufsl/G0eMc/f1GgLjEVPkYClDbRKv+rnBFuE5EusomUw==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
eslint-visitor-keys "^1.1.0"
|
||||||
|
glob "^7.1.6"
|
||||||
|
is-glob "^4.0.1"
|
||||||
|
lodash.unescape "4.0.1"
|
||||||
|
semver "^6.3.0"
|
||||||
|
tsutils "^3.17.1"
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.8.5":
|
"@webassemblyjs/ast@1.8.5":
|
||||||
version "1.8.5"
|
version "1.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
|
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
|
||||||
|
@ -2881,6 +2908,13 @@ eslint-plugin-flowtype@^2.30.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.10"
|
lodash "^4.17.10"
|
||||||
|
|
||||||
|
eslint-plugin-jest@^23.0.4:
|
||||||
|
version "23.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.4.tgz#1ab81ffe3b16c5168efa72cbd4db14d335092aa0"
|
||||||
|
integrity sha512-OaP8hhT8chJNodUPvLJ6vl8gnalcsU/Ww1t9oR3HnGdEWjm/DdCCUXLOral+IPGAeWu/EwgVQCK/QtxALpH1Yw==
|
||||||
|
dependencies:
|
||||||
|
"@typescript-eslint/experimental-utils" "^2.5.0"
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^2.0.1:
|
eslint-plugin-react-hooks@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.0.1.tgz#e898ec26a0a335af6f7b0ad1f0bedda7143ed756"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.0.1.tgz#e898ec26a0a335af6f7b0ad1f0bedda7143ed756"
|
||||||
|
@ -2914,6 +2948,14 @@ eslint-scope@^4.0.3:
|
||||||
esrecurse "^4.1.0"
|
esrecurse "^4.1.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
|
eslint-scope@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
|
||||||
|
integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
|
||||||
|
dependencies:
|
||||||
|
esrecurse "^4.1.0"
|
||||||
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-utils@^1.3.1:
|
eslint-utils@^1.3.1:
|
||||||
version "1.4.2"
|
version "1.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
|
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
|
||||||
|
@ -2921,7 +2963,7 @@ eslint-utils@^1.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-visitor-keys "^1.0.0"
|
eslint-visitor-keys "^1.0.0"
|
||||||
|
|
||||||
eslint-visitor-keys@^1.0.0:
|
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||||
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
||||||
|
@ -3704,6 +3746,18 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
|
glob@^7.1.6:
|
||||||
|
version "7.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||||
|
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||||
|
dependencies:
|
||||||
|
fs.realpath "^1.0.0"
|
||||||
|
inflight "^1.0.4"
|
||||||
|
inherits "2"
|
||||||
|
minimatch "^3.0.4"
|
||||||
|
once "^1.3.0"
|
||||||
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
global-modules@2.0.0, global-modules@^2.0.0:
|
global-modules@2.0.0, global-modules@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
|
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
|
||||||
|
@ -5028,6 +5082,11 @@ lodash.mergewith@^4.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
||||||
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
||||||
|
|
||||||
|
lodash.unescape@4.0.1:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
|
||||||
|
integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=
|
||||||
|
|
||||||
lodash@^4.1.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1:
|
lodash@^4.1.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1:
|
||||||
version "4.17.15"
|
version "4.17.15"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||||
|
@ -7139,7 +7198,7 @@ selection-is-backward@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||||
|
|
||||||
semver@6.3.0:
|
semver@6.3.0, semver@^6.3.0:
|
||||||
version "6.3.0"
|
version "6.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||||
|
@ -8076,11 +8135,18 @@ trough@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.4.tgz#3b52b1f13924f460c3fbfd0df69b587dbcbc762e"
|
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.4.tgz#3b52b1f13924f460c3fbfd0df69b587dbcbc762e"
|
||||||
integrity sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==
|
integrity sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==
|
||||||
|
|
||||||
tslib@^1.9.0:
|
tslib@^1.8.1, tslib@^1.9.0:
|
||||||
version "1.10.0"
|
version "1.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||||
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
||||||
|
|
||||||
|
tsutils@^3.17.1:
|
||||||
|
version "3.17.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
||||||
|
integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.8.1"
|
||||||
|
|
||||||
tty-browserify@0.0.0:
|
tty-browserify@0.0.0:
|
||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||||
|
|
Loading…
Reference in a new issue