Fix #986 published claims out of order #1018
17 changed files with 251 additions and 248 deletions
|
@ -17,6 +17,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fixed sort by date of published content ([#986](https://github.com/lbryio/lbry-app/issues/986))
|
* Fixed sort by date of published content ([#986](https://github.com/lbryio/lbry-app/issues/986))
|
||||||
|
* Fix night mode start time, set to 9PM (#1050)
|
||||||
*
|
*
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
37
flow-typed/npm/mixpanel-browser_v2.11.x.js
vendored
Normal file
37
flow-typed/npm/mixpanel-browser_v2.11.x.js
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// flow-typed signature: 89b1643389fe61f97995bdeb2f68d847
|
||||||
|
// flow-typed version: dcf8c1c580/mixpanel-browser_v2.11.x/flow_>=v0.25.x
|
||||||
|
|
||||||
|
declare module 'mixpanel-browser' {
|
||||||
|
declare type People = {
|
||||||
|
set(prop: Object|String, to?: any, callback?: Function): void;
|
||||||
|
set_once(prop: Object|String, to?: any, callback?: Function): void;
|
||||||
|
increment(prop: Object|string, by?: number, callback?: Function): void;
|
||||||
|
append(prop: Object|string, value?: any, callback?: Function): void;
|
||||||
|
union(prop: Object|string, value?: any, callback?: Function): void;
|
||||||
|
track_charge(amount: number, properties?: Object, callback?: Function): void;
|
||||||
|
clear_charges(callback?: Function): void;
|
||||||
|
delete_user(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type MixpanelBrowser = {
|
||||||
|
init(token: string, config?: Object, name?: string): void;
|
||||||
|
push(item: [string, Object]): void;
|
||||||
|
disable(events?: string[]): void;
|
||||||
|
track(event_name: string, properties?: Object, callback?: Function): void;
|
||||||
|
track_links(query: Object|string, event_name: string, properties?: Object|Function): void;
|
||||||
|
track_forms(query: Object|string, event_name: string, properties?: Object|Function): void;
|
||||||
|
time_event(event_name: string): void;
|
||||||
|
register(properties: Object, days?: number): void;
|
||||||
|
register_once(properties: Object, default_value?: any, days?: number): void;
|
||||||
|
unregister(property: string): void;
|
||||||
|
identify(unique_id: string): void;
|
||||||
|
reset(): void;
|
||||||
|
get_distinct_id(): string;
|
||||||
|
alias(alias: string, original?: string): void;
|
||||||
|
set_config(config: Object): void;
|
||||||
|
get_config(): Object;
|
||||||
|
people: People;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module.exports: MixpanelBrowser;
|
||||||
|
}
|
|
@ -29,7 +29,6 @@
|
||||||
"lbry"
|
"lbry"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"amplitude-js": "^4.0.0",
|
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"country-data": "^0.0.31",
|
"country-data": "^0.0.31",
|
||||||
|
@ -45,6 +44,7 @@
|
||||||
"jshashes": "^1.0.7",
|
"jshashes": "^1.0.7",
|
||||||
"keytar-prebuild": "^4.0.4",
|
"keytar-prebuild": "^4.0.4",
|
||||||
"localforage": "^1.5.0",
|
"localforage": "^1.5.0",
|
||||||
|
"mixpanel-browser": "^2.17.1",
|
||||||
"moment": "^2.20.1",
|
"moment": "^2.20.1",
|
||||||
"npm": "^5.5.1",
|
"npm": "^5.5.1",
|
||||||
"qrcode.react": "^0.7.2",
|
"qrcode.react": "^0.7.2",
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
import { app, Menu, Tray as ElectronTray } from 'electron';
|
|
||||||
import path from 'path';
|
|
||||||
import createWindow from './createWindow';
|
|
||||||
|
|
||||||
export default class Tray {
|
|
||||||
window;
|
|
||||||
updateAttachedWindow;
|
|
||||||
tray;
|
|
||||||
|
|
||||||
constructor(window, updateAttachedWindow) {
|
|
||||||
this.window = window;
|
|
||||||
this.updateAttachedWindow = updateAttachedWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
let iconPath;
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'darwin': {
|
|
||||||
iconPath = path.join(__static, '/img/tray/mac/trayTemplate.png');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'win32': {
|
|
||||||
iconPath = path.join(__static, '/img/tray/windows/tray.ico');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
iconPath = path.join(__static, '/img/tray/default/tray.png');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tray = new ElectronTray(iconPath);
|
|
||||||
|
|
||||||
this.tray.on('double-click', () => {
|
|
||||||
if (!this.window || this.window.isDestroyed()) {
|
|
||||||
this.window = createWindow();
|
|
||||||
this.updateAttachedWindow(this.window);
|
|
||||||
} else {
|
|
||||||
this.window.show();
|
|
||||||
this.window.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tray.setToolTip('LBRY App');
|
|
||||||
|
|
||||||
const template = [
|
|
||||||
{
|
|
||||||
label: `Open ${app.getName()}`,
|
|
||||||
click: () => {
|
|
||||||
if (!this.window || this.window.isDestroyed()) {
|
|
||||||
this.window = createWindow();
|
|
||||||
this.updateAttachedWindow(this.window);
|
|
||||||
} else {
|
|
||||||
this.window.show();
|
|
||||||
this.window.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ role: 'quit' },
|
|
||||||
];
|
|
||||||
const contextMenu = Menu.buildFromTemplate(template);
|
|
||||||
this.tray.setContextMenu(contextMenu);
|
|
||||||
}
|
|
||||||
}
|
|
41
src/main/createTray.js
Normal file
41
src/main/createTray.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { app, Menu, Tray } from 'electron';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default window => {
|
||||||
|
let iconPath;
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'darwin': {
|
||||||
|
iconPath = path.join(__static, '/img/tray/mac/trayTemplate.png');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'win32': {
|
||||||
|
iconPath = path.join(__static, '/img/tray/windows/tray.ico');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
iconPath = path.join(__static, '/img/tray/default/tray.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tray = new Tray(iconPath);
|
||||||
|
|
||||||
|
tray.on('double-click', () => {
|
||||||
|
window.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
tray.setToolTip('LBRY App');
|
||||||
|
|
||||||
|
const template = [
|
||||||
|
{
|
||||||
|
label: `Open ${app.getName()}`,
|
||||||
|
click: () => {
|
||||||
|
window.show();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ role: 'quit' },
|
||||||
|
];
|
||||||
|
const contextMenu = Menu.buildFromTemplate(template);
|
||||||
|
tray.setContextMenu(contextMenu);
|
||||||
|
|
||||||
|
return tray;
|
||||||
|
};
|
|
@ -2,7 +2,7 @@ import { app, BrowserWindow, dialog } from 'electron';
|
||||||
import setupBarMenu from './menu/setupBarMenu';
|
import setupBarMenu from './menu/setupBarMenu';
|
||||||
import setupContextMenu from './menu/setupContextMenu';
|
import setupContextMenu from './menu/setupContextMenu';
|
||||||
|
|
||||||
export default deepLinkingURIArg => {
|
export default appState => {
|
||||||
let windowConfiguration = {
|
let windowConfiguration = {
|
||||||
backgroundColor: '#155B4A',
|
backgroundColor: '#155B4A',
|
||||||
minWidth: 800,
|
minWidth: 800,
|
||||||
|
@ -35,11 +35,7 @@ export default deepLinkingURIArg => {
|
||||||
|
|
||||||
let deepLinkingURI;
|
let deepLinkingURI;
|
||||||
// Protocol handler for win32
|
// Protocol handler for win32
|
||||||
if (
|
if (process.platform === 'win32' && String(process.argv[1]).startsWith('lbry')) {
|
||||||
!deepLinkingURIArg &&
|
|
||||||
process.platform === 'win32' &&
|
|
||||||
String(process.argv[1]).startsWith('lbry')
|
|
||||||
) {
|
|
||||||
// Keep only command line / deep linked arguments
|
// Keep only command line / deep linked arguments
|
||||||
// Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
|
// Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
|
||||||
// restore the original URI that was typed.
|
// restore the original URI that was typed.
|
||||||
|
@ -48,15 +44,16 @@ export default deepLinkingURIArg => {
|
||||||
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
||||||
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
||||||
deepLinkingURI = process.argv[1].replace(/\/$/, '').replace('/#', '#');
|
deepLinkingURI = process.argv[1].replace(/\/$/, '').replace('/#', '#');
|
||||||
} else {
|
|
||||||
deepLinkingURI = deepLinkingURIArg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupBarMenu();
|
setupBarMenu();
|
||||||
setupContextMenu(window);
|
setupContextMenu(window);
|
||||||
|
|
||||||
window.on('closed', () => {
|
window.on('close', event => {
|
||||||
window = null;
|
if (!appState.isQuitting) {
|
||||||
|
event.preventDefault();
|
||||||
|
window.hide();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.on('focus', () => {
|
window.on('focus', () => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import https from 'https';
|
||||||
import { shell, app, ipcMain, dialog } from 'electron';
|
import { shell, app, ipcMain, dialog } from 'electron';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
import Daemon from './Daemon';
|
import Daemon from './Daemon';
|
||||||
import Tray from './Tray';
|
import createTray from './createTray';
|
||||||
import createWindow from './createWindow';
|
import createWindow from './createWindow';
|
||||||
|
|
||||||
autoUpdater.autoDownload = true;
|
autoUpdater.autoDownload = true;
|
||||||
|
@ -32,11 +32,7 @@ let rendererWindow;
|
||||||
let tray;
|
let tray;
|
||||||
let daemon;
|
let daemon;
|
||||||
|
|
||||||
let isQuitting;
|
const appState = {};
|
||||||
|
|
||||||
const updateRendererWindow = window => {
|
|
||||||
rendererWindow = window;
|
|
||||||
};
|
|
||||||
|
|
||||||
const installExtensions = async () => {
|
const installExtensions = async () => {
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
||||||
|
@ -64,7 +60,7 @@ app.on('ready', async () => {
|
||||||
daemon = new Daemon();
|
daemon = new Daemon();
|
||||||
daemon.on('exit', () => {
|
daemon.on('exit', () => {
|
||||||
daemon = null;
|
daemon = null;
|
||||||
if (!isQuitting) {
|
if (!appState.isQuitting) {
|
||||||
dialog.showErrorBox(
|
dialog.showErrorBox(
|
||||||
'Daemon has Exited',
|
'Daemon has Exited',
|
||||||
'The daemon may have encountered an unexpected error, or another daemon instance is already running.'
|
'The daemon may have encountered an unexpected error, or another daemon instance is already running.'
|
||||||
|
@ -77,15 +73,12 @@ app.on('ready', async () => {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
await installExtensions();
|
await installExtensions();
|
||||||
}
|
}
|
||||||
rendererWindow = createWindow();
|
rendererWindow = createWindow(appState);
|
||||||
tray = new Tray(rendererWindow, updateRendererWindow);
|
tray = createTray(rendererWindow);
|
||||||
tray.create();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
rendererWindow.show();
|
||||||
// dock icon is clicked and there are no other windows open.
|
|
||||||
if (!rendererWindow) rendererWindow = createWindow();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('will-quit', event => {
|
app.on('will-quit', event => {
|
||||||
|
@ -117,7 +110,7 @@ app.on('will-quit', event => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isQuitting = true;
|
appState.isQuitting = true;
|
||||||
if (daemon) daemon.quit();
|
if (daemon) daemon.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -126,18 +119,13 @@ app.on('will-finish-launching', () => {
|
||||||
// Protocol handler for macOS
|
// Protocol handler for macOS
|
||||||
app.on('open-url', (event, URL) => {
|
app.on('open-url', (event, URL) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (rendererWindow && !rendererWindow.isDestroyed()) {
|
rendererWindow.webContents.send('open-uri-requested', URL);
|
||||||
rendererWindow.webContents.send('open-uri-requested', URL);
|
rendererWindow.show();
|
||||||
rendererWindow.show();
|
|
||||||
rendererWindow.focus();
|
|
||||||
} else {
|
|
||||||
rendererWindow = createWindow(URL);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('before-quit', () => {
|
||||||
// Subscribe to event so the app doesn't quit when closing the window.
|
appState.isQuitting = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('upgrade', (event, installerPath) => {
|
ipcMain.on('upgrade', (event, installerPath) => {
|
||||||
|
@ -224,7 +212,7 @@ ipcMain.on('set-auth-token', (event, token) => {
|
||||||
|
|
||||||
process.on('uncaughtException', error => {
|
process.on('uncaughtException', error => {
|
||||||
dialog.showErrorBox('Error Encountered', `Caught error: ${error}`);
|
dialog.showErrorBox('Error Encountered', `Caught error: ${error}`);
|
||||||
isQuitting = true;
|
appState.isQuitting = true;
|
||||||
if (daemon) daemon.quit();
|
if (daemon) daemon.quit();
|
||||||
app.exit(1);
|
app.exit(1);
|
||||||
});
|
});
|
||||||
|
@ -240,14 +228,8 @@ const isSecondInstance = app.makeSingleInstance(argv => {
|
||||||
URI = argv[1].replace(/\/$/, '').replace('/#', '#');
|
URI = argv[1].replace(/\/$/, '').replace('/#', '#');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rendererWindow && !rendererWindow.isDestroyed()) {
|
rendererWindow.webContents.send('open-uri-requested', URI);
|
||||||
rendererWindow.webContents.send('open-uri-requested', URI);
|
rendererWindow.show();
|
||||||
|
|
||||||
rendererWindow.show();
|
|
||||||
rendererWindow.focus();
|
|
||||||
} else {
|
|
||||||
rendererWindow = createWindow(URI);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isSecondInstance) {
|
if (isSecondInstance) {
|
||||||
|
|
42
src/renderer/analytics.js
Normal file
42
src/renderer/analytics.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// @flow
|
||||||
|
import mixpanel from 'mixpanel-browser';
|
||||||
|
|
||||||
|
mixpanel.init('691723e855cabb9d27a7a79002216967');
|
||||||
|
|
||||||
|
type Analytics = {
|
||||||
|
track: (string, ?Object) => void,
|
||||||
|
setUser: (Object) => void,
|
||||||
|
toggle: (boolean, ?boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
let analyticsEnabled: boolean = false;
|
||||||
|
|
||||||
|
const analytics: Analytics = {
|
||||||
|
track: (name: string, payload: ?Object): void => {
|
||||||
|
if(analyticsEnabled) {
|
||||||
|
if(payload) {
|
||||||
|
mixpanel.track(name, payload);
|
||||||
|
} else {
|
||||||
|
mixpanel.track(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setUser: (user: Object): void => {
|
||||||
|
if(user.id) {
|
||||||
|
mixpanel.identify(user.id);
|
||||||
|
}
|
||||||
|
if(user.primary_email) {
|
||||||
|
mixpanel.people.set({
|
||||||
|
"$email": user.primary_email
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggle: (enabled: boolean, logDisabled: ?boolean): void => {
|
||||||
|
if(!enabled && logDisabled) {
|
||||||
|
mixpanel.track('DISABLED');
|
||||||
|
}
|
||||||
|
analyticsEnabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default analytics;
|
|
@ -1,5 +1,4 @@
|
||||||
const { remote } = require('electron');
|
import { remote } from 'electron';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Thumbnail } from 'component/common';
|
import { Thumbnail } from 'component/common';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
|
@ -21,33 +20,21 @@ class VideoPlayer extends React.PureComponent {
|
||||||
this.togglePlayListener = this.togglePlay.bind(this);
|
this.togglePlayListener = this.togglePlay.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(next) {
|
|
||||||
const el = this.refs.media.children[0];
|
|
||||||
if (!this.props.paused && next.paused && !el.paused) el.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const container = this.refs.media;
|
const container = this.media;
|
||||||
const {
|
const { contentType, changeVolume, volume, position, claim } = this.props;
|
||||||
contentType,
|
|
||||||
downloadPath,
|
|
||||||
mediaType,
|
|
||||||
changeVolume,
|
|
||||||
volume,
|
|
||||||
position,
|
|
||||||
claim,
|
|
||||||
uri,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const loadedMetadata = e => {
|
const loadedMetadata = () => {
|
||||||
this.setState({ hasMetadata: true, startedPlaying: true });
|
this.setState({ hasMetadata: true, startedPlaying: true });
|
||||||
this.refs.media.children[0].play();
|
this.media.children[0].play();
|
||||||
};
|
};
|
||||||
const renderMediaCallback = err => {
|
|
||||||
if (err) this.setState({ unplayable: true });
|
const renderMediaCallback = error => {
|
||||||
|
if (error) this.setState({ unplayable: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle fullscreen change for the Windows platform
|
// Handle fullscreen change for the Windows platform
|
||||||
const win32FullScreenChange = e => {
|
const win32FullScreenChange = () => {
|
||||||
const win = remote.BrowserWindow.getFocusedWindow();
|
const win = remote.BrowserWindow.getFocusedWindow();
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
win.setMenu(document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu());
|
win.setMenu(document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu());
|
||||||
|
@ -61,13 +48,13 @@ class VideoPlayer extends React.PureComponent {
|
||||||
player.append(
|
player.append(
|
||||||
this.file(),
|
this.file(),
|
||||||
container,
|
container,
|
||||||
{ autoplay: false, controls: true },
|
{ autoplay: true, controls: true },
|
||||||
renderMediaCallback.bind(this)
|
renderMediaCallback.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', this.togglePlayListener);
|
document.addEventListener('keydown', this.togglePlayListener);
|
||||||
const mediaElement = this.refs.media.children[0];
|
const mediaElement = this.media.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.currentTime = position || 0;
|
mediaElement.currentTime = position || 0;
|
||||||
mediaElement.addEventListener('play', () => this.props.doPlay());
|
mediaElement.addEventListener('play', () => this.props.doPlay());
|
||||||
|
@ -87,29 +74,38 @@ class VideoPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(next) {
|
||||||
|
const el = this.media.children[0];
|
||||||
|
if (!this.props.paused && next.paused && !el.paused) el.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
const { contentType, downloadCompleted } = this.props;
|
||||||
|
const { startedPlaying } = this.state;
|
||||||
|
|
||||||
|
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
||||||
|
const container = this.media.children[0];
|
||||||
|
|
||||||
|
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
||||||
|
this.renderAudio(this.media, true);
|
||||||
|
} else {
|
||||||
|
player.render(this.file(), container, {
|
||||||
|
autoplay: true,
|
||||||
|
controls: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
document.removeEventListener('keydown', this.togglePlayListener);
|
document.removeEventListener('keydown', this.togglePlayListener);
|
||||||
const mediaElement = this.refs.media.children[0];
|
const mediaElement = this.media.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.removeEventListener('click', this.togglePlayListener);
|
mediaElement.removeEventListener('click', this.togglePlayListener);
|
||||||
}
|
}
|
||||||
this.props.doPause();
|
this.props.doPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAudio(container, autoplay) {
|
|
||||||
if (container.firstChild) {
|
|
||||||
container.firstChild.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the container
|
|
||||||
const { downloadPath } = this.props;
|
|
||||||
const audio = document.createElement('audio');
|
|
||||||
audio.autoplay = autoplay;
|
|
||||||
audio.controls = true;
|
|
||||||
audio.src = downloadPath;
|
|
||||||
container.appendChild(audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
togglePlay(event) {
|
togglePlay(event) {
|
||||||
// ignore all events except click and spacebar keydown, or input events in a form control
|
// ignore all events except click and spacebar keydown, or input events in a form control
|
||||||
if (
|
if (
|
||||||
|
@ -119,7 +115,7 @@ class VideoPlayer extends React.PureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const mediaElement = this.refs.media.children[0];
|
const mediaElement = this.media.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
if (!mediaElement.paused) {
|
if (!mediaElement.paused) {
|
||||||
mediaElement.pause();
|
mediaElement.pause();
|
||||||
|
@ -129,24 +125,6 @@ class VideoPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
const { contentType, downloadCompleted } = this.props;
|
|
||||||
const { startedPlaying } = this.state;
|
|
||||||
|
|
||||||
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
|
||||||
const container = this.refs.media.children[0];
|
|
||||||
|
|
||||||
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
|
||||||
this.renderAudio(this.refs.media, true);
|
|
||||||
} else {
|
|
||||||
player.render(this.file(), container, {
|
|
||||||
autoplay: true,
|
|
||||||
controls: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file() {
|
file() {
|
||||||
const { downloadPath, filename } = this.props;
|
const { downloadPath, filename } = this.props;
|
||||||
|
|
||||||
|
@ -162,14 +140,26 @@ class VideoPlayer extends React.PureComponent {
|
||||||
return ['audio', 'video'].indexOf(mediaType) !== -1;
|
return ['audio', 'video'].indexOf(mediaType) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderAudio(container, autoplay) {
|
||||||
|
if (container.firstChild) {
|
||||||
|
container.firstChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the container
|
||||||
|
const { downloadPath } = this.props;
|
||||||
|
const audio = document.createElement('audio');
|
||||||
|
audio.autoplay = autoplay;
|
||||||
|
audio.controls = true;
|
||||||
|
audio.src = downloadPath;
|
||||||
|
container.appendChild(audio);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { mediaType, poster } = this.props;
|
const { mediaType, poster } = this.props;
|
||||||
const { hasMetadata, unplayable } = this.state;
|
const { hasMetadata, unplayable } = this.state;
|
||||||
const noMetadataMessage = 'Waiting for metadata.';
|
const noMetadataMessage = 'Waiting for metadata.';
|
||||||
const unplayableMessage = "Sorry, looks like we can't play this file.";
|
const unplayableMessage = "Sorry, looks like we can't play this file.";
|
||||||
|
|
||||||
const needsMetadata = this.playableType();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{['audio', 'application'].indexOf(mediaType) !== -1 &&
|
{['audio', 'application'].indexOf(mediaType) !== -1 &&
|
||||||
|
@ -179,7 +169,12 @@ class VideoPlayer extends React.PureComponent {
|
||||||
!hasMetadata &&
|
!hasMetadata &&
|
||||||
!unplayable && <LoadingScreen status={noMetadataMessage} />}
|
!unplayable && <LoadingScreen status={noMetadataMessage} />}
|
||||||
{unplayable && <LoadingScreen status={unplayableMessage} spinner={false} />}
|
{unplayable && <LoadingScreen status={unplayableMessage} spinner={false} />}
|
||||||
<div ref="media" className="media" />
|
<div
|
||||||
|
ref={container => {
|
||||||
|
this.media = container;
|
||||||
|
}}
|
||||||
|
className="media"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
/* eslint-disable react/jsx-filename-extension */
|
/* eslint-disable react/jsx-filename-extension */
|
||||||
import amplitude from 'amplitude-js';
|
|
||||||
import App from 'component/app';
|
import App from 'component/app';
|
||||||
import SnackBar from 'component/snackBar';
|
import SnackBar from 'component/snackBar';
|
||||||
import SplashScreen from 'component/splash';
|
import SplashScreen from 'component/splash';
|
||||||
|
@ -17,6 +16,7 @@ import { doUserEmailVerify } from 'redux/actions/user';
|
||||||
import 'scss/all.scss';
|
import 'scss/all.scss';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import app from './app';
|
import app from './app';
|
||||||
|
import analytics from './analytics';
|
||||||
|
|
||||||
const { autoUpdater } = remote.require('electron-updater');
|
const { autoUpdater } = remote.require('electron-updater');
|
||||||
|
|
||||||
|
@ -62,15 +62,6 @@ ipcRenderer.on('window-is-focused', () => {
|
||||||
dock.setBadge('');
|
dock.setBadge('');
|
||||||
});
|
});
|
||||||
|
|
||||||
((history, ...args) => {
|
|
||||||
const { replaceState } = history;
|
|
||||||
const newHistory = history;
|
|
||||||
newHistory.replaceState = (_, __, path) => {
|
|
||||||
amplitude.getInstance().logEvent('NAVIGATION', { destination: path ? path.slice(1) : path });
|
|
||||||
return replaceState.apply(history, args);
|
|
||||||
};
|
|
||||||
})(window.history);
|
|
||||||
|
|
||||||
document.addEventListener('click', event => {
|
document.addEventListener('click', event => {
|
||||||
let { target } = event;
|
let { target } = event;
|
||||||
while (target && target !== document) {
|
while (target && target !== document) {
|
||||||
|
@ -79,12 +70,12 @@ document.addEventListener('click', event => {
|
||||||
const hrefParts = window.location.href.split('#');
|
const hrefParts = window.location.href.split('#');
|
||||||
const element = target.title || (target.textContent && target.textContent.trim());
|
const element = target.title || (target.textContent && target.textContent.trim());
|
||||||
if (element) {
|
if (element) {
|
||||||
amplitude.getInstance().logEvent('CLICK', {
|
analytics.track('CLICK', {
|
||||||
target: element,
|
target: element,
|
||||||
location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
|
location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
amplitude.getInstance().logEvent('UNMARKED_CLICK', {
|
analytics.track('UNMARKED_CLICK', {
|
||||||
location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
|
location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
|
||||||
source: target.outerHTML,
|
source: target.outerHTML,
|
||||||
});
|
});
|
||||||
|
@ -120,28 +111,18 @@ const init = () => {
|
||||||
app.store.dispatch(doDownloadLanguages());
|
app.store.dispatch(doDownloadLanguages());
|
||||||
|
|
||||||
function onDaemonReady() {
|
function onDaemonReady() {
|
||||||
lbry.status().then(info => {
|
window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again
|
||||||
amplitude.getInstance().init(
|
app.store.dispatch(doDaemonReady());
|
||||||
// Amplitude API Key
|
|
||||||
'0b130efdcbdbf86ec2f7f9eff354033e',
|
|
||||||
info.lbry_id,
|
|
||||||
null,
|
|
||||||
() => {
|
|
||||||
window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again
|
|
||||||
app.store.dispatch(doDaemonReady());
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<div>
|
<div>
|
||||||
<App />
|
<App />
|
||||||
<SnackBar />
|
<SnackBar />
|
||||||
</div>
|
</div>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
document.getElementById('app')
|
document.getElementById('app')
|
||||||
);
|
);
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.sessionStorage.getItem('loaded') === 'y') {
|
if (window.sessionStorage.getItem('loaded') === 'y') {
|
||||||
|
|
|
@ -15,7 +15,7 @@ jsonrpc.call = (
|
||||||
return response.json().then(json => {
|
return response.json().then(json => {
|
||||||
let error;
|
let error;
|
||||||
if (json.error) {
|
if (json.error) {
|
||||||
error = new Error(json.error);
|
error = new Error(json.error.message);
|
||||||
} else {
|
} else {
|
||||||
error = new Error('Protocol error with unknown response signature');
|
error = new Error('Protocol error with unknown response signature');
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ class SettingsPage extends React.PureComponent {
|
||||||
this.state = {
|
this.state = {
|
||||||
clearingCache: false,
|
clearingCache: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCache() {
|
clearCache() {
|
||||||
|
@ -62,11 +64,16 @@ class SettingsPage extends React.PureComponent {
|
||||||
|
|
||||||
onThemeChange(event) {
|
onThemeChange(event) {
|
||||||
const { value } = event.target;
|
const { value } = event.target;
|
||||||
|
|
||||||
|
if (value === 'dark') {
|
||||||
|
this.onAutomaticDarkModeChange(false);
|
||||||
|
}
|
||||||
|
|
||||||
this.props.setClientSetting(settings.THEME, value);
|
this.props.setClientSetting(settings.THEME, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAutomaticDarkModeChange(event) {
|
onAutomaticDarkModeChange(value) {
|
||||||
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, event.target.checked);
|
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
onInstantPurchaseEnabledChange(enabled) {
|
onInstantPurchaseEnabledChange(enabled) {
|
||||||
|
@ -143,6 +150,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<main className="main--single-column">
|
||||||
<SubHeader />
|
<SubHeader />
|
||||||
|
@ -325,8 +333,9 @@ class SettingsPage extends React.PureComponent {
|
||||||
|
|
||||||
<FormRow
|
<FormRow
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={this.onAutomaticDarkModeChange.bind(this)}
|
disabled={theme === 'dark'}
|
||||||
defaultChecked={automaticDarkModeEnabled}
|
onChange={(e) => this.onAutomaticDarkModeChange(e.target.checked)}
|
||||||
|
checked={automaticDarkModeEnabled}
|
||||||
label={__('Automatic dark mode (9pm to 8am)')}
|
label={__('Automatic dark mode (9pm to 8am)')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import { selectHistoryIndex, selectHistoryStack } from 'redux/selectors/navigation';
|
import { selectHistoryIndex, selectHistoryStack } from 'redux/selectors/navigation';
|
||||||
import { toQueryString } from 'util/query_params';
|
import { toQueryString } from 'util/query_params';
|
||||||
|
import analytics from 'analytics';
|
||||||
|
|
||||||
export function doNavigate(path, params = {}, options = {}) {
|
export function doNavigate(path, params = {}, options = {}) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
@ -13,6 +14,8 @@ export function doNavigate(path, params = {}, options = {}) {
|
||||||
url += `?${toQueryString(params)}`;
|
url += `?${toQueryString(params)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
analytics.track('NAVIGATION', { destination: url });
|
||||||
|
|
||||||
const { scrollY } = options;
|
const { scrollY } = options;
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -2,15 +2,16 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
import * as SETTINGS from 'constants/settings';
|
import * as SETTINGS from 'constants/settings';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import Http from 'http';
|
import Http from 'http';
|
||||||
|
|
||||||
import Lbry from 'lbry';
|
import Lbry from 'lbry';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import analytics from 'analytics';
|
||||||
|
|
||||||
const UPDATE_IS_NIGHT_INTERVAL = 10 * 60 * 1000;
|
const UPDATE_IS_NIGHT_INTERVAL = 10 * 60 * 1000;
|
||||||
|
|
||||||
export function doFetchDaemonSettings() {
|
export function doFetchDaemonSettings() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
Lbry.settings_get().then(settings => {
|
Lbry.settings_get().then(settings => {
|
||||||
|
analytics.toggle(settings.share_usage_data);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -27,6 +28,7 @@ export function doSetDaemonSetting(key, value) {
|
||||||
newSettings[key] = value;
|
newSettings[key] = value;
|
||||||
Lbry.settings_set(newSettings).then(newSettings);
|
Lbry.settings_set(newSettings).then(newSettings);
|
||||||
Lbry.settings_get().then(settings => {
|
Lbry.settings_get().then(settings => {
|
||||||
|
analytics.toggle(settings.share_usage_data, true);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
type: ACTIONS.DAEMON_SETTINGS_RECEIVED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -69,7 +71,7 @@ export function doUpdateIsNight() {
|
||||||
return {
|
return {
|
||||||
type: ACTIONS.UPDATE_IS_NIGHT,
|
type: ACTIONS.UPDATE_IS_NIGHT,
|
||||||
data: { isNight: (() => {
|
data: { isNight: (() => {
|
||||||
const startNightMoment = moment('19:00', 'HH:mm');
|
const startNightMoment = moment('21:00', 'HH:mm');
|
||||||
const endNightMoment = moment('8:00', 'HH:mm');
|
const endNightMoment = moment('8:00', 'HH:mm');
|
||||||
return !(momentNow.isAfter(endNightMoment) && momentNow.isBefore(startNightMoment));
|
return !(momentNow.isAfter(endNightMoment) && momentNow.isBefore(startNightMoment));
|
||||||
})()
|
})()
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
selectUserCountryCode,
|
selectUserCountryCode,
|
||||||
} from 'redux/selectors/user';
|
} from 'redux/selectors/user';
|
||||||
import rewards from 'rewards';
|
import rewards from 'rewards';
|
||||||
|
import analytics from 'analytics';
|
||||||
|
|
||||||
export function doFetchInviteStatus() {
|
export function doFetchInviteStatus() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
@ -42,6 +43,7 @@ export function doAuthenticate() {
|
||||||
});
|
});
|
||||||
Lbryio.authenticate()
|
Lbryio.authenticate()
|
||||||
.then(user => {
|
.then(user => {
|
||||||
|
analytics.setUser(user);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.AUTHENTICATION_SUCCESS,
|
type: ACTIONS.AUTHENTICATION_SUCCESS,
|
||||||
data: { user },
|
data: { user },
|
||||||
|
@ -66,6 +68,7 @@ export function doUserFetch() {
|
||||||
});
|
});
|
||||||
Lbryio.getCurrentUser()
|
Lbryio.getCurrentUser()
|
||||||
.then(user => {
|
.then(user => {
|
||||||
|
analytics.setUser(user);
|
||||||
dispatch(doRewardList());
|
dispatch(doRewardList());
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -2,10 +2,10 @@ import { remote } from 'electron';
|
||||||
|
|
||||||
const application = remote.app;
|
const application = remote.app;
|
||||||
const { dock } = application;
|
const { dock } = application;
|
||||||
const win = remote.BrowserWindow.getFocusedWindow();
|
const browserWindow = remote.getCurrentWindow();
|
||||||
const setBadge = text => {
|
const setBadge = text => {
|
||||||
if (!dock) return;
|
if (!dock) return;
|
||||||
if (win.isFocused()) return;
|
if (browserWindow.isFocused()) return;
|
||||||
|
|
||||||
dock.setBadge(text);
|
dock.setBadge(text);
|
||||||
};
|
};
|
||||||
|
|
49
yarn.lock
49
yarn.lock
|
@ -79,13 +79,6 @@
|
||||||
lodash "^4.2.0"
|
lodash "^4.2.0"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@segment/top-domain@^3.0.0":
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@segment/top-domain/-/top-domain-3.0.0.tgz#02e5a5a4fd42a9f6cf886b05e82f104012a3c3a7"
|
|
||||||
dependencies:
|
|
||||||
component-cookie "^1.1.2"
|
|
||||||
component-url "^0.2.1"
|
|
||||||
|
|
||||||
"@types/node@^7.0.18":
|
"@types/node@^7.0.18":
|
||||||
version "7.0.52"
|
version "7.0.52"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716"
|
||||||
|
@ -217,16 +210,6 @@ amdefine@>=0.0.4:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||||
|
|
||||||
amplitude-js@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/amplitude-js/-/amplitude-js-4.0.0.tgz#70bbc0ec893b01d00453d3765f78bc0f32a395cc"
|
|
||||||
dependencies:
|
|
||||||
"@segment/top-domain" "^3.0.0"
|
|
||||||
blueimp-md5 "^2.10.0"
|
|
||||||
json3 "^3.3.2"
|
|
||||||
lodash "^4.17.4"
|
|
||||||
ua-parser-js "github:amplitude/ua-parser-js#ed538f1"
|
|
||||||
|
|
||||||
ansi-align@^2.0.0:
|
ansi-align@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||||
|
@ -1400,10 +1383,6 @@ bluebird@^3.4.7, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@~3.5.0:
|
||||||
version "3.5.1"
|
version "3.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||||
|
|
||||||
blueimp-md5@^2.10.0:
|
|
||||||
version "2.10.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.10.0.tgz#02f0843921f90dca14f5b8920a38593201d6964d"
|
|
||||||
|
|
||||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
|
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
|
||||||
version "4.11.8"
|
version "4.11.8"
|
||||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
||||||
|
@ -2081,16 +2060,6 @@ compare-version@^0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080"
|
resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080"
|
||||||
|
|
||||||
component-cookie@^1.1.2:
|
|
||||||
version "1.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/component-cookie/-/component-cookie-1.1.3.tgz#053e14a3bd7748154f55724fd39a60c01994ebed"
|
|
||||||
dependencies:
|
|
||||||
debug "*"
|
|
||||||
|
|
||||||
component-url@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/component-url/-/component-url-0.2.1.tgz#4e4f4799c43ead9fd3ce91b5a305d220208fee47"
|
|
||||||
|
|
||||||
compressible@~2.0.11:
|
compressible@~2.0.11:
|
||||||
version "2.0.12"
|
version "2.0.12"
|
||||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66"
|
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66"
|
||||||
|
@ -2451,18 +2420,18 @@ date-now@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||||
|
|
||||||
debug@*, debug@^3.0.0, debug@^3.0.1, debug@^3.1.0:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
|
||||||
dependencies:
|
|
||||||
ms "2.0.0"
|
|
||||||
|
|
||||||
debug@2, debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8:
|
debug@2, debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
|
debug@^3.0.0, debug@^3.0.1, debug@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
|
dependencies:
|
||||||
|
ms "2.0.0"
|
||||||
|
|
||||||
debuglog@^1.0.1:
|
debuglog@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
|
||||||
|
@ -5799,6 +5768,10 @@ mixin-object@^2.0.1:
|
||||||
for-in "^0.1.3"
|
for-in "^0.1.3"
|
||||||
is-extendable "^0.1.1"
|
is-extendable "^0.1.1"
|
||||||
|
|
||||||
|
mixpanel-browser@^2.17.1:
|
||||||
|
version "2.17.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mixpanel-browser/-/mixpanel-browser-2.17.1.tgz#1b90a0478ec912f35f761c52e08d4228fc37867f"
|
||||||
|
|
||||||
mkdirp@0.5, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
|
mkdirp@0.5, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
|
||||||
version "0.5.1"
|
version "0.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||||
|
@ -8795,7 +8768,7 @@ typo-js@*:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.0.3.tgz#54d8ebc7949f1a7810908b6002c6841526c99d5a"
|
resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.0.3.tgz#54d8ebc7949f1a7810908b6002c6841526c99d5a"
|
||||||
|
|
||||||
ua-parser-js@^0.7.9, "ua-parser-js@github:amplitude/ua-parser-js#ed538f1":
|
ua-parser-js@^0.7.9:
|
||||||
version "0.7.10"
|
version "0.7.10"
|
||||||
resolved "https://codeload.github.com/amplitude/ua-parser-js/tar.gz/ed538f16f5c6ecd8357da989b617d4f156dcf35d"
|
resolved "https://codeload.github.com/amplitude/ua-parser-js/tar.gz/ed538f16f5c6ecd8357da989b617d4f156dcf35d"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue