loading instances
This commit is contained in:
parent
4e0adc7579
commit
6d05ceadba
|
@ -54,11 +54,13 @@ INSTALLED_APPS = [
|
|||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'silk',
|
||||
'corsheaders',
|
||||
'scraper.apps.ScraperConfig',
|
||||
'apiv1.apps.Apiv1Config',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
|
|
|
@ -4,3 +4,9 @@ DEBUG = True
|
|||
|
||||
ALLOWED_HOSTS += ['localhost']
|
||||
|
||||
CORS_ORIGIN_WHITELIST = [
|
||||
'localhost:3000',
|
||||
'localhost:8000',
|
||||
'127.0.0.1',
|
||||
]
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
from .base import *
|
||||
|
||||
ALLOWED_HOSTS += ['fediverse.space']
|
||||
ALLOWED_HOSTS += ['fediverse.space']
|
||||
|
||||
CORS_ORIGIN_WHITELIST = [
|
||||
'fediverse.space',
|
||||
]
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
"@blueprintjs/core": "^3.4.0",
|
||||
"@blueprintjs/icons": "^3.1.0",
|
||||
"@blueprintjs/select": "^3.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"cross-fetch": "^2.2.2",
|
||||
"normalize.css": "^8.0.0",
|
||||
"react": "^16.4.2",
|
||||
"react-dom": "^16.4.2",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-scripts-ts": "2.17.0",
|
||||
"react-virtualized": "^9.20.1",
|
||||
"redux": "^4.0.0",
|
||||
"redux-thunk": "^2.3.0"
|
||||
},
|
||||
|
@ -22,11 +24,13 @@
|
|||
"eject": "react-scripts-ts eject"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/classnames": "^2.2.6",
|
||||
"@types/jest": "^23.3.1",
|
||||
"@types/node": "^10.9.2",
|
||||
"@types/react": "^16.4.12",
|
||||
"@types/react-dom": "^16.0.7",
|
||||
"@types/react-redux": "^6.0.6",
|
||||
"@types/react-virtualized": "^9.18.7",
|
||||
"typescript": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
<title>fediverse.space</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
|
|
@ -10,6 +10,7 @@ import { fetchInstances } from './redux/actions';
|
|||
import { IAppState, IInstance } from './redux/types';
|
||||
|
||||
interface IAppProps {
|
||||
currentInstance: IInstance;
|
||||
instances?: IInstance[],
|
||||
isLoadingInstances: boolean,
|
||||
fetchInstances: () => void;
|
||||
|
@ -19,6 +20,8 @@ class AppImpl extends React.Component<IAppProps> {
|
|||
let body = this.welcomeState();
|
||||
if (this.props.isLoadingInstances) {
|
||||
body = this.loadingState();
|
||||
} else if (!!this.props.instances) {
|
||||
body = this.renderGraph()
|
||||
}
|
||||
// TODO: show the number of instances up front
|
||||
return (
|
||||
|
@ -46,14 +49,26 @@ class AppImpl extends React.Component<IAppProps> {
|
|||
<NonIdealState
|
||||
className="fediverse-welcome"
|
||||
icon={<Spinner />}
|
||||
title="Welcome to fediverse.space!"
|
||||
title="Loading..."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private renderGraph = () => {
|
||||
return (
|
||||
<NonIdealState
|
||||
className="fediverse-welcome"
|
||||
icon={IconNames.SEARCH_AROUND}
|
||||
title="Graph. TODO"
|
||||
description={"Selected " + this.props.currentInstance.name}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: IAppState) => ({
|
||||
currentInstance: state.currentInstance,
|
||||
instances: state.data.instances,
|
||||
isLoadingInstances: state.data.isLoadingInstances,
|
||||
})
|
||||
|
|
|
@ -15,41 +15,48 @@ interface IInstanceSearchProps {
|
|||
}
|
||||
|
||||
class InstanceSearchImpl extends React.Component<IInstanceSearchProps> {
|
||||
|
||||
public render() {
|
||||
// TODO: make prettier when no instances loaded
|
||||
if (!this.props.instances) {
|
||||
return (
|
||||
<Suggest
|
||||
items={[]}
|
||||
inputValueRenderer={this.inputValueRenderer}
|
||||
itemRenderer={this.itemRenderer}
|
||||
onItemSelect={this.onItemSelect}
|
||||
popoverProps={{minimal: true}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Suggest
|
||||
items={this.props.instances!.map(i => i.name)}
|
||||
inputValueRenderer={this.inputValueRenderer}
|
||||
itemRenderer={this.itemRenderer}
|
||||
items={this.props.instances || []}
|
||||
onItemSelect={this.onItemSelect}
|
||||
popoverProps={{minimal: true}}
|
||||
// itemListRenderer={this.itemListRenderer}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private inputValueRenderer = (item: string) => {
|
||||
return item;
|
||||
private inputValueRenderer = (item: IInstance): string => {
|
||||
return item.name;
|
||||
}
|
||||
|
||||
private itemRenderer = (item: string, itemProps: IItemRendererProps) => {
|
||||
return <MenuItem text={item} />;
|
||||
private itemRenderer = (item: IInstance, itemProps: IItemRendererProps): JSX.Element => {
|
||||
return <MenuItem label={item.name} key={item.name} />;
|
||||
}
|
||||
|
||||
private onItemSelect = (item: string) => {
|
||||
return;
|
||||
private onItemSelect = (item: IInstance, event?: React.SyntheticEvent<HTMLElement>) => {
|
||||
this.props.selectInstance(item.name);
|
||||
}
|
||||
|
||||
// private itemListRenderer = (itemListProps: IItemListRendererProps<IInstance>): JSX.Element => {
|
||||
// return (
|
||||
// <List
|
||||
// height={350}
|
||||
// rowHeight={30}
|
||||
// rowCount={(this.props.instances && this.props.instances.length) || 0}
|
||||
// // tslint:disable-next-line
|
||||
// rowRenderer={this.rowRenderer}
|
||||
// width={214}
|
||||
// />
|
||||
// )
|
||||
// }
|
||||
|
||||
// private rowRenderer = (listRowProps: ListRowProps) => {
|
||||
// const instanceName = (this.props.instances && this.props.instances[listRowProps.index].name) || "";
|
||||
// return <MenuItem label={instanceName} key={instanceName} />;
|
||||
// }
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: IAppState) => ({
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
import { Alignment, Button, Icon, Navbar } from '@blueprintjs/core';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
|
||||
import { selectInstance } from '../redux/actions';
|
||||
import { IAppState, IInstance } from '../redux/types';
|
||||
import { InstanceSearch } from './InstanceSearch';
|
||||
|
||||
export class Nav extends React.Component {
|
||||
interface INavProps {
|
||||
instances?: IInstance[];
|
||||
selectInstance: (instance: string) => void;
|
||||
}
|
||||
|
||||
class NavImpl extends React.Component<INavProps> {
|
||||
public render() {
|
||||
return (
|
||||
<Navbar>
|
||||
|
@ -29,3 +38,11 @@ export class Nav extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: IAppState) => ({
|
||||
instances: state.data.instances,
|
||||
})
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
selectInstance: (instanceName: string) => dispatch(selectInstance(instanceName)),
|
||||
})
|
||||
export const Nav = connect(mapStateToProps, mapDispatchToProps)(NavImpl)
|
|
@ -9,4 +9,18 @@ html, body {
|
|||
|
||||
.fediverse-welcome {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.fediverse-instance-search-popover {
|
||||
max-height: 350px;
|
||||
min-width: 214px;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.fediverse-instance-search-popover-empty-state {
|
||||
padding: 10px;
|
||||
width: 214px;
|
||||
height: 60px;
|
||||
}
|
|
@ -7,7 +7,7 @@ import './index.css';
|
|||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { applyMiddleware, createStore } from 'redux';
|
||||
import { applyMiddleware, compose, createStore } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import { FocusStyleManager } from '@blueprintjs/core';
|
||||
|
@ -20,10 +20,11 @@ import registerServiceWorker from './registerServiceWorker';
|
|||
FocusStyleManager.onlyShowFocusOnTabs();
|
||||
|
||||
// Initialize redux
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
// @ts-ignore
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
const store = createStore(rootReducer, /* preloadedState, */ composeEnhancers(
|
||||
applyMiddleware(thunk)
|
||||
);
|
||||
));
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import fetch from 'cross-fetch';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
import { getFromApi } from '../util';
|
||||
import { ActionType, IInstance } from './types';
|
||||
|
||||
const API_ROOT = "https://fediverse.space/api/v1"
|
||||
|
||||
export const selectInstance = (instance: string) => {
|
||||
return {
|
||||
payload: {
|
||||
|
@ -33,8 +31,10 @@ export const fetchInstances = () => {
|
|||
// TODO: handle errors
|
||||
return (dispatch: Dispatch) => {
|
||||
dispatch(requestInstances());
|
||||
return fetch(`${API_ROOT}/instances/`)
|
||||
.then(response => response.json())
|
||||
return getFromApi("instances")
|
||||
.then(response => {
|
||||
return response.json();
|
||||
})
|
||||
.then(instances => dispatch(receiveInstances(instances))
|
||||
);
|
||||
}
|
||||
|
|
11
frontend/src/util.ts
Normal file
11
frontend/src/util.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import fetch from 'cross-fetch';
|
||||
|
||||
// const API_ROOT = "https://fediverse.space/api/v1/"
|
||||
const API_ROOT = "http://localhost:8000/api/v1/"
|
||||
|
||||
export const getFromApi = (path: string): Promise<any> => {
|
||||
const domain = API_ROOT.endsWith("/") ? API_ROOT : API_ROOT + "/";
|
||||
path = path.endsWith("/") ? path : path + "/";
|
||||
path += "?format=json"
|
||||
return fetch(domain + path);
|
||||
}
|
|
@ -46,6 +46,10 @@
|
|||
classnames "^2.2"
|
||||
tslib "^1.9.0"
|
||||
|
||||
"@types/classnames@^2.2.6":
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.6.tgz#dbe8a666156d556ed018e15a4c65f08937c3f628"
|
||||
|
||||
"@types/dom4@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033"
|
||||
|
@ -82,6 +86,13 @@
|
|||
"@types/react" "*"
|
||||
redux "^4.0.0"
|
||||
|
||||
"@types/react-virtualized@^9.18.7":
|
||||
version "9.18.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.18.7.tgz#8703d8904236819facff90b8b320f29233160c90"
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^16.4.12":
|
||||
version "16.4.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.12.tgz#c554005770b06c7cbcd6b0b19721e180deab7a02"
|
||||
|
@ -1468,7 +1479,7 @@ class-utils@^0.3.5:
|
|||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
classnames@^2.2:
|
||||
classnames@^2.2, classnames@^2.2.3, classnames@^2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
|
||||
|
@ -2139,7 +2150,7 @@ dom-converter@~0.1:
|
|||
dependencies:
|
||||
utila "~0.3"
|
||||
|
||||
dom-helpers@^3.3.1:
|
||||
"dom-helpers@^2.4.0 || ^3.0.0", dom-helpers@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
|
||||
|
||||
|
@ -4368,7 +4379,7 @@ longest@^1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.3.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
dependencies:
|
||||
|
@ -5807,6 +5818,17 @@ react-transition-group@^2.2.1:
|
|||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react-virtualized@^9.20.1:
|
||||
version "9.20.1"
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.20.1.tgz#02dc08fe9070386b8c48e2ac56bce7af0208d22d"
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
classnames "^2.2.3"
|
||||
dom-helpers "^2.4.0 || ^3.0.0"
|
||||
loose-envify "^1.3.0"
|
||||
prop-types "^15.6.0"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@^16.4.2:
|
||||
version "16.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.4.2.tgz#2cd90154e3a9d9dd8da2991149fdca3c260e129f"
|
||||
|
|
Loading…
Reference in a new issue