use better instance dropdown
This commit is contained in:
parent
955ad4d0cf
commit
74511c67dd
|
@ -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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) => ({
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue