Added feature to export servers list

This commit is contained in:
Alejandro Celaya
2018-08-20 16:40:33 +02:00
parent d84bf01937
commit 2b373cc4af
5 changed files with 94 additions and 17 deletions

View File

@@ -21,7 +21,8 @@ body,
.dropdown-item {
cursor: pointer;
}
.dropdown-item.active {
.dropdown-item.active,
.dropdown-item:active {
@extend .bg-main;
}

View File

@@ -1,4 +1,4 @@
import { isEmpty, pick } from 'ramda';
import { isEmpty, pick, values } from 'ramda';
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
@@ -6,27 +6,39 @@ import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from
import { listServers } from './reducers/server';
import { selectServer } from '../servers/reducers/selectedServer';
import serversExporter from '../servers/services/ServersExporter';
const defaultProps = {
serversExporter,
};
export class ServersDropdown extends React.Component {
renderServers = () => {
const { servers, selectedServer, selectServer } = this.props;
const { servers, selectedServer, selectServer, serversExporter } = this.props;
if (isEmpty(servers)) {
return <DropdownItem disabled><i>Add a server first...</i></DropdownItem>
}
return Object.values(servers).map(({ name, id }) => (
<span key={id}>
<DropdownItem
tag={Link}
to={`/server/${id}/list-short-urls/1`}
active={selectedServer && selectedServer.id === id}
onClick={() => selectServer(id)} // FIXME This should be implicit
>
{name}
return (
<React.Fragment>
{values(servers).map(({ name, id }) => (
<DropdownItem
key={id}
tag={Link}
to={`/server/${id}/list-short-urls/1`}
active={selectedServer && selectedServer.id === id}
onClick={() => selectServer(id)} // FIXME This should be implicit
>
{name}
</DropdownItem>
))}
<DropdownItem divider />
<DropdownItem onClick={serversExporter.exportServers}>
Export servers
</DropdownItem>
</span>
));
</React.Fragment>
);
};
componentDidMount() {
@@ -35,12 +47,17 @@ export class ServersDropdown extends React.Component {
render() {
return (
<UncontrolledDropdown nav>
<UncontrolledDropdown nav inNavbar>
<DropdownToggle nav caret>Servers</DropdownToggle>
<DropdownMenu>{this.renderServers()}</DropdownMenu>
<DropdownMenu right>{this.renderServers()}</DropdownMenu>
</UncontrolledDropdown>
);
}
}
export default connect(pick(['servers', 'selectedServer']), { listServers, selectServer })(ServersDropdown);
ServersDropdown.defaultProps = defaultProps;
export default connect(
pick(['servers', 'selectedServer']),
{ listServers, selectServer }
)(ServersDropdown);

View File

@@ -0,0 +1,54 @@
import Storage from '../../utils/Storage';
import jsonexport from 'jsonexport/dist';
import { dissoc, values } from 'ramda';
const SERVERS_STORAGE_KEY = 'servers';
const saveCsv = (window, csv) => {
const { navigator, document } = window;
const filename = 'shlink-servers.csv';
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
// IE10 and IE11
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
return;
}
// Modern browsers
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
export class ServersExporter {
constructor(storage, window, jsonexport) {
this.storage = storage;
this.window = window;
this.jsonexport = jsonexport;
}
exportServers = async () => {
const servers = values(this.storage.get(SERVERS_STORAGE_KEY) || {}).map(
dissoc('id')
);
try {
const csv = await new Promise((resolve, reject) => {
this.jsonexport(servers, (err, csv) => err ? reject(err) : resolve(csv));
});
saveCsv(this.window, csv);
} catch (e) {
// FIXME Handle error
console.error(e);
}
};
}
export default new ServersExporter(Storage, global.window, jsonexport);