use better instance dropdown

This commit is contained in:
Tao Bojlen 2018-08-29 02:17:08 +02:00
parent 955ad4d0cf
commit 74511c67dd
5 changed files with 52 additions and 57 deletions

View file

@ -10,7 +10,7 @@ import { fetchInstances } from './redux/actions';
import { IAppState, IInstance } from './redux/types'; import { IAppState, IInstance } from './redux/types';
interface IAppProps { interface IAppProps {
currentInstance: IInstance; currentInstance: IInstance | null;
instances?: IInstance[], instances?: IInstance[],
isLoadingInstances: boolean, isLoadingInstances: boolean,
fetchInstances: () => void; fetchInstances: () => void;
@ -56,13 +56,15 @@ class AppImpl extends React.Component<IAppProps> {
private renderGraph = () => { private renderGraph = () => {
return ( return (
<NonIdealState <div>
className="fediverse-welcome" <NonIdealState
icon={IconNames.SEARCH_AROUND} className="fediverse-welcome"
title="Graph. TODO" icon={IconNames.SEARCH_AROUND}
description={"Selected " + this.props.currentInstance.name} title="Graph. TODO"
/> description={"Selected " + ((this.props.currentInstance && this.props.currentInstance.name) || "nothing")}
) />
</div>
);
} }
} }

View file

@ -1,62 +1,68 @@
import * as React from 'react'; import * as React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// import { List, ListRowProps } from 'react-virtualized';
import { Dispatch } from 'redux'; import { Dispatch } from 'redux';
import { MenuItem } from '@blueprintjs/core'; import { Button, MenuItem } from '@blueprintjs/core';
import { IItemRendererProps, Suggest } from '@blueprintjs/select'; import { IconNames } from '@blueprintjs/icons';
import { ItemPredicate, ItemRenderer, Select } from '@blueprintjs/select';
import { selectInstance } from '../redux/actions'; import { selectInstance } from '../redux/actions';
import { IAppState, IInstance } from '../redux/types'; import { IAppState, IInstance } from '../redux/types';
interface IInstanceSearchProps { interface IInstanceSearchProps {
currentInstance: IInstance; currentInstance: IInstance | null;
instances?: IInstance[]; instances?: IInstance[];
selectInstance: (instanceName: string) => void; selectInstance: (instanceName: string) => void;
} }
const InstanceSelect = Select.ofType<IInstance>();
class InstanceSearchImpl extends React.Component<IInstanceSearchProps> { class InstanceSearchImpl extends React.Component<IInstanceSearchProps> {
public render() { public render() {
return ( return (
<Suggest <InstanceSelect
inputValueRenderer={this.inputValueRenderer} items={this.props.instances && this.props.instances.slice(50) || []}
itemRenderer={this.itemRenderer} itemRenderer={this.itemRenderer}
items={this.props.instances || []}
onItemSelect={this.onItemSelect} onItemSelect={this.onItemSelect}
// itemListRenderer={this.itemListRenderer} itemPredicate={this.itemPredicate}
disabled={!this.props.instances}
>
<Button
icon={IconNames.SELECTION}
rightIcon={IconNames.CARET_DOWN}
text={(this.props.currentInstance && this.props.currentInstance.name) || ("Select an instance")}
disabled={!this.props.instances}
/>
</InstanceSelect>
);
}
private itemRenderer: ItemRenderer<IInstance> = (item, { handleClick, modifiers }) => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<MenuItem
text={item.name}
key={item.name}
active={modifiers.active}
onClick={handleClick}
/> />
) );
} }
private inputValueRenderer = (item: IInstance): string => { private itemPredicate: ItemPredicate<IInstance> = (query, item, index) => {
return item.name; if (!item.name) {
} return false;
}
private itemRenderer = (item: IInstance, itemProps: IItemRendererProps): JSX.Element => { return item.name.toLowerCase().indexOf(query.toLowerCase()) >= 0;
return <MenuItem label={item.name} key={item.name} />;
} }
private onItemSelect = (item: IInstance, event?: React.SyntheticEvent<HTMLElement>) => { private onItemSelect = (item: IInstance, event?: React.SyntheticEvent<HTMLElement>) => {
this.props.selectInstance(item.name); 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) => ({ const mapStateToProps = (state: IAppState) => ({

View file

@ -12,15 +12,7 @@ html, body {
} }
.fediverse-instance-search-popover { .fediverse-instance-search-popover {
max-height: 350px; height: 350px;
min-width: 214px; min-width: 214px;
overflow: scroll;
overflow-x: hidden; overflow-x: hidden;
text-align: left;
} }
.fediverse-instance-search-popover-empty-state {
padding: 10px;
width: 214px;
height: 60px;
}

View file

@ -24,8 +24,7 @@ const data = (state: IDataState = initialDataState, action: IAction) => {
} }
} }
const initialInstanceState = {'name': 'mastodon.social'} const currentInstance = (state: IInstance | null = null, action: IAction): IInstance | null => {
const currentInstance = (state: IInstance = initialInstanceState, action: IAction): IInstance => {
switch (action.type) { switch (action.type) {
case ActionType.SELECT_INSTANCE: case ActionType.SELECT_INSTANCE:
return action.payload; return action.payload;

View file

@ -9,10 +9,6 @@ export interface IAction {
payload: any, payload: any,
} }
export interface IInstanceState {
currentInstance?: string,
}
export interface IInstance { export interface IInstance {
name: string, name: string,
numUsers?: number, numUsers?: number,
@ -24,6 +20,6 @@ export interface IDataState {
} }
export interface IAppState { export interface IAppState {
currentInstance: IInstance, currentInstance: IInstance | null,
data: IDataState, data: IDataState,
} }