mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Updated list servers action so that it tries to fetch servers from the servers.json file when no local servers are found
This commit is contained in:
parent
502c8a7e02
commit
20820c47d4
9 changed files with 74 additions and 48 deletions
|
@ -3,7 +3,7 @@
|
||||||
"description": "A React-based progressive web application for shlink",
|
"description": "A React-based progressive web application for shlink",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"homepage": "https://shlink.io",
|
"homepage": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "npm run lint:js && npm run lint:css",
|
"lint": "npm run lint:js && npm run lint:css",
|
||||||
"lint:js": "eslint src test scripts config",
|
"lint:js": "eslint src test scripts config",
|
||||||
|
|
|
@ -18,18 +18,20 @@ export default class Home extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const servers = values(this.props.servers);
|
const { servers: { list, loading } } = this.props;
|
||||||
|
const servers = values(list);
|
||||||
const hasServers = !isEmpty(servers);
|
const hasServers = !isEmpty(servers);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="home">
|
<div className="home">
|
||||||
<h1 className="home__title">Welcome to Shlink</h1>
|
<h1 className="home__title">Welcome to Shlink</h1>
|
||||||
<h5 className="home__intro">
|
<h5 className="home__intro">
|
||||||
{hasServers && <span>Please, select a server.</span>}
|
{!loading && hasServers && <span>Please, select a server.</span>}
|
||||||
{!hasServers && <span>Please, <Link to="/server/create">add a server</Link>.</span>}
|
{!loading && !hasServers && <span>Please, <Link to="/server/create">add a server</Link>.</span>}
|
||||||
|
{loading && <span>Trying to load servers....</span>}
|
||||||
</h5>
|
</h5>
|
||||||
|
|
||||||
{hasServers && (
|
{!loading && hasServers && (
|
||||||
<ListGroup className="home__servers-list">
|
<ListGroup className="home__servers-list">
|
||||||
{servers.map(({ name, id }) => (
|
{servers.map(({ name, id }) => (
|
||||||
<ListGroupItem
|
<ListGroupItem
|
||||||
|
|
|
@ -14,7 +14,12 @@ const ServersDropdown = (serversExporter) => class ServersDropdown extends React
|
||||||
};
|
};
|
||||||
|
|
||||||
renderServers = () => {
|
renderServers = () => {
|
||||||
const { servers, selectedServer, selectServer } = this.props;
|
const { servers: { list, loading }, selectedServer, selectServer } = this.props;
|
||||||
|
const servers = values(list);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <DropdownItem disabled><i>Trying to load servers...</i></DropdownItem>;
|
||||||
|
}
|
||||||
|
|
||||||
if (isEmpty(servers)) {
|
if (isEmpty(servers)) {
|
||||||
return <DropdownItem disabled><i>Add a server first...</i></DropdownItem>;
|
return <DropdownItem disabled><i>Add a server first...</i></DropdownItem>;
|
||||||
|
@ -22,7 +27,7 @@ const ServersDropdown = (serversExporter) => class ServersDropdown extends React
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{values(servers).map(({ name, id }) => (
|
{servers.map(({ name, id }) => (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
key={id}
|
key={id}
|
||||||
tag={Link}
|
tag={Link}
|
||||||
|
@ -46,18 +51,14 @@ const ServersDropdown = (serversExporter) => class ServersDropdown extends React
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount = this.props.listServers;
|
||||||
this.props.listServers();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render = () => (
|
||||||
return (
|
|
||||||
<UncontrolledDropdown nav inNavbar>
|
<UncontrolledDropdown nav inNavbar>
|
||||||
<DropdownToggle nav caret>Servers</DropdownToggle>
|
<DropdownToggle nav caret>Servers</DropdownToggle>
|
||||||
<DropdownMenu right>{this.renderServers()}</DropdownMenu>
|
<DropdownMenu right>{this.renderServers()}</DropdownMenu>
|
||||||
</UncontrolledDropdown>
|
</UncontrolledDropdown>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ServersDropdown;
|
export default ServersDropdown;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { UncontrolledTooltip } from 'reactstrap';
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
import { assoc, map } from 'ramda';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const ImportServersBtn = (serversImporter) => class ImportServersBtn extends React.Component {
|
const ImportServersBtn = (serversImporter) => class ImportServersBtn extends React.Component {
|
||||||
|
@ -22,10 +20,8 @@ const ImportServersBtn = (serversImporter) => class ImportServersBtn extends Rea
|
||||||
render() {
|
render() {
|
||||||
const { importServersFromFile } = serversImporter;
|
const { importServersFromFile } = serversImporter;
|
||||||
const { onImport, createServers } = this.props;
|
const { onImport, createServers } = this.props;
|
||||||
const assocId = (server) => assoc('id', uuid(), server);
|
|
||||||
const onChange = ({ target }) =>
|
const onChange = ({ target }) =>
|
||||||
importServersFromFile(target.files[0])
|
importServersFromFile(target.files[0])
|
||||||
.then(map(assocId))
|
|
||||||
.then(createServers)
|
.then(createServers)
|
||||||
.then(onImport)
|
.then(onImport)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -10,10 +10,10 @@ const initialState = null;
|
||||||
|
|
||||||
export const resetSelectedServer = createAction(RESET_SELECTED_SERVER);
|
export const resetSelectedServer = createAction(RESET_SELECTED_SERVER);
|
||||||
|
|
||||||
export const selectServer = (serversService) => (serverId) => (dispatch) => {
|
export const selectServer = ({ findServerById }) => (serverId) => (dispatch) => {
|
||||||
dispatch(resetShortUrlParams());
|
dispatch(resetShortUrlParams());
|
||||||
|
|
||||||
const selectedServer = serversService.findServerById(serverId);
|
const selectedServer = findServerById(serverId);
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: SELECT_SERVER,
|
type: SELECT_SERVER,
|
||||||
|
|
|
@ -1,16 +1,51 @@
|
||||||
import { createAction, handleActions } from 'redux-actions';
|
import { handleActions } from 'redux-actions';
|
||||||
import { pipe } from 'ramda';
|
import { pipe, isEmpty, assoc, map } from 'ramda';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { homepage } from '../../../package.json';
|
||||||
|
|
||||||
|
/* eslint-disable padding-line-between-statements */
|
||||||
|
export const FETCH_SERVERS_START = 'shlink/servers/FETCH_SERVERS_START';
|
||||||
export const FETCH_SERVERS = 'shlink/servers/FETCH_SERVERS';
|
export const FETCH_SERVERS = 'shlink/servers/FETCH_SERVERS';
|
||||||
|
/* eslint-enable padding-line-between-statements */
|
||||||
|
|
||||||
export const listServers = ({ listServers }) => createAction(FETCH_SERVERS, () => listServers());
|
const initialState = {
|
||||||
|
list: {},
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
|
||||||
export const createServer = ({ createServer }, listServers) => pipe(createServer, listServers);
|
const assocId = (server) => assoc('id', uuid(), server);
|
||||||
|
|
||||||
export const deleteServer = ({ deleteServer }, listServers) => pipe(deleteServer, listServers);
|
|
||||||
|
|
||||||
export const createServers = ({ createServers }, listServers) => pipe(createServers, listServers);
|
|
||||||
|
|
||||||
export default handleActions({
|
export default handleActions({
|
||||||
[FETCH_SERVERS]: (state, { payload }) => payload,
|
[FETCH_SERVERS_START]: (state) => ({ ...state, loading: true }),
|
||||||
}, {});
|
[FETCH_SERVERS]: (state, { list }) => ({ list, loading: false }),
|
||||||
|
}, initialState);
|
||||||
|
|
||||||
|
export const listServers = ({ listServers, createServers }, { get }) => () => async (dispatch) => {
|
||||||
|
dispatch({ type: FETCH_SERVERS_START });
|
||||||
|
|
||||||
|
// Fetch list from local storage.
|
||||||
|
const localList = listServers();
|
||||||
|
|
||||||
|
if (!isEmpty(localList)) {
|
||||||
|
dispatch({ type: FETCH_SERVERS, list: localList });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If local list is empty, try to fetch it remotely, calculate IDs for every server, and use it
|
||||||
|
const { data: remoteList } = await get(`${homepage}/servers.json`);
|
||||||
|
const listWithIds = map(assocId, remoteList);
|
||||||
|
|
||||||
|
createServers(listWithIds);
|
||||||
|
dispatch({ type: FETCH_SERVERS, list: listWithIds });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createServer = ({ createServer }, listServersAction) => pipe(createServer, listServersAction);
|
||||||
|
|
||||||
|
export const deleteServer = ({ deleteServer }, listServersAction) => pipe(deleteServer, listServersAction);
|
||||||
|
|
||||||
|
export const createServers = ({ createServers }, listServersAction) => pipe(
|
||||||
|
map(assocId),
|
||||||
|
createServers,
|
||||||
|
listServersAction
|
||||||
|
);
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
export const serversImporterType = PropTypes.shape({
|
|
||||||
importServersFromFile: PropTypes.func,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default class ServersImporter {
|
export default class ServersImporter {
|
||||||
constructor(csvjson) {
|
constructor(csvjson) {
|
||||||
this.csvjson = csvjson;
|
this.csvjson = csvjson;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { assoc, dissoc, reduce } from 'ramda';
|
import { assoc, curry, dissoc, reduce } from 'ramda';
|
||||||
|
|
||||||
const SERVERS_STORAGE_KEY = 'servers';
|
const SERVERS_STORAGE_KEY = 'servers';
|
||||||
|
|
||||||
export default class ServersService {
|
export default class ServersService {
|
||||||
constructor(storage) {
|
constructor(storage) {
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
this.setServers = curry(this.storage.set)(SERVERS_STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
listServers = () => this.storage.get(SERVERS_STORAGE_KEY) || {};
|
listServers = () => this.storage.get(SERVERS_STORAGE_KEY) || {};
|
||||||
|
@ -20,12 +21,9 @@ export default class ServersService {
|
||||||
servers
|
servers
|
||||||
);
|
);
|
||||||
|
|
||||||
this.storage.set(SERVERS_STORAGE_KEY, allServers);
|
this.setServers(allServers);
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteServer = (server) =>
|
deleteServer = ({ id }) =>
|
||||||
this.storage.set(
|
this.setServers(dissoc(id, this.listServers()));
|
||||||
SERVERS_STORAGE_KEY,
|
|
||||||
dissoc(server.id, this.listServers())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ const provideServices = (bottle, connect, withRouter) => {
|
||||||
bottle.serviceFactory('createServer', createServer, 'ServersService', 'listServers');
|
bottle.serviceFactory('createServer', createServer, 'ServersService', 'listServers');
|
||||||
bottle.serviceFactory('createServers', createServers, 'ServersService', 'listServers');
|
bottle.serviceFactory('createServers', createServers, 'ServersService', 'listServers');
|
||||||
bottle.serviceFactory('deleteServer', deleteServer, 'ServersService', 'listServers');
|
bottle.serviceFactory('deleteServer', deleteServer, 'ServersService', 'listServers');
|
||||||
bottle.serviceFactory('listServers', listServers, 'ServersService');
|
bottle.serviceFactory('listServers', listServers, 'ServersService', 'axios');
|
||||||
|
|
||||||
bottle.serviceFactory('resetSelectedServer', () => resetSelectedServer);
|
bottle.serviceFactory('resetSelectedServer', () => resetSelectedServer);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue