1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-30 00:57:12 +00:00
Files
seahub/frontend/src/pages/linked-devices/linked-devices.js

244 lines
6.3 KiB
JavaScript
Raw Normal View History

2018-11-26 17:53:18 +08:00
import React, { Component } from 'react';
import { Dropdown, DropdownToggle, DropdownItem } from 'reactstrap';
import moment from 'moment';
import { seafileAPI } from '../../utils/seafile-api';
2018-11-26 14:00:32 +08:00
import { gettext, loginUrl } from '../../utils/constants';
2018-12-07 14:58:37 +08:00
import toaster from '../../components/toast';
import EmptyTip from '../../components/empty-tip';
import { Utils } from '../../utils/utils';
class Content extends Component {
render() {
const {loading, errorMsg, items} = this.props.data;
if (loading) {
return <span className="loading-icon loading-tip"></span>;
} else if (errorMsg) {
return <p className="error text-center">{errorMsg}</p>;
} else {
const emptyTip = (
<EmptyTip>
<h2>{gettext('You do not have connected devices')}</h2>
<p>{gettext('Your clients (Desktop/Android/iOS) will be listed here.')}</p>
</EmptyTip>
);
const desktopThead = (
<thead>
<tr>
<th width="13%">{gettext('Platform')}</th>
<th width="30%">{gettext('Device Name')}</th>
<th width="30%">{gettext('IP')}</th>
<th width="17%">{gettext('Last Access')}</th>
<th width="10%"></th>
</tr>
</thead>
);
const mobileThead = (
<thead>
<tr>
<th width="92%"></th>
<th width="8%"></th>
</tr>
</thead>
);
return items.length ? (
<table className={`table-hover ${window.innerWidth >= 768 ? '': 'table-thead-hidden'}`}>
{window.innerWidth >= 768 ? desktopThead : mobileThead}
<TableBody items={items} />
</table>
): emptyTip;
}
}
}
class TableBody extends Component {
constructor(props) {
super(props);
this.state = {
items: this.props.items
};
}
render() {
let listLinkedDevices = this.state.items.map(function(item, index) {
return <Item key={index} data={item} />;
}, this);
return (
<tbody>{listLinkedDevices}</tbody>
);
}
}
class Item extends Component {
constructor(props) {
super(props);
this.state = {
isOpMenuOpen: false, // for mobile
showOpIcon: false,
unlinked: false
};
}
toggleOpMenu = () => {
this.setState({
isOpMenuOpen: !this.state.isOpMenuOpen
});
}
handleMouseOver = () => {
this.setState({
showOpIcon: true
});
}
handleMouseOut = () => {
this.setState({
showOpIcon: false
});
}
handleClick = (e) => {
e.preventDefault();
const data = this.props.data;
seafileAPI.unlinkDevice(data.platform, data.device_id).then((res) => {
this.setState({
unlinked: true
});
let msg_s = gettext('Successfully unlink %(name)s.');
msg_s = msg_s.replace('%(name)s', data.device_name);
2018-12-07 14:58:37 +08:00
toaster.success(msg_s);
}).catch((error) => {
let errMessage = Utils.getErrorMsg(error);
if (errMessage === gettext('Error')) {
errMessage = gettext('Failed to unlink %(name)s');
errMessage = errMessage.replace('%(name)s', data.device_name);
}
toaster.danger(errMessage);
});
}
render() {
if (this.state.unlinked) {
return null;
}
const data = this.props.data;
2018-12-28 11:12:24 +08:00
let opClasses = 'sf2-icon-delete unlink-device action-icon';
opClasses += this.state.showOpIcon ? '' : ' invisible';
const desktopItem = (
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
<td>{data.platform}</td>
<td>{data.device_name}</td>
<td>{data.last_login_ip}</td>
<td>{moment(data.last_accessed).fromNow()}</td>
<td>
<a href="#" className={opClasses} title={gettext('Unlink')} aria-label={gettext('Unlink')} onClick={this.handleClick}></a>
</td>
</tr>
);
const mobileItem = (
<tr>
<td>
{data.device_name}<br />
<span className="item-meta-info">{data.last_login_ip}</span>
<span className="item-meta-info">{moment(data.last_accessed).fromNow()}</span>
<span className="item-meta-info">{data.platform}</span>
</td>
<td>
<Dropdown isOpen={this.state.isOpMenuOpen} toggle={this.toggleOpMenu}>
<DropdownToggle
tag="i"
className="sf-dropdown-toggle fa fa-ellipsis-v ml-0"
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isOpMenuOpen}
/>
<div className={this.state.isOpMenuOpen ? '' : 'd-none'} onClick={this.toggleOpMenu}>
<div className="mobile-operation-menu-bg-layer"></div>
<div className="mobile-operation-menu">
<DropdownItem className="mobile-menu-item" onClick={this.handleClick}>{gettext('Unlink')}</DropdownItem>
</div>
</div>
</Dropdown>
</td>
</tr>
);
if (window.innerWidth >= 768) {
return desktopItem;
} else {
return mobileItem;
}
}
}
class LinkedDevices extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
errorMsg: '',
items: []
};
}
componentDidMount() {
seafileAPI.listLinkedDevices().then((res) => {
this.setState({
loading: false,
items: res.data
});
}).catch((error) => {
if (error.response) {
if (error.response.status == 403) {
this.setState({
loading: false,
errorMsg: gettext('Permission denied')
});
location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`;
} else {
this.setState({
loading: false,
errorMsg: gettext('Error')
});
}
} else {
this.setState({
loading: false,
errorMsg: gettext('Please check the network.')
});
}
});
}
render() {
return (
2018-11-26 17:53:18 +08:00
<div className="main-panel-center">
<div className="cur-view-container" id="linked-devices">
<div className="cur-view-path">
<h3 className="sf-heading">{gettext('Linked Devices')}</h3>
</div>
<div className="cur-view-content">
<Content data={this.state} />
2018-11-26 14:00:32 +08:00
</div>
</div>
2018-11-26 17:53:18 +08:00
</div>
);
}
}
export default LinkedDevices;