2016-06-24 06:52:45 +08:00
|
|
|
/* eslint react/react-in-jsx-scope: 0*/
|
2016-07-01 03:33:08 +08:00
|
|
|
const React = window.React;
|
|
|
|
const ReactDOM = window.ReactDOM;
|
2016-07-08 05:30:51 +08:00
|
|
|
const {
|
|
|
|
SyncPolicy,
|
|
|
|
SetAllSyncPolicies,
|
|
|
|
AccountFilter,
|
|
|
|
SyncGraph,
|
2016-07-12 03:55:34 +08:00
|
|
|
SyncbackRequestDetails,
|
2016-07-08 05:30:51 +08:00
|
|
|
} = window;
|
2016-06-24 06:52:45 +08:00
|
|
|
|
|
|
|
class Account extends React.Component {
|
2016-06-28 14:48:00 +08:00
|
|
|
renderError() {
|
2016-07-01 03:33:08 +08:00
|
|
|
const {account} = this.props;
|
|
|
|
|
2016-06-28 14:48:00 +08:00
|
|
|
if (account.sync_error != null) {
|
2016-07-02 06:46:15 +08:00
|
|
|
const {message, stack} = account.sync_error
|
2016-06-28 14:48:00 +08:00
|
|
|
const error = {
|
2016-07-02 06:46:15 +08:00
|
|
|
message,
|
|
|
|
stack: stack.slice(0, 4),
|
2016-06-28 14:48:00 +08:00
|
|
|
}
|
|
|
|
return (
|
2016-07-08 05:30:51 +08:00
|
|
|
<div>
|
|
|
|
<div className="section">Error</div>
|
|
|
|
<div className="error">
|
|
|
|
<pre>
|
|
|
|
{JSON.stringify(error, null, 2)}
|
|
|
|
</pre>
|
|
|
|
</div>
|
2016-06-28 14:48:00 +08:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return <span />
|
|
|
|
}
|
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
render() {
|
2016-07-01 03:33:08 +08:00
|
|
|
const {account, assignment, active} = this.props;
|
2016-06-28 14:48:00 +08:00
|
|
|
const errorClass = account.sync_error ? ' errored' : ''
|
2016-07-08 05:30:51 +08:00
|
|
|
|
|
|
|
const numStoredSyncs = account.last_sync_completions.length;
|
|
|
|
const oldestSync = account.last_sync_completions[numStoredSyncs - 1];
|
|
|
|
const newestSync = account.last_sync_completions[0];
|
|
|
|
const avgBetweenSyncs = (newestSync - oldestSync) / (1000 * numStoredSyncs);
|
|
|
|
const timeSinceLastSync = (Date.now() - newestSync) / 1000;
|
|
|
|
|
|
|
|
let firstSyncDuration = "Incomplete";
|
2016-07-12 05:16:39 +08:00
|
|
|
if (account.first_sync_completion) {
|
|
|
|
firstSyncDuration = (new Date(account.first_sync_completion) - new Date(account.created_at)) / 1000;
|
2016-07-01 08:24:20 +08:00
|
|
|
}
|
2016-07-08 05:30:51 +08:00
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
return (
|
2016-06-28 14:48:00 +08:00
|
|
|
<div className={`account${errorClass}`}>
|
2016-07-01 03:33:08 +08:00
|
|
|
<h3>{account.email_address} {active ? '🌕' : '🌑'}</h3>
|
2016-06-24 06:52:45 +08:00
|
|
|
<strong>{assignment}</strong>
|
2016-07-12 03:55:34 +08:00
|
|
|
<SyncbackRequestDetails accountId={account.id} />
|
2016-07-06 06:41:56 +08:00
|
|
|
<SyncPolicy
|
|
|
|
accountId={account.id}
|
|
|
|
stringifiedSyncPolicy={JSON.stringify(account.sync_policy, null, 2)}
|
|
|
|
/>
|
2016-07-02 04:15:49 +08:00
|
|
|
<div className="section">Sync Cycles</div>
|
2016-07-08 05:30:51 +08:00
|
|
|
<div className="stats">
|
|
|
|
<b>First Sync Duration (seconds)</b>:
|
|
|
|
<pre>{firstSyncDuration}</pre>
|
|
|
|
<b> Average Time Between Syncs (seconds)</b>:
|
|
|
|
<pre>{avgBetweenSyncs}</pre>
|
|
|
|
<b>Time Since Last Sync (seconds)</b>:
|
|
|
|
<pre>{timeSinceLastSync}</pre>
|
|
|
|
<b>Recent Syncs</b>:
|
|
|
|
<SyncGraph id={account.last_sync_completions.length} syncTimestamps={account.last_sync_completions} />
|
2016-07-02 04:15:49 +08:00
|
|
|
</div>
|
2016-06-28 14:48:00 +08:00
|
|
|
{this.renderError()}
|
2016-06-24 06:52:45 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-01 03:33:08 +08:00
|
|
|
Account.propTypes = {
|
|
|
|
account: React.PropTypes.object,
|
|
|
|
active: React.PropTypes.bool,
|
|
|
|
assignment: React.PropTypes.string,
|
|
|
|
}
|
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
class Root extends React.Component {
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.state = {
|
|
|
|
accounts: {},
|
|
|
|
assignments: {},
|
2016-07-01 03:33:08 +08:00
|
|
|
activeAccountIds: [],
|
2016-07-07 07:49:16 +08:00
|
|
|
visibleAccounts: AccountFilter.states.all,
|
2016-06-24 06:52:45 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
let url = null;
|
|
|
|
if (window.location.protocol === "https:") {
|
|
|
|
url = `wss://${window.location.host}/accounts`;
|
|
|
|
} else {
|
|
|
|
url = `ws://${window.location.host}/accounts`;
|
|
|
|
}
|
|
|
|
this.websocket = new WebSocket(url);
|
|
|
|
this.websocket.onopen = () => {
|
|
|
|
this.websocket.send("Message to send");
|
|
|
|
};
|
|
|
|
this.websocket.onmessage = (evt) => {
|
|
|
|
try {
|
|
|
|
const msg = JSON.parse(evt.data);
|
|
|
|
if (msg.cmd === 'ACCOUNT') {
|
|
|
|
this.onReceivedAccount(msg.payload);
|
|
|
|
}
|
|
|
|
if (msg.cmd === 'ASSIGNMENTS') {
|
|
|
|
this.onReceivedAssignments(msg.payload);
|
|
|
|
}
|
2016-07-01 03:33:08 +08:00
|
|
|
if (msg.cmd === 'ACTIVE') {
|
|
|
|
this.onReceivedActiveAccountIds(msg.payload);
|
|
|
|
}
|
2016-06-24 06:52:45 +08:00
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.websocket.onclose = () => {
|
|
|
|
window.location.reload();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
onReceivedAssignments(assignments) {
|
|
|
|
this.setState({assignments})
|
|
|
|
}
|
|
|
|
|
2016-07-01 03:33:08 +08:00
|
|
|
onReceivedActiveAccountIds(accountIds) {
|
|
|
|
this.setState({activeAccountIds: accountIds})
|
|
|
|
}
|
2016-07-01 04:25:13 +08:00
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
onReceivedAccount(account) {
|
|
|
|
const accounts = Object.assign({}, this.state.accounts);
|
|
|
|
accounts[account.id] = account;
|
|
|
|
this.setState({accounts});
|
|
|
|
}
|
|
|
|
|
2016-07-07 07:49:16 +08:00
|
|
|
onFilter() {
|
|
|
|
this.setState({visibleAccounts: document.getElementById('account-filter').value});
|
|
|
|
}
|
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
render() {
|
2016-07-07 07:49:16 +08:00
|
|
|
let ids = Object.keys(this.state.accounts);
|
|
|
|
|
|
|
|
switch (this.state.visibleAccounts) {
|
|
|
|
case AccountFilter.states.errored:
|
|
|
|
ids = ids.filter((id) => this.state.accounts[id].sync_error)
|
|
|
|
break;
|
|
|
|
case AccountFilter.states.notErrored:
|
|
|
|
ids = ids.filter((id) => !this.state.accounts[id].sync_error)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-24 06:52:45 +08:00
|
|
|
return (
|
|
|
|
<div>
|
2016-07-07 07:49:16 +08:00
|
|
|
<AccountFilter id="account-filter" onChange={() => this.onFilter.call(this)} />
|
2016-07-07 06:48:25 +08:00
|
|
|
<SetAllSyncPolicies accountIds={ids.map((id) => parseInt(id, 10))} />
|
2016-06-24 06:52:45 +08:00
|
|
|
{
|
2016-07-07 06:48:25 +08:00
|
|
|
ids.sort((a, b) => a.localeCompare(b)).map((id) =>
|
2016-06-24 06:52:45 +08:00
|
|
|
<Account
|
2016-07-01 03:33:08 +08:00
|
|
|
key={id}
|
|
|
|
active={this.state.activeAccountIds.includes(id)}
|
|
|
|
assignment={this.state.assignments[id]}
|
|
|
|
account={this.state.accounts[id]}
|
2016-06-24 06:52:45 +08:00
|
|
|
/>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReactDOM.render(
|
|
|
|
<Root />,
|
|
|
|
document.getElementById('root')
|
|
|
|
);
|