implemented general actionbar

This commit is contained in:
Peter Holmberg
2018-09-28 14:34:58 +02:00
parent 7ae4076ddd
commit 21cfc11009
8 changed files with 100 additions and 193 deletions

View File

@@ -1,23 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import { DataSourcesActionBar, Props } from './DataSourcesActionBar';
import { LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector';
const setup = (propOverrides?: object) => {
const props: Props = {
layoutMode: LayoutModes.Grid,
searchQuery: '',
setDataSourcesLayoutMode: jest.fn(),
setDataSourcesSearchQuery: jest.fn(),
};
return shallow(<DataSourcesActionBar {...props} />);
};
describe('Render', () => {
it('should render component', () => {
const wrapper = setup();
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -1,62 +0,0 @@
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import LayoutSelector, { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions';
import { getDataSourcesLayoutMode, getDataSourcesSearchQuery } from './state/selectors';
export interface Props {
searchQuery: string;
layoutMode: LayoutMode;
setDataSourcesLayoutMode: typeof setDataSourcesLayoutMode;
setDataSourcesSearchQuery: typeof setDataSourcesSearchQuery;
}
export class DataSourcesActionBar extends PureComponent<Props> {
onSearchQueryChange = event => {
this.props.setDataSourcesSearchQuery(event.target.value);
};
render() {
const { searchQuery, layoutMode, setDataSourcesLayoutMode } = this.props;
return (
<div className="page-action-bar">
<div className="gf-form gf-form--grow">
<label className="gf-form--has-input-icon">
<input
type="text"
className="gf-form-input width-20"
value={searchQuery}
onChange={this.onSearchQueryChange}
placeholder="Filter by name or type"
/>
<i className="gf-form-input-icon fa fa-search" />
</label>
<LayoutSelector
mode={layoutMode}
onLayoutModeChanged={(mode: LayoutMode) => setDataSourcesLayoutMode(mode)}
/>
</div>
<div className="page-action-bar__spacer" />
<a className="page-header__cta btn btn-success" href="datasources/new">
<i className="fa fa-plus" />
Add data source
</a>
</div>
);
}
}
function mapStateToProps(state) {
return {
searchQuery: getDataSourcesSearchQuery(state.dataSources),
layoutMode: getDataSourcesLayoutMode(state.dataSources),
};
}
const mapDispatchToProps = {
setDataSourcesLayoutMode,
setDataSourcesSearchQuery,
};
export default connect(mapStateToProps, mapDispatchToProps)(DataSourcesActionBar);

View File

@@ -2,21 +2,29 @@ import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import PageHeader from '../../core/components/PageHeader/PageHeader';
import DataSourcesActionBar from './DataSourcesActionBar';
import OrgActionBar from '../../core/components/OrgActionBar/OrgActionBar';
import EmptyListCTA from '../../core/components/EmptyListCTA/EmptyListCTA';
import DataSourcesList from './DataSourcesList';
import { loadDataSources } from './state/actions';
import { getDataSources, getDataSourcesCount, getDataSourcesLayoutMode } from './state/selectors';
import { getNavModel } from '../../core/selectors/navModel';
import { DataSource, NavModel } from 'app/types';
import { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
import EmptyListCTA from '../../core/components/EmptyListCTA/EmptyListCTA';
import { loadDataSources, setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions';
import { getNavModel } from '../../core/selectors/navModel';
import {
getDataSources,
getDataSourcesCount,
getDataSourcesLayoutMode,
getDataSourcesSearchQuery,
} from './state/selectors';
export interface Props {
navModel: NavModel;
dataSources: DataSource[];
dataSourcesCount: number;
layoutMode: LayoutMode;
searchQuery: string;
loadDataSources: typeof loadDataSources;
setDataSourcesLayoutMode: typeof setDataSourcesLayoutMode;
setDataSourcesSearchQuery: typeof setDataSourcesSearchQuery;
}
const emptyListModel = {
@@ -40,7 +48,20 @@ export class DataSourcesListPage extends PureComponent<Props> {
}
render() {
const { dataSources, dataSourcesCount, navModel, layoutMode } = this.props;
const {
dataSources,
dataSourcesCount,
navModel,
layoutMode,
searchQuery,
setDataSourcesSearchQuery,
setDataSourcesLayoutMode,
} = this.props;
const linkButton = {
href: 'datasources/new',
title: 'Add data source',
};
return (
<div>
@@ -50,7 +71,14 @@ export class DataSourcesListPage extends PureComponent<Props> {
<EmptyListCTA model={emptyListModel} />
) : (
[
<DataSourcesActionBar key="action-bar" />,
<OrgActionBar
layoutMode={layoutMode}
searchQuery={searchQuery}
setLayoutMode={mode => setDataSourcesLayoutMode(mode)}
setSearchQuery={query => setDataSourcesSearchQuery(query)}
linkButton={linkButton}
key="action-bar"
/>,
<DataSourcesList dataSources={dataSources} layoutMode={layoutMode} key="list" />,
]
)}
@@ -66,11 +94,14 @@ function mapStateToProps(state) {
dataSources: getDataSources(state.dataSources),
layoutMode: getDataSourcesLayoutMode(state.dataSources),
dataSourcesCount: getDataSourcesCount(state.dataSources),
searchQuery: getDataSourcesSearchQuery(state.dataSources),
};
}
const mapDispatchToProps = {
loadDataSources,
setDataSourcesSearchQuery,
setDataSourcesLayoutMode,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourcesListPage));

View File

@@ -1,31 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import { PluginActionBar, Props } from './PluginActionBar';
import { LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector';
const setup = (propOverrides?: object) => {
const props: Props = {
searchQuery: '',
layoutMode: LayoutModes.Grid,
setLayoutMode: jest.fn(),
setPluginsSearchQuery: jest.fn(),
};
Object.assign(props, propOverrides);
const wrapper = shallow(<PluginActionBar {...props} />);
const instance = wrapper.instance() as PluginActionBar;
return {
wrapper,
instance,
};
};
describe('Render', () => {
it('should render component', () => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -1,62 +0,0 @@
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import LayoutSelector, { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
import { setLayoutMode, setPluginsSearchQuery } from './state/actions';
import { getPluginsSearchQuery, getLayoutMode } from './state/selectors';
export interface Props {
searchQuery: string;
layoutMode: LayoutMode;
setLayoutMode: typeof setLayoutMode;
setPluginsSearchQuery: typeof setPluginsSearchQuery;
}
export class PluginActionBar extends PureComponent<Props> {
onSearchQueryChange = event => {
this.props.setPluginsSearchQuery(event.target.value);
};
render() {
const { searchQuery, layoutMode, setLayoutMode } = this.props;
return (
<div className="page-action-bar">
<div className="gf-form gf-form--grow">
<label className="gf-form--has-input-icon">
<input
type="text"
className="gf-form-input width-20"
value={searchQuery}
onChange={this.onSearchQueryChange}
placeholder="Filter by name or type"
/>
<i className="gf-form-input-icon fa fa-search" />
</label>
<LayoutSelector mode={layoutMode} onLayoutModeChanged={(mode: LayoutMode) => setLayoutMode(mode)} />
</div>
<div className="page-action-bar__spacer" />
<a
className="btn btn-success"
href="https://grafana.com/plugins?utm_source=grafana_plugin_list"
target="_blank"
>
Find more plugins on Grafana.com
</a>
</div>
);
}
}
function mapStateToProps(state) {
return {
searchQuery: getPluginsSearchQuery(state.plugins),
layoutMode: getLayoutMode(state.plugins),
};
}
const mapDispatchToProps = {
setPluginsSearchQuery,
setLayoutMode,
};
export default connect(mapStateToProps, mapDispatchToProps)(PluginActionBar);

View File

@@ -1,20 +1,23 @@
import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import PageHeader from '../../core/components/PageHeader/PageHeader';
import PluginActionBar from './PluginActionBar';
import PageHeader from 'app/core/components/PageHeader/PageHeader';
import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar';
import PluginList from './PluginList';
import { NavModel, Plugin } from '../../types';
import { loadPlugins } from './state/actions';
import { NavModel, Plugin } from 'app/types';
import { loadPlugins, setPluginsLayoutMode, setPluginsSearchQuery } from './state/actions';
import { getNavModel } from '../../core/selectors/navModel';
import { getLayoutMode, getPlugins } from './state/selectors';
import { getLayoutMode, getPlugins, getPluginsSearchQuery } from './state/selectors';
import { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
export interface Props {
navModel: NavModel;
plugins: Plugin[];
layoutMode: LayoutMode;
searchQuery: string;
loadPlugins: typeof loadPlugins;
setPluginsLayoutMoode: typeof setPluginsLayoutMode;
setPluginsSearchQuery: typeof setPluginsSearchQuery;
}
export class PluginListPage extends PureComponent<Props> {
@@ -27,13 +30,23 @@ export class PluginListPage extends PureComponent<Props> {
}
render() {
const { navModel, plugins, layoutMode } = this.props;
const { navModel, plugins, layoutMode, setPluginsLayoutMoode, setPluginsSearchQuery, searchQuery } = this.props;
const linkButton = {
href: 'https://grafana.com/plugins?utm_source=grafana_plugin_list',
title: 'Find more plugins on Grafana.com',
};
return (
<div>
<PageHeader model={navModel} />
<div className="page-container page-body">
<PluginActionBar />
<OrgActionBar
searchQuery={searchQuery}
layoutMode={layoutMode}
setLayoutMode={mode => setPluginsLayoutMoode(mode)}
setSearchQuery={query => setPluginsSearchQuery(query)}
linkButton={linkButton}
/>
{plugins && <PluginList plugins={plugins} layoutMode={layoutMode} />}
</div>
</div>
@@ -46,11 +59,14 @@ function mapStateToProps(state) {
navModel: getNavModel(state.navIndex, 'plugins'),
plugins: getPlugins(state.plugins),
layoutMode: getLayoutMode(state.plugins),
searchQuery: getPluginsSearchQuery(state.plugins),
};
}
const mapDispatchToProps = {
loadPlugins,
setPluginsLayoutMode,
setPluginsSearchQuery,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(PluginListPage));

View File

@@ -24,7 +24,7 @@ export interface SetLayoutModeAction {
payload: LayoutMode;
}
export const setLayoutMode = (mode: LayoutMode): SetLayoutModeAction => ({
export const setPluginsLayoutMode = (mode: LayoutMode): SetLayoutModeAction => ({
type: ActionTypes.SetLayoutMode,
payload: mode,
});