Propmt when a api key can not be use + house keeping (#173)
* chore: remove old files * chore: change JS tests to TS, delete dummy tests * chore: bump manifests version
This commit is contained in:
committed by
GitHub
parent
fe49f50b65
commit
35543489e5
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"editor.codeActionsOnSave": ["source.organizeImports", "source.fixAll"]
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/* This is a fix for Bootstrap requiring jQuery */
|
|
||||||
global.jQuery = require('jquery');
|
|
||||||
require('bootstrap');
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var ReactDOM = require('react-dom');
|
|
||||||
|
|
||||||
// React components
|
|
||||||
var WakaTime = require('./components/WakaTime.jsx');
|
|
||||||
|
|
||||||
ReactDOM.render(<WakaTime />, document.getElementById('wakatime'));
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
var classNames = require('classnames');
|
|
||||||
|
|
||||||
var Alert = reactCreateClass({
|
|
||||||
render: function () {
|
|
||||||
return <div className={classNames('alert', 'alert-' + this.props.type)}>{this.props.text}</div>;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = Alert;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
var MainList = reactCreateClass({
|
|
||||||
_openOptionsPage: function () {
|
|
||||||
if (browser.runtime.openOptionsPage) {
|
|
||||||
// New way to open options pages, if supported (Chrome 42+).
|
|
||||||
browser.runtime.openOptionsPage();
|
|
||||||
} else {
|
|
||||||
// Reasonable fallback.
|
|
||||||
window.open(browser.runtime.getURL('options.html'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var loginLogoutButton = function () {
|
|
||||||
if (that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<a href="#" className="list-group-item" onClick={that.props.logoutUser}>
|
|
||||||
<i className="fa fa-fw fa-sign-out"></i>
|
|
||||||
Logout
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a target="_blank" href="https://wakatime.com/login" className="list-group-item">
|
|
||||||
<i className="fa fa-fw fa-sign-in"></i>
|
|
||||||
Login
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// If logging is enabled, display that info to user
|
|
||||||
var loggingStatus = function () {
|
|
||||||
if (that.props.loggingEnabled === true && that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
onClick={that.props.disableLogging}
|
|
||||||
className="btn btn-danger btn-block"
|
|
||||||
>
|
|
||||||
Disable logging
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (that.props.loggingEnabled === false && that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
onClick={that.props.enableLogging}
|
|
||||||
className="btn btn-success btn-block"
|
|
||||||
>
|
|
||||||
Enable logging
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var totalTimeLoggedToday = function () {
|
|
||||||
if (that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-xs-12">
|
|
||||||
<blockquote>
|
|
||||||
<p>{that.props.totalTimeLoggedToday}</p>
|
|
||||||
<small>
|
|
||||||
<cite>TOTAL TIME LOGGED TODAY</cite>
|
|
||||||
</small>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{totalTimeLoggedToday()}
|
|
||||||
|
|
||||||
{loggingStatus()}
|
|
||||||
|
|
||||||
<div className="list-group">
|
|
||||||
<a href="#" className="list-group-item" onClick={this._openOptionsPage}>
|
|
||||||
<i className="fa fa-fw fa-cogs"></i>
|
|
||||||
Options
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{loginLogoutButton()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = MainList;
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
|
|
||||||
var NavBar = reactCreateClass({
|
|
||||||
render: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var signedInAs = function () {
|
|
||||||
if (that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<p className="navbar-text">
|
|
||||||
Signed in as <b>{that.props.user.full_name}</b>
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var dashboard = function () {
|
|
||||||
if (that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://wakatime.com/dashboard">
|
|
||||||
<i className="fa fa-fw fa-tachometer"></i>
|
|
||||||
Dashboard
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var customRules = function () {
|
|
||||||
if (that.props.loggedIn === true) {
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://wakatime.com/settings/rules">
|
|
||||||
<i className="fa fa-fw fa-filter"></i>
|
|
||||||
Custom Rules
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className="navbar navbar-default" role="navigation">
|
|
||||||
<div className="container-fluid">
|
|
||||||
<div className="navbar-header">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="navbar-toggle collapsed"
|
|
||||||
data-toggle="collapse"
|
|
||||||
data-target="#bs-example-navbar-collapse-1"
|
|
||||||
>
|
|
||||||
<span className="sr-only">Toggle navigation</span>
|
|
||||||
<i className="fa fa-fw fa-cogs"></i>
|
|
||||||
</button>
|
|
||||||
<a target="_blank" className="navbar-brand" href="https://wakatime.com">
|
|
||||||
WakaTime
|
|
||||||
<img src="graphics/wakatime-logo-48.png" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
|
||||||
{signedInAs()}
|
|
||||||
<ul className="nav navbar-nav">
|
|
||||||
{customRules()}
|
|
||||||
{dashboard()}
|
|
||||||
<li className="dropdown">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className="dropdown-toggle"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
role="button"
|
|
||||||
aria-expanded="false"
|
|
||||||
>
|
|
||||||
<i className="fa fa-fw fa-info"></i>
|
|
||||||
About
|
|
||||||
<span className="caret"></span>
|
|
||||||
</a>
|
|
||||||
<ul className="dropdown-menu" role="menu">
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://github.com/wakatime/chrome-wakatime/issues">
|
|
||||||
<i className="fa fa-fw fa-bug"></i>
|
|
||||||
Report an Issue
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a target="_blank" href="https://github.com/wakatime/chrome-wakatime">
|
|
||||||
<i className="fa fa-fw fa-github"></i>
|
|
||||||
View on GitHub
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = NavBar;
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
var ReactCSSTransitionGroup = require('react-transition-group/CSSTransitionGroup');
|
|
||||||
|
|
||||||
var config = require('../config');
|
|
||||||
|
|
||||||
// React components
|
|
||||||
var Alert = require('./Alert.jsx');
|
|
||||||
var SitesList = require('./SitesList.jsx');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* One thing to keep in mind is that you cannot use this.refs.blacklist if
|
|
||||||
* the blacklist select box is not being rendered on the form.
|
|
||||||
*
|
|
||||||
* @type {*|Function}
|
|
||||||
*/
|
|
||||||
var Options = reactCreateClass({
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
theme: config.theme,
|
|
||||||
blacklist: '',
|
|
||||||
whitelist: '',
|
|
||||||
loggingType: config.loggingType,
|
|
||||||
loggingStyle: config.loggingStyle,
|
|
||||||
displayAlert: false,
|
|
||||||
alertType: config.alert.success.type,
|
|
||||||
alertText: config.alert.success.text,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function () {
|
|
||||||
this.restoreSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
restoreSettings: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
browser.storage.sync
|
|
||||||
.get({
|
|
||||||
theme: config.theme,
|
|
||||||
blacklist: '',
|
|
||||||
whitelist: '',
|
|
||||||
loggingType: config.loggingType,
|
|
||||||
loggingStyle: config.loggingStyle,
|
|
||||||
})
|
|
||||||
.then(function (items) {
|
|
||||||
that.setState({
|
|
||||||
theme: items.theme,
|
|
||||||
blacklist: items.blacklist,
|
|
||||||
whitelist: items.whitelist,
|
|
||||||
loggingType: items.loggingType,
|
|
||||||
loggingStyle: items.loggingStyle,
|
|
||||||
});
|
|
||||||
|
|
||||||
that.refs.theme.value = items.theme;
|
|
||||||
that.refs.loggingType.value = items.loggingType;
|
|
||||||
that.refs.loggingStyle.value = items.loggingStyle;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleSubmit: function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this.saveSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
saveSettings: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var theme = this.refs.theme.value.trim();
|
|
||||||
var loggingType = this.refs.loggingType.value.trim();
|
|
||||||
var loggingStyle = this.refs.loggingStyle.value.trim();
|
|
||||||
// Trimming blacklist and whitelist removes blank lines and spaces.
|
|
||||||
var blacklist = that.state.blacklist.trim();
|
|
||||||
var whitelist = that.state.whitelist.trim();
|
|
||||||
|
|
||||||
// Sync options with google storage.
|
|
||||||
browser.storage.sync
|
|
||||||
.set({
|
|
||||||
theme: theme,
|
|
||||||
blacklist: blacklist,
|
|
||||||
whitelist: whitelist,
|
|
||||||
loggingType: loggingType,
|
|
||||||
loggingStyle: loggingStyle,
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
// Set state to be newly entered values.
|
|
||||||
that.setState({
|
|
||||||
theme: theme,
|
|
||||||
blacklist: blacklist,
|
|
||||||
whitelist: whitelist,
|
|
||||||
loggingType: loggingType,
|
|
||||||
loggingStyle: loggingStyle,
|
|
||||||
displayAlert: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_displayBlackOrWhiteList: function () {
|
|
||||||
var loggingStyle = this.refs.loggingStyle.value.trim();
|
|
||||||
|
|
||||||
this.setState({ loggingStyle: loggingStyle });
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateBlacklistState: function (sites) {
|
|
||||||
this.setState({
|
|
||||||
blacklist: sites,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateWhitelistState: function (sites) {
|
|
||||||
this.setState({
|
|
||||||
whitelist: sites,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var alert = function () {
|
|
||||||
if (that.state.displayAlert === true) {
|
|
||||||
setTimeout(function () {
|
|
||||||
that.setState({ displayAlert: false });
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Alert
|
|
||||||
key={that.state.alertText}
|
|
||||||
type={that.state.alertType}
|
|
||||||
text={that.state.alertText}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var loggingStyle = function () {
|
|
||||||
if (that.state.loggingStyle == 'blacklist') {
|
|
||||||
return (
|
|
||||||
<SitesList
|
|
||||||
handleChange={that._updateBlacklistState}
|
|
||||||
label="Blacklist"
|
|
||||||
sites={that.state.blacklist}
|
|
||||||
helpText="Sites that you don't want to show in your reports."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SitesList
|
|
||||||
handleChange={that._updateWhitelistState}
|
|
||||||
label="Whitelist"
|
|
||||||
sites={that.state.whitelist}
|
|
||||||
placeholder="http://google.com http://myproject.com/MyProject"
|
|
||||||
helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="container">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-12">
|
|
||||||
<ReactCSSTransitionGroup
|
|
||||||
transitionName="alert"
|
|
||||||
transitionEnterTimeout={500}
|
|
||||||
transitionLeaveTimeout={300}
|
|
||||||
>
|
|
||||||
{alert()}
|
|
||||||
</ReactCSSTransitionGroup>
|
|
||||||
|
|
||||||
<form className="form-horizontal" onSubmit={this._handleSubmit}>
|
|
||||||
<div className="form-group">
|
|
||||||
<label className="col-lg-2 control-label">Logging style</label>
|
|
||||||
|
|
||||||
<div className="col-lg-10">
|
|
||||||
<select
|
|
||||||
className="form-control"
|
|
||||||
ref="loggingStyle"
|
|
||||||
defaultValue="blacklist"
|
|
||||||
onChange={this._displayBlackOrWhiteList}
|
|
||||||
>
|
|
||||||
<option value="blacklist">All except blacklisted sites</option>
|
|
||||||
<option value="whitelist">Only whitelisted sites</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{loggingStyle()}
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label className="col-lg-2 control-label">Logging type</label>
|
|
||||||
|
|
||||||
<div className="col-lg-10">
|
|
||||||
<select className="form-control" ref="loggingType" defaultValue="domain">
|
|
||||||
<option value="domain">Only the domain</option>
|
|
||||||
<option value="url">Entire URL</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="theme" className="col-lg-2 control-label">
|
|
||||||
Theme
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className="col-lg-10">
|
|
||||||
<select className="form-control" ref="theme" defaultValue="light">
|
|
||||||
<option value="light">Light</option>
|
|
||||||
<option value="dark">Dark</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<div className="col-lg-10 col-lg-offset-2">
|
|
||||||
<button type="submit" className="btn btn-primary">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = Options;
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
|
|
||||||
var SitesList = reactCreateClass({
|
|
||||||
getDefaultProps: function () {
|
|
||||||
return {
|
|
||||||
placeholder: 'http://google.com',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleChange: function (event) {
|
|
||||||
var sites = event.target.value;
|
|
||||||
|
|
||||||
this.props.handleChange(sites);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="sites" className="col-lg-2 control-label">
|
|
||||||
{this.props.label}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div className="col-lg-10">
|
|
||||||
<textarea
|
|
||||||
className="form-control"
|
|
||||||
rows="3"
|
|
||||||
ref="sites"
|
|
||||||
onChange={this._handleChange}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
value={this.props.sites}
|
|
||||||
></textarea>
|
|
||||||
<span className="help-block">
|
|
||||||
{this.props.helpText}
|
|
||||||
<br />
|
|
||||||
One line per site.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = SitesList;
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var reactCreateClass = require('create-react-class');
|
|
||||||
var $ = require('jquery');
|
|
||||||
|
|
||||||
var config = require('../config');
|
|
||||||
|
|
||||||
// React components
|
|
||||||
var NavBar = require('./NavBar.jsx');
|
|
||||||
var MainList = require('./MainList.jsx');
|
|
||||||
|
|
||||||
// Core
|
|
||||||
var WakaTimeCore = require('../core/WakaTimeCore').default;
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
var changeExtensionState = require('../helpers/changeExtensionState');
|
|
||||||
|
|
||||||
var Wakatime = reactCreateClass({
|
|
||||||
getInitialState: function () {
|
|
||||||
return {
|
|
||||||
user: {
|
|
||||||
full_name: null,
|
|
||||||
email: null,
|
|
||||||
photo: null,
|
|
||||||
},
|
|
||||||
loggedIn: false,
|
|
||||||
loggingEnabled: config.loggingEnabled,
|
|
||||||
totalTimeLoggedToday: '0 minutes',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount: function () {
|
|
||||||
var wakatime = new WakaTimeCore();
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
wakatime.checkAuth().done(function (data) {
|
|
||||||
if (data !== false) {
|
|
||||||
browser.storage.sync
|
|
||||||
.get({
|
|
||||||
loggingEnabled: config.loggingEnabled,
|
|
||||||
})
|
|
||||||
.then(function (items) {
|
|
||||||
that.setState({ loggingEnabled: items.loggingEnabled });
|
|
||||||
|
|
||||||
if (items.loggingEnabled === true) {
|
|
||||||
changeExtensionState('allGood');
|
|
||||||
} else {
|
|
||||||
changeExtensionState('notLogging');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
that.setState({
|
|
||||||
user: {
|
|
||||||
full_name: data.full_name,
|
|
||||||
email: data.email,
|
|
||||||
photo: data.photo,
|
|
||||||
},
|
|
||||||
loggedIn: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
wakatime.getTotalTimeLoggedToday().done(function (grand_total) {
|
|
||||||
that.setState({
|
|
||||||
totalTimeLoggedToday: grand_total.text,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
} else {
|
|
||||||
changeExtensionState('notSignedIn');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
logoutUser: function () {
|
|
||||||
var deferredObject = $.Deferred();
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: config.logoutUserUrl,
|
|
||||||
method: 'GET',
|
|
||||||
success: function () {
|
|
||||||
deferredObject.resolve(that);
|
|
||||||
},
|
|
||||||
error: function (xhr, status, err) {
|
|
||||||
console.error(config.logoutUserUrl, status, err.toString());
|
|
||||||
|
|
||||||
deferredObject.resolve(that);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferredObject.promise();
|
|
||||||
},
|
|
||||||
|
|
||||||
_logoutUser: function () {
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
this.logoutUser().done(function () {
|
|
||||||
that.setState({
|
|
||||||
user: {
|
|
||||||
full_name: null,
|
|
||||||
email: null,
|
|
||||||
photo: null,
|
|
||||||
},
|
|
||||||
loggedIn: false,
|
|
||||||
loggingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
changeExtensionState('notSignedIn');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_disableLogging: function () {
|
|
||||||
this.setState({
|
|
||||||
loggingEnabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
changeExtensionState('notLogging');
|
|
||||||
|
|
||||||
browser.storage.sync.set({
|
|
||||||
loggingEnabled: false,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_enableLogging: function () {
|
|
||||||
this.setState({
|
|
||||||
loggingEnabled: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
changeExtensionState('allGood');
|
|
||||||
|
|
||||||
browser.storage.sync.set({
|
|
||||||
loggingEnabled: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<NavBar user={this.state.user} loggedIn={this.state.loggedIn} />
|
|
||||||
<div className="container">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-md-12">
|
|
||||||
<MainList
|
|
||||||
disableLogging={this._disableLogging}
|
|
||||||
enableLogging={this._enableLogging}
|
|
||||||
loggingEnabled={this.state.loggingEnabled}
|
|
||||||
user={this.state.user}
|
|
||||||
totalTimeLoggedToday={this.state.totalTimeLoggedToday}
|
|
||||||
logoutUser={this._logoutUser}
|
|
||||||
loggedIn={this.state.loggedIn}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = Wakatime;
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
//jshint esnext:true
|
|
||||||
var config = {
|
|
||||||
// Extension name
|
|
||||||
name: 'WakaTime',
|
|
||||||
// Extension version
|
|
||||||
version: process.env.NODE_ENV === 'test' ? 'test' : browser.runtime.getManifest().version,
|
|
||||||
// Time for idle state of the browser
|
|
||||||
// The user is considered idle if there was
|
|
||||||
// no activity in the browser for x seconds
|
|
||||||
detectionIntervalInSeconds: 60,
|
|
||||||
// Default logging style
|
|
||||||
// Log all except blacklisted sites
|
|
||||||
// or log only the white listed sites.
|
|
||||||
loggingStyle: 'blacklist',
|
|
||||||
// Default logging type
|
|
||||||
loggingType: 'domain',
|
|
||||||
// By default logging is enabled
|
|
||||||
loggingEnabled: true,
|
|
||||||
// Url to which to send the heartbeat
|
|
||||||
heartbeatApiUrl: 'https://wakatime.com/api/v1/users/current/heartbeats',
|
|
||||||
// Url from which to detect if the user is logged in
|
|
||||||
currentUserApiUrl: 'https://wakatime.com/api/v1/users/current',
|
|
||||||
// The url to logout the user from wakatime
|
|
||||||
logoutUserUrl: 'https://wakatime.com/logout',
|
|
||||||
// Gets stats from the WakaTime API
|
|
||||||
summariesApiUrl: 'https://wakatime.com/api/v1/users/current/summaries',
|
|
||||||
// Different colors for different states of the extension
|
|
||||||
colors: {
|
|
||||||
allGood: '',
|
|
||||||
notLogging: 'gray',
|
|
||||||
notSignedIn: 'red',
|
|
||||||
lightTheme: 'white',
|
|
||||||
},
|
|
||||||
// Tooltips for each of the extension states
|
|
||||||
tooltips: {
|
|
||||||
allGood: '',
|
|
||||||
notLogging: 'Not logging',
|
|
||||||
notSignedIn: 'Not signed In',
|
|
||||||
blacklisted: 'This URL is blacklisted',
|
|
||||||
whitelisted: 'This URL is not on your whitelist',
|
|
||||||
},
|
|
||||||
// Default theme
|
|
||||||
theme: 'light',
|
|
||||||
// Valid extension states
|
|
||||||
states: ['allGood', 'notLogging', 'notSignedIn', 'blacklisted', 'whitelisted'],
|
|
||||||
// Predefined alert type and text for success and failure.
|
|
||||||
alert: {
|
|
||||||
success: {
|
|
||||||
type: 'success',
|
|
||||||
text: 'Options have been saved!',
|
|
||||||
},
|
|
||||||
failure: {
|
|
||||||
type: 'danger',
|
|
||||||
text: 'There was an error while saving the options!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
//jshint esnext:true
|
|
||||||
|
|
||||||
var $ = require('jquery');
|
|
||||||
var moment = require('moment');
|
|
||||||
var config = require('./../config');
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
var getDomainFromUrl = require('./../helpers/getDomainFromUrl');
|
|
||||||
var changeExtensionState = require('../helpers/changeExtensionState');
|
|
||||||
var in_array = require('./../helpers/in_array');
|
|
||||||
var contains = require('./../helpers/contains');
|
|
||||||
|
|
||||||
class WakaTimeCore {
|
|
||||||
constructor() {
|
|
||||||
this.tabsWithDevtoolsOpen = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settter for tabsWithDevtoolsOpen
|
|
||||||
*
|
|
||||||
* @param tabs
|
|
||||||
*/
|
|
||||||
setTabsWithDevtoolsOpen(tabs) {
|
|
||||||
this.tabsWithDevtoolsOpen = tabs;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTotalTimeLoggedToday() {
|
|
||||||
var deferredObject = $.Deferred();
|
|
||||||
var today = moment().format('YYYY-MM-DD');
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: config.summariesApiUrl + '?start=' + today + '&end=' + today,
|
|
||||||
dataType: 'json',
|
|
||||||
success: (data) => {
|
|
||||||
deferredObject.resolve(data.data[0].grand_total);
|
|
||||||
},
|
|
||||||
error: (xhr, status, err) => {
|
|
||||||
console.error(config.summariesApiUrl, status, err.toString());
|
|
||||||
|
|
||||||
deferredObject.resolve(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferredObject.promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the user is logged in.
|
|
||||||
*
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
checkAuth() {
|
|
||||||
var deferredObject = $.Deferred();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: config.currentUserApiUrl,
|
|
||||||
dataType: 'json',
|
|
||||||
success: (data) => {
|
|
||||||
deferredObject.resolve(data.data);
|
|
||||||
},
|
|
||||||
error: (xhr, status, err) => {
|
|
||||||
console.error(config.currentUserApiUrl, status, err.toString());
|
|
||||||
deferredObject.resolve(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferredObject.promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Depending on various factors detects the current active tab URL or domain,
|
|
||||||
* and sends it to WakaTime for logging.
|
|
||||||
*/
|
|
||||||
recordHeartbeat() {
|
|
||||||
browser.storage.sync
|
|
||||||
.get({
|
|
||||||
loggingEnabled: config.loggingEnabled,
|
|
||||||
loggingStyle: config.loggingStyle,
|
|
||||||
blacklist: '',
|
|
||||||
whitelist: '',
|
|
||||||
})
|
|
||||||
.then((items) => {
|
|
||||||
if (items.loggingEnabled === true) {
|
|
||||||
changeExtensionState('allGood');
|
|
||||||
|
|
||||||
browser.idle.queryState(config.detectionIntervalInSeconds).then((newState) => {
|
|
||||||
if (newState === 'active') {
|
|
||||||
// Get current tab URL.
|
|
||||||
browser.tabs.query({ currentWindow: true, active: true }).then((tabs) => {
|
|
||||||
if (tabs.length == 0) return;
|
|
||||||
|
|
||||||
var currentActiveTab = tabs[0];
|
|
||||||
var debug = false;
|
|
||||||
|
|
||||||
// If the current active tab has devtools open
|
|
||||||
if (in_array(currentActiveTab.id, this.tabsWithDevtoolsOpen)) {
|
|
||||||
debug = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.loggingStyle == 'blacklist') {
|
|
||||||
if (!contains(currentActiveTab.url, items.blacklist)) {
|
|
||||||
this.sendHeartbeat(
|
|
||||||
{
|
|
||||||
url: currentActiveTab.url,
|
|
||||||
project: null,
|
|
||||||
},
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
changeExtensionState('blacklisted');
|
|
||||||
console.log(currentActiveTab.url + ' is on a blacklist.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items.loggingStyle == 'whitelist') {
|
|
||||||
var heartbeat = this.getHeartbeat(currentActiveTab.url, items.whitelist);
|
|
||||||
if (heartbeat.url) {
|
|
||||||
this.sendHeartbeat(heartbeat, debug);
|
|
||||||
} else {
|
|
||||||
changeExtensionState('whitelisted');
|
|
||||||
console.log(currentActiveTab.url + ' is not on a whitelist.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
changeExtensionState('notLogging');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an array from list using \n as delimiter
|
|
||||||
* and checks if any element in list is contained in the url.
|
|
||||||
* Also checks if element is assigned to a project using @@ as delimiter
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @param list
|
|
||||||
* @returns {object}
|
|
||||||
*/
|
|
||||||
getHeartbeat(url, list) {
|
|
||||||
var projectIndicatorCharacters = '@@';
|
|
||||||
|
|
||||||
var lines = list.split('\n');
|
|
||||||
for (var i = 0; i < lines.length; i++) {
|
|
||||||
// strip (http:// or https://) and trailing (`/` or `@@`)
|
|
||||||
var cleanLine = lines[i]
|
|
||||||
.trim()
|
|
||||||
.replace(/(\/|@@)$/, '')
|
|
||||||
.replace(/^(?:https?:\/\/)?/i, '');
|
|
||||||
if (cleanLine === '') continue;
|
|
||||||
|
|
||||||
var projectIndicatorIndex = cleanLine.lastIndexOf(projectIndicatorCharacters);
|
|
||||||
var projectIndicatorExists = projectIndicatorIndex > -1;
|
|
||||||
var projectName = null;
|
|
||||||
var urlFromLine = cleanLine;
|
|
||||||
if (projectIndicatorExists) {
|
|
||||||
var start = projectIndicatorIndex + projectIndicatorCharacters.length;
|
|
||||||
projectName = cleanLine.substring(start);
|
|
||||||
urlFromLine = cleanLine
|
|
||||||
.replace(cleanLine.substring(projectIndicatorIndex), '')
|
|
||||||
.replace(/\/$/, '');
|
|
||||||
}
|
|
||||||
var schemaHttpExists = url.match(/^http:\/\//i);
|
|
||||||
var schemaHttpsExists = url.match(/^https:\/\//i);
|
|
||||||
var schema = '';
|
|
||||||
if (schemaHttpExists) {
|
|
||||||
schema = 'http://';
|
|
||||||
}
|
|
||||||
if (schemaHttpsExists) {
|
|
||||||
schema = 'https://';
|
|
||||||
}
|
|
||||||
var cleanUrl = url
|
|
||||||
.trim()
|
|
||||||
.replace(/(\/|@@)$/, '')
|
|
||||||
.replace(/^(?:https?:\/\/)?/i, '');
|
|
||||||
var startsWithUrl = cleanUrl.toLowerCase().indexOf(urlFromLine.toLowerCase()) > -1;
|
|
||||||
if (startsWithUrl) {
|
|
||||||
return {
|
|
||||||
url: schema + urlFromLine,
|
|
||||||
project: projectName,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: null,
|
|
||||||
project: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates payload for the heartbeat and returns it as JSON.
|
|
||||||
*
|
|
||||||
* @param heartbeat
|
|
||||||
* @param type
|
|
||||||
* @param debug
|
|
||||||
* @returns {*}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_preparePayload(heartbeat, type, debug = false) {
|
|
||||||
return JSON.stringify({
|
|
||||||
entity: heartbeat.url,
|
|
||||||
type: type,
|
|
||||||
time: moment().format('X'),
|
|
||||||
project: heartbeat.project || '<<LAST_PROJECT>>',
|
|
||||||
is_debugging: debug,
|
|
||||||
plugin: 'browser-wakatime/' + config.version,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a promise with logging type variable.
|
|
||||||
*
|
|
||||||
* @returns {*}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_getLoggingType() {
|
|
||||||
var deferredObject = $.Deferred();
|
|
||||||
|
|
||||||
browser.storage.sync
|
|
||||||
.get({
|
|
||||||
loggingType: config.loggingType,
|
|
||||||
})
|
|
||||||
.then(function (items) {
|
|
||||||
deferredObject.resolve(items.loggingType);
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferredObject.promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given the heartbeat and logging type it creates a payload and
|
|
||||||
* sends an ajax post request to the API.
|
|
||||||
*
|
|
||||||
* @param heartbeat
|
|
||||||
* @param debug
|
|
||||||
*/
|
|
||||||
sendHeartbeat(heartbeat, debug) {
|
|
||||||
var payload = null;
|
|
||||||
|
|
||||||
this._getLoggingType().done((loggingType) => {
|
|
||||||
// Get only the domain from the entity.
|
|
||||||
// And send that in heartbeat
|
|
||||||
if (loggingType == 'domain') {
|
|
||||||
heartbeat.url = getDomainFromUrl(heartbeat.url);
|
|
||||||
payload = this._preparePayload(heartbeat, 'domain', debug);
|
|
||||||
console.log(payload);
|
|
||||||
this.sendAjaxRequestToApi(payload);
|
|
||||||
}
|
|
||||||
// Send entity in heartbeat
|
|
||||||
else if (loggingType == 'url') {
|
|
||||||
payload = this._preparePayload(heartbeat, 'url', debug);
|
|
||||||
console.log(payload);
|
|
||||||
this.sendAjaxRequestToApi(payload);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends AJAX request with payload to the heartbeat API as JSON.
|
|
||||||
*
|
|
||||||
* @param payload
|
|
||||||
* @param method
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
sendAjaxRequestToApi(payload, method = 'POST') {
|
|
||||||
var deferredObject = $.Deferred();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: config.heartbeatApiUrl,
|
|
||||||
dataType: 'json',
|
|
||||||
contentType: 'application/json',
|
|
||||||
method: method,
|
|
||||||
data: payload,
|
|
||||||
statusCode: {
|
|
||||||
401: function () {
|
|
||||||
changeExtensionState('notSignedIn');
|
|
||||||
},
|
|
||||||
201: function () {
|
|
||||||
// nothing to do here
|
|
||||||
},
|
|
||||||
},
|
|
||||||
success: (response) => {
|
|
||||||
deferredObject.resolve(this);
|
|
||||||
},
|
|
||||||
error: (xhr, status, err) => {
|
|
||||||
console.error(config.heartbeatApiUrl, status, err.toString());
|
|
||||||
|
|
||||||
deferredObject.resolve(this);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return deferredObject.promise();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default WakaTimeCore;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
// Create a connection to the background page
|
|
||||||
var backgroundPageConnection = browser.runtime.connect({
|
|
||||||
name: 'devtools-page',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Send a message to background page with the current active tabId
|
|
||||||
backgroundPageConnection.postMessage({
|
|
||||||
name: 'init',
|
|
||||||
tabId: browser.devtools.inspectedWindow.tabId,
|
|
||||||
});
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
// Core
|
|
||||||
var WakaTimeCore = require('./core/WakaTimeCore').default;
|
|
||||||
|
|
||||||
// initialize class
|
|
||||||
var wakatime = new WakaTimeCore();
|
|
||||||
|
|
||||||
// Holds currently open connections (ports) with devtools
|
|
||||||
// Uses tabId as index key.
|
|
||||||
var connections = {};
|
|
||||||
|
|
||||||
// Add a listener to resolve alarms
|
|
||||||
browser.alarms.onAlarm.addListener(function (alarm) {
|
|
||||||
// |alarm| can be undefined because onAlarm also gets called from
|
|
||||||
// window.setTimeout on old chrome versions.
|
|
||||||
if (alarm && alarm.name == 'heartbeatAlarm') {
|
|
||||||
console.log('recording a heartbeat - alarm triggered');
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a new alarm for heartbeats.
|
|
||||||
browser.alarms.create('heartbeatAlarm', { periodInMinutes: 2 });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whenever a active tab is changed it records a heartbeat with that tab url.
|
|
||||||
*/
|
|
||||||
browser.tabs.onActivated.addListener(function (activeInfo) {
|
|
||||||
browser.tabs.get(activeInfo.tabId).then(function (tab) {
|
|
||||||
console.log('recording a heartbeat - active tab changed');
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whenever a active window is changed it records a heartbeat with the active tab url.
|
|
||||||
*/
|
|
||||||
browser.windows.onFocusChanged.addListener(function (windowId) {
|
|
||||||
if (windowId != browser.windows.WINDOW_ID_NONE) {
|
|
||||||
console.log('recording a heartbeat - active window changed');
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
} else {
|
|
||||||
console.log('lost focus');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whenever any tab is updated it checks if the updated tab is the tab that is
|
|
||||||
* currently active and if it is, then it records a heartbeat.
|
|
||||||
*/
|
|
||||||
browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
|
|
||||||
if (changeInfo.status === 'complete') {
|
|
||||||
// Get current tab URL.
|
|
||||||
browser.tabs.query({ currentWindow: true, active: true }).then(function (tabs) {
|
|
||||||
// If tab updated is the same as active tab
|
|
||||||
if (tabId == tabs[0].id) {
|
|
||||||
console.log('recording a heartbeat - tab updated');
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is in charge of detecting if devtools are opened or closed
|
|
||||||
* and sending a heartbeat depending on that.
|
|
||||||
*/
|
|
||||||
browser.runtime.onConnect.addListener(function (port) {
|
|
||||||
if (port.name == 'devtools-page') {
|
|
||||||
// Listen to messages sent from the DevTools page
|
|
||||||
port.onMessage.addListener(function (message, sender, sendResponse) {
|
|
||||||
if (message.name == 'init') {
|
|
||||||
connections[message.tabId] = port;
|
|
||||||
|
|
||||||
wakatime.setTabsWithDevtoolsOpen(Object.keys(connections));
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
port.onDisconnect.addListener(function (port) {
|
|
||||||
var tabs = Object.keys(connections);
|
|
||||||
|
|
||||||
for (var i = 0, len = tabs.length; i < len; i++) {
|
|
||||||
if (connections[tabs[i]] == port) {
|
|
||||||
delete connections[tabs[i]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wakatime.setTabsWithDevtoolsOpen(Object.keys(connections));
|
|
||||||
|
|
||||||
wakatime.recordHeartbeat();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
var config = require('../config');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It changes the extension icon color.
|
|
||||||
* Supported values are: 'red', 'white', 'gray' and ''.
|
|
||||||
*
|
|
||||||
* @param color
|
|
||||||
*/
|
|
||||||
function changeExtensionIcon(color) {
|
|
||||||
color = color ? color : '';
|
|
||||||
|
|
||||||
var path = null;
|
|
||||||
|
|
||||||
if (color !== '') {
|
|
||||||
color = '-' + color;
|
|
||||||
|
|
||||||
path = './graphics/wakatime-logo-38' + color + '.png';
|
|
||||||
|
|
||||||
browser.browserAction.setIcon({
|
|
||||||
path: path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color === '') {
|
|
||||||
browser.storage.sync
|
|
||||||
.get({
|
|
||||||
theme: config.theme,
|
|
||||||
})
|
|
||||||
.then(function (items) {
|
|
||||||
if (items.theme == config.theme) {
|
|
||||||
path = './graphics/wakatime-logo-38.png';
|
|
||||||
|
|
||||||
browser.browserAction.setIcon({
|
|
||||||
path: path,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
path = './graphics/wakatime-logo-38-white.png';
|
|
||||||
|
|
||||||
browser.browserAction.setIcon({
|
|
||||||
path: path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = changeExtensionIcon;
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
var config = require('../config');
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
var changeExtensionIcon = require('./changeExtensionIcon');
|
|
||||||
var changeExtensionTooltip = require('./changeExtensionTooltip');
|
|
||||||
var in_array = require('./in_array');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current state of the extension.
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
function changeExtensionState(state) {
|
|
||||||
if (!in_array(state, config.states)) {
|
|
||||||
throw new Error('Not a valid state!');
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case 'allGood':
|
|
||||||
changeExtensionIcon(config.colors.allGood);
|
|
||||||
changeExtensionTooltip(config.tooltips.allGood);
|
|
||||||
break;
|
|
||||||
case 'notLogging':
|
|
||||||
changeExtensionIcon(config.colors.notLogging);
|
|
||||||
changeExtensionTooltip(config.tooltips.notLogging);
|
|
||||||
break;
|
|
||||||
case 'notSignedIn':
|
|
||||||
changeExtensionIcon(config.colors.notSignedIn);
|
|
||||||
changeExtensionTooltip(config.tooltips.notSignedIn);
|
|
||||||
break;
|
|
||||||
case 'blacklisted':
|
|
||||||
changeExtensionIcon(config.colors.notLogging);
|
|
||||||
changeExtensionTooltip(config.tooltips.blacklisted);
|
|
||||||
break;
|
|
||||||
case 'whitelisted':
|
|
||||||
changeExtensionIcon(config.colors.notLogging);
|
|
||||||
changeExtensionTooltip(config.tooltips.whitelisted);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = changeExtensionState;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
var config = require('../config');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It changes the extension title
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
*/
|
|
||||||
function changeExtensionTooltip(text) {
|
|
||||||
if (text === '') {
|
|
||||||
text = config.name;
|
|
||||||
} else {
|
|
||||||
text = config.name + ' - ' + text;
|
|
||||||
}
|
|
||||||
|
|
||||||
browser.browserAction.setTitle({ title: text });
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = changeExtensionTooltip;
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Creates an array from list using \n as delimiter
|
|
||||||
* and checks if any element in list is contained in the url.
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @param list
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function contains(url, list) {
|
|
||||||
var lines = list.split('\n');
|
|
||||||
|
|
||||||
for (var i = 0; i < lines.length; i++) {
|
|
||||||
// Trim all lines from the list one by one
|
|
||||||
var cleanLine = lines[i].trim();
|
|
||||||
|
|
||||||
// If by any chance one line in the list is empty, ignore it
|
|
||||||
if (cleanLine === '') continue;
|
|
||||||
|
|
||||||
var lineRe = new RegExp(cleanLine.replace('.', '.').replace('*', '.*'));
|
|
||||||
|
|
||||||
// If url matches the current line return true
|
|
||||||
if (lineRe.test(url)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = contains;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Returns domain from given URL.
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getDomainFromUrl(url) {
|
|
||||||
var parts = url.split('/');
|
|
||||||
|
|
||||||
return parts[0] + '//' + parts[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = getDomainFromUrl;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* Returns boolean if needle is found in haystack or not.
|
|
||||||
*
|
|
||||||
* @param needle
|
|
||||||
* @param haystack
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function in_array(needle, haystack) {
|
|
||||||
for (var i = 0; i < haystack.length; i++) {
|
|
||||||
if (needle == haystack[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = in_array;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/* global browser */
|
|
||||||
|
|
||||||
/* This is a fix for Bootstrap requiring jQuery */
|
|
||||||
global.jQuery = require('jquery');
|
|
||||||
require('bootstrap');
|
|
||||||
|
|
||||||
var React = require('react');
|
|
||||||
var ReactDOM = require('react-dom');
|
|
||||||
|
|
||||||
// React components
|
|
||||||
var Options = require('./components/Options.jsx');
|
|
||||||
|
|
||||||
ReactDOM.render(<Options />, document.getElementById('wakatime-options'));
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<script src="public/js/browser-polyfill.min.js"></script>
|
|
||||||
<script src="public/js/devtools.js"></script>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"background": {
|
|
||||||
"scripts": ["public/js/browser-polyfill.min.js", "public/js/events.js"],
|
|
||||||
"persistent": false
|
|
||||||
},
|
|
||||||
"browser_action": {
|
|
||||||
"default_icon": {
|
|
||||||
"19": "graphics/wakatime-logo-19.png",
|
|
||||||
"38": "graphics/wakatime-logo-38.png"
|
|
||||||
},
|
|
||||||
"default_title": "WakaTime",
|
|
||||||
"default_popup": "popup.html"
|
|
||||||
},
|
|
||||||
"browser_specific_settings": {
|
|
||||||
"gecko": {
|
|
||||||
"id": "addon@wakatime.com",
|
|
||||||
"strict_min_version": "48.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "Automatic time tracking for Chrome.",
|
|
||||||
"devtools_page": "devtools.html",
|
|
||||||
"homepage_url": "https://wakatime.com",
|
|
||||||
"icons": {
|
|
||||||
"16": "graphics/wakatime-logo-16.png",
|
|
||||||
"48": "graphics/wakatime-logo-48.png",
|
|
||||||
"128": "graphics/wakatime-logo-128.png"
|
|
||||||
},
|
|
||||||
"manifest_version": 2,
|
|
||||||
"name": "WakaTime",
|
|
||||||
"options_ui": {
|
|
||||||
"page": "options.html",
|
|
||||||
"chrome_style": false
|
|
||||||
},
|
|
||||||
"permissions": [
|
|
||||||
"https://api.wakatime.com/*",
|
|
||||||
"https://wakatime.com/*",
|
|
||||||
"alarms",
|
|
||||||
"tabs",
|
|
||||||
"storage",
|
|
||||||
"idle"
|
|
||||||
],
|
|
||||||
"version": "3.0.0"
|
|
||||||
}
|
|
||||||
17
options.html
17
options.html
@@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>WakaTime options</title>
|
|
||||||
|
|
||||||
<link href="public/css/app.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="wakatime-options"></div>
|
|
||||||
|
|
||||||
<script src="public/js/browser-polyfill.min.js"></script>
|
|
||||||
<script src="public/js/options.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -32,6 +32,7 @@
|
|||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^12.6.0",
|
"@testing-library/user-event": "^12.6.0",
|
||||||
|
"@types/chai": "^4.3.4",
|
||||||
"@types/chrome": "0.0.128",
|
"@types/chrome": "0.0.128",
|
||||||
"@types/classnames": "^2.2.11",
|
"@types/classnames": "^2.2.11",
|
||||||
"@types/copy-webpack-plugin": "^10.1.0",
|
"@types/copy-webpack-plugin": "^10.1.0",
|
||||||
@@ -3631,6 +3632,12 @@
|
|||||||
"@babel/types": "^7.3.0"
|
"@babel/types": "^7.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/chai": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/chrome": {
|
"node_modules/@types/chrome": {
|
||||||
"version": "0.0.128",
|
"version": "0.0.128",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.128.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.128.tgz",
|
||||||
@@ -26005,6 +26012,12 @@
|
|||||||
"@babel/types": "^7.3.0"
|
"@babel/types": "^7.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/chai": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/chrome": {
|
"@types/chrome": {
|
||||||
"version": "0.0.128",
|
"version": "0.0.128",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.128.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.128.tgz",
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^12.6.0",
|
"@testing-library/user-event": "^12.6.0",
|
||||||
|
"@types/chai": "^4.3.4",
|
||||||
"@types/chrome": "0.0.128",
|
"@types/chrome": "0.0.128",
|
||||||
"@types/classnames": "^2.2.11",
|
"@types/classnames": "^2.2.11",
|
||||||
"@types/copy-webpack-plugin": "^10.1.0",
|
"@types/copy-webpack-plugin": "^10.1.0",
|
||||||
|
|||||||
17
popup.html
17
popup.html
@@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>WakaTime</title>
|
|
||||||
|
|
||||||
<link href="public/css/app.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="wakatime"></div>
|
|
||||||
|
|
||||||
<script src="public/js/browser-polyfill.min.js"></script>
|
|
||||||
<script src="public/js/app.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { ApiKeyReducer, ReduxSelector } from '../types/store';
|
import { ApiKeyReducer, ReduxSelector } from '../types/store';
|
||||||
import { fetchUserData } from '../utils/user';
|
import { fetchUserData } from '../utils/user';
|
||||||
@@ -10,6 +10,7 @@ import MainList from './MainList';
|
|||||||
|
|
||||||
export default function WakaTime(): JSX.Element {
|
export default function WakaTime(): JSX.Element {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const [extensionState, setExtensionState] = useState('');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
apiKey: apiKeyFromRedux,
|
apiKey: apiKeyFromRedux,
|
||||||
@@ -18,7 +19,12 @@ export default function WakaTime(): JSX.Element {
|
|||||||
}: ApiKeyReducer = useSelector((selector: ReduxSelector) => selector.config);
|
}: ApiKeyReducer = useSelector((selector: ReduxSelector) => selector.config);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void fetchUserData(apiKeyFromRedux, dispatch);
|
const fetchData = async () => {
|
||||||
|
await fetchUserData(apiKeyFromRedux, dispatch);
|
||||||
|
const items = await browser.storage.sync.get({ extensionState: '' });
|
||||||
|
setExtensionState(items.extensionState as string);
|
||||||
|
};
|
||||||
|
void fetchData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isApiKeyValid = apiKeyInvalid(apiKeyFromRedux) === '';
|
const isApiKeyValid = apiKeyInvalid(apiKeyFromRedux) === '';
|
||||||
@@ -26,6 +32,14 @@ export default function WakaTime(): JSX.Element {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<NavBar />
|
<NavBar />
|
||||||
|
{isApiKeyValid && extensionState === 'notSignedIn' && (
|
||||||
|
<Alert
|
||||||
|
type={config.alert.failure.type}
|
||||||
|
text={'Invalid api key'}
|
||||||
|
onClick={() => browser.runtime.openOptionsPage()}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{!isApiKeyValid && (
|
{!isApiKeyValid && (
|
||||||
<Alert
|
<Alert
|
||||||
type={config.alert.failure.type}
|
type={config.alert.failure.type}
|
||||||
|
|||||||
@@ -26,5 +26,5 @@
|
|||||||
"page": "options.html"
|
"page": "options.html"
|
||||||
},
|
},
|
||||||
"permissions": ["alarms", "tabs", "storage", "idle"],
|
"permissions": ["alarms", "tabs", "storage", "idle"],
|
||||||
"version": "3.0.2"
|
"version": "3.0.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,5 +39,5 @@
|
|||||||
"storage",
|
"storage",
|
||||||
"idle"
|
"idle"
|
||||||
],
|
],
|
||||||
"version": "3.0.1"
|
"version": "3.0.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import config, { ApiStates } from '../config/config';
|
import config, { ApiStates } from '../config/config';
|
||||||
|
|
||||||
import changeExtensionIcon from './changeExtensionIcon';
|
import changeExtensionIcon from './changeExtensionIcon';
|
||||||
import changeExtensionTooltip from './changeExtensionTooltip';
|
import changeExtensionTooltip from './changeExtensionTooltip';
|
||||||
|
|
||||||
@@ -31,4 +30,5 @@ export default async function changeExtensionState(state: ApiStates): Promise<vo
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
await browser.storage.sync.set({ extensionState: state });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/Alert.jsx');
|
|
||||||
|
|
||||||
describe('Alert', function () {
|
|
||||||
var React, Alert, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
Alert = require('../../assets/js/components/Alert.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/MainList.jsx');
|
|
||||||
|
|
||||||
describe('MainList', function () {
|
|
||||||
var React, MainList, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
MainList = require('../../assets/js/components/MainList.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/Navbar.jsx');
|
|
||||||
|
|
||||||
describe('Navbar', function () {
|
|
||||||
var React, Navbar, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
Navbar = require('../../assets/js/components/Navbar.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/Options.jsx');
|
|
||||||
|
|
||||||
describe('Options', function () {
|
|
||||||
var React, Options, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
Options = require('../../assets/js/components/Options.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/SitesList.jsx');
|
|
||||||
|
|
||||||
describe('SitesList', function () {
|
|
||||||
var React, SitesList, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
SitesList = require('../../assets/js/components/SitesList.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
jest.dontMock('../../assets/js/components/Wakatime.jsx');
|
|
||||||
|
|
||||||
describe('Wakatime', function () {
|
|
||||||
var React, Wakatime, TestUtils, Component;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Setup our tools
|
|
||||||
React = require('react/addons');
|
|
||||||
Wakatime = require('../../assets/js/components/Wakatime.jsx');
|
|
||||||
TestUtils = React.addons.TestUtils;
|
|
||||||
// Create the React component here using TestUtils and store into Component
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', function () {
|
|
||||||
expect(2 + 2).toEqual(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
|
|
||||||
var changeExtensionIcon = require('../../assets/js/helpers/changeExtensionIcon');
|
|
||||||
|
|
||||||
describe('changeExtensionIcon', function () {
|
|
||||||
it('should be a function', function () {
|
|
||||||
expect(changeExtensionIcon).to.be.a('function');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
|
|
||||||
var changeExtensionState = require('../../assets/js/helpers/changeExtensionState');
|
|
||||||
|
|
||||||
describe('changeExtensionState', function () {
|
|
||||||
beforeEach(() => {
|
|
||||||
browser = window;
|
|
||||||
});
|
|
||||||
it('should be a function', function () {
|
|
||||||
expect(changeExtensionState).to.be.a('function');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
var chai = require('chai');
|
|
||||||
var expect = chai.expect;
|
|
||||||
|
|
||||||
var in_array = require('../../assets/js/helpers/in_array');
|
|
||||||
|
|
||||||
describe('in_array', function () {
|
|
||||||
it('should be a function', function () {
|
|
||||||
expect(in_array).to.be.a('function');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find the needle and return true', function () {
|
|
||||||
expect(in_array('4', ['4', '3', '2', '1'])).to.equal(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not find the needle and it should return false', function () {
|
|
||||||
expect(in_array('5', ['4', '3', '2', '1'])).to.equal(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
var chai = require('chai');
|
import chai from 'chai';
|
||||||
var sinon = require('sinon');
|
import sinon from 'sinon';
|
||||||
var chrome = require('sinon-chrome');
|
import chrome from 'sinon-chrome';
|
||||||
var expect = chai.expect;
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('Chrome Dev Tools', function () {
|
describe('Chrome Dev Tools', function () {
|
||||||
it('should work', function () {
|
it('should work', function () {
|
||||||
20
tests/utils/changeExtensionIcon.spec.ts
Normal file
20
tests/utils/changeExtensionIcon.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import chai from 'chai';
|
||||||
|
import changeExtensionIcon from '../../src/utils/changeExtensionIcon';
|
||||||
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
jest.mock('webextension-polyfill', () => {
|
||||||
|
return {
|
||||||
|
runtime: {
|
||||||
|
getManifest: () => {
|
||||||
|
return { version: 'test-version' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeExtensionIcon', function () {
|
||||||
|
it('should be a function', function () {
|
||||||
|
expect(changeExtensionIcon).to.be.a('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
20
tests/utils/changeExtensionState.spec.ts
Normal file
20
tests/utils/changeExtensionState.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import chai from 'chai';
|
||||||
|
import changeExtensionState from '../../src/utils/changeExtensionState';
|
||||||
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
jest.mock('webextension-polyfill', () => {
|
||||||
|
return {
|
||||||
|
runtime: {
|
||||||
|
getManifest: () => {
|
||||||
|
return { version: 'test-version' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('changeExtensionState', function () {
|
||||||
|
it('should be a function', function () {
|
||||||
|
expect(changeExtensionState).to.be.a('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
var chai = require('chai');
|
import chai from 'chai';
|
||||||
var sinon = require('sinon-chai');
|
import changeExtensionTooltip from '../../src/utils/changeExtensionTooltip';
|
||||||
var chrome = require('sinon-chrome');
|
|
||||||
var expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
jest.mock('webextension-polyfill', () => {
|
||||||
|
return {
|
||||||
|
runtime: {
|
||||||
|
getManifest: () => {
|
||||||
|
return { version: 'test-version' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
var changeExtensionTooltip = require('../../assets/js/helpers/changeExtensionTooltip');
|
|
||||||
describe('changeExtensionTooltip', function () {
|
describe('changeExtensionTooltip', function () {
|
||||||
it('should be a function', function () {
|
it('should be a function', function () {
|
||||||
expect(changeExtensionTooltip).to.be.a('function');
|
expect(changeExtensionTooltip).to.be.a('function');
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var chai = require('chai');
|
import chai from 'chai';
|
||||||
var expect = chai.expect;
|
import contains from '../../src/utils/contains';
|
||||||
|
|
||||||
var contains = require('../../assets/js/helpers/contains');
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('contains', function () {
|
describe('contains', function () {
|
||||||
it('should be a function', function () {
|
it('should be a function', function () {
|
||||||
@@ -9,16 +9,16 @@ describe('contains', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should match url against blacklist and return true', function () {
|
it('should match url against blacklist and return true', function () {
|
||||||
var list = 'localhost\ntest.com';
|
const list = 'localhost\ntest.com';
|
||||||
|
|
||||||
var url = 'http://localhost/fooapp';
|
const url = 'http://localhost/fooapp';
|
||||||
expect(contains(url, list)).to.equal(true);
|
expect(contains(url, list)).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not match url against blacklist and return false', function () {
|
it('should not match url against blacklist and return false', function () {
|
||||||
var list = 'localhost2\ntest.com';
|
const list = 'localhost2\ntest.com';
|
||||||
|
|
||||||
var url = 'http://localhost/fooapp';
|
const url = 'http://localhost/fooapp';
|
||||||
expect(contains(url, list)).to.equal(false);
|
expect(contains(url, list)).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
var chai = require('chai');
|
import chai from 'chai';
|
||||||
var expect = chai.expect;
|
import getDomainFromUrl from '../../src/utils/getDomainFromUrl';
|
||||||
|
|
||||||
var getDomainFromUrl = require('../../assets/js/helpers/getDomainFromUrl');
|
const expect = chai.expect;
|
||||||
|
|
||||||
describe('getDomainFromUrl', function () {
|
describe('getDomainFromUrl', function () {
|
||||||
it('should be a function', function () {
|
it('should be a function', function () {
|
||||||
18
tests/utils/in_array.spec.ts
Normal file
18
tests/utils/in_array.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import chai from 'chai';
|
||||||
|
import inArray from '../../src/utils/inArray';
|
||||||
|
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('inArray', function () {
|
||||||
|
it('should be a function', function () {
|
||||||
|
expect(inArray).to.be.a('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find the needle and return true', function () {
|
||||||
|
expect(inArray('4', ['4', '3', '2', '1'])).to.equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not find the needle and it should return false', function () {
|
||||||
|
expect(inArray('5', ['4', '3', '2', '1'])).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
41
xclap.ts
41
xclap.ts
@@ -69,22 +69,17 @@ load({
|
|||||||
serial('postinstall'),
|
serial('postinstall'),
|
||||||
'webpack',
|
'webpack',
|
||||||
concurrent(
|
concurrent(
|
||||||
exec('web-ext build'),
|
exec(
|
||||||
exec(`web-ext build -a dist/firefox/web-ext-artifacts --source-dir ${ffNextBuildFolder}`),
|
`web-ext build --artifacts-dir dist/chrome/web-ext-artifacts --source-dir ${chromeNextBuildFolder}`,
|
||||||
|
),
|
||||||
|
exec(
|
||||||
|
`web-ext build --artifacts-dir dist/firefox/web-ext-artifacts --source-dir ${ffNextBuildFolder}`,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
clean: [exec('rimraf public coverage vendor web-ext-artifacts'), 'clean:webpack'],
|
clean: [exec('rimraf public coverage vendor web-ext-artifacts'), 'clean:webpack'],
|
||||||
'clean:webpack': exec('rimraf dist'),
|
'clean:webpack': exec('rimraf dist'),
|
||||||
dev: [
|
dev: ['clean', 'postinstall', concurrent('watch', 'web-ext:run:firefox', 'web-ext:run:chrome')],
|
||||||
'clean',
|
|
||||||
'postinstall',
|
|
||||||
concurrent('watch', 'web-ext:run:firefox-next', 'web-ext:run:chrome-next'),
|
|
||||||
],
|
|
||||||
'dev:legacy': [
|
|
||||||
'clean',
|
|
||||||
'postinstall',
|
|
||||||
concurrent(exec('gulp watch'), 'web-ext:run:firefox-legacy', 'web-ext:run:chrome-legacy'),
|
|
||||||
],
|
|
||||||
eslint: exec('eslint src . --fix'),
|
eslint: exec('eslint src . --fix'),
|
||||||
less: exec('lessc assets/less/app.less public/css/app.css'),
|
less: exec('lessc assets/less/app.less public/css/app.css'),
|
||||||
lint: ['prettier', 'eslint'],
|
lint: ['prettier', 'eslint'],
|
||||||
@@ -93,34 +88,16 @@ load({
|
|||||||
'remotedev-server': exec('remotedev --hostname=localhost --port=8000'),
|
'remotedev-server': exec('remotedev --hostname=localhost --port=8000'),
|
||||||
test: ['build', 'lint', 'test-jest'],
|
test: ['build', 'lint', 'test-jest'],
|
||||||
'test-jest': [exec('jest --clearCache'), exec('jest --verbose --coverage')],
|
'test-jest': [exec('jest --clearCache'), exec('jest --verbose --coverage')],
|
||||||
'test-jest-update': exec('jest -u'),
|
|
||||||
'wait:legacy-files': waitForFilesTask(
|
|
||||||
'manifest.json',
|
|
||||||
'public/js/browser-polyfill.min.js',
|
|
||||||
'public/js/events.js',
|
|
||||||
'options.html',
|
|
||||||
),
|
|
||||||
watch: concurrent('watch-jest', 'webpack:watch'),
|
watch: concurrent('watch-jest', 'webpack:watch'),
|
||||||
'watch-jest': exec('jest --watch'),
|
'watch-jest': exec('jest --watch'),
|
||||||
'web-ext:run:chrome': concurrent('web-ext:run:chrome-next', 'web-ext:run:chrome-legacy'),
|
'web-ext:run:chrome': [
|
||||||
'web-ext:run:chrome-legacy': [
|
|
||||||
'wait:legacy-files',
|
|
||||||
exec('web-ext run -t chromium --source-dir .'),
|
|
||||||
],
|
|
||||||
'web-ext:run:chrome-next': [
|
|
||||||
chromeNextBuildFileWaitTask,
|
chromeNextBuildFileWaitTask,
|
||||||
exec('web-ext run -t chromium --source-dir dist/chrome'),
|
exec('web-ext run -t chromium --source-dir dist/chrome'),
|
||||||
],
|
],
|
||||||
'web-ext:run:firefox': concurrent('web-ext:run:firefox-next', 'web-ext:run:firefox-legacy'),
|
'web-ext:run:firefox': [
|
||||||
'web-ext:run:firefox-legacy': [
|
|
||||||
'wait:legacy-files',
|
|
||||||
exec('web-ext run -t firefox-desktop --source-dir .'),
|
|
||||||
],
|
|
||||||
'web-ext:run:firefox-next': [
|
|
||||||
ffNextBuildFileWaitTask,
|
ffNextBuildFileWaitTask,
|
||||||
exec('web-ext run -t firefox-desktop --source-dir dist/firefox'),
|
exec('web-ext run -t firefox-desktop --source-dir dist/firefox'),
|
||||||
],
|
],
|
||||||
webpack: ['clean:webpack', exec('webpack --mode production')],
|
webpack: ['clean:webpack', exec('webpack --mode production')],
|
||||||
'webpack:dev': ['clean:webpack', exec('webpack --mode development')],
|
|
||||||
'webpack:watch': ['clean:webpack', exec('webpack --mode development --watch')],
|
'webpack:watch': ['clean:webpack', exec('webpack --mode development --watch')],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user