Commit 1bad8db9 by Torkel Ödegaard

data source picker demo state

parent a7daf58b
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import _ from 'lodash';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { DataSourceSelectItem } from 'app/types';
interface Props {}
interface State {
datasources: DataSourceSelectItem[];
searchQuery: string;
}
export class DataSourcePicker extends PureComponent<Props, State> {
searchInput: HTMLElement;
constructor(props) {
super(props);
this.state = {
datasources: getDatasourceSrv().getMetricSources(),
searchQuery: '',
};
}
getDataSources() {
const { datasources, searchQuery } = this.state;
const regex = new RegExp(searchQuery, 'i');
const filtered = datasources.filter(item => {
return regex.test(item.name) || regex.test(item.meta.name);
});
return _.sortBy(filtered, 'sort');
}
renderDataSource = (ds: DataSourceSelectItem, index) => {
const cssClass = classNames({
'ds-picker-list__item': true,
});
return (
<div key={index} className={cssClass} title={ds.name}>
<img className="ds-picker-list__img" src={ds.meta.info.logos.small} />
<div className="ds-picker-list__name">{ds.name}</div>
</div>
);
};
componentDidMount() {
setTimeout(() => {
this.searchInput.focus();
}, 300);
}
renderFilters() {
return (
<>
<label className="gf-form--has-input-icon">
<input
type="text"
className="gf-form-input width-13"
placeholder=""
ref={elem => (this.searchInput = elem)}
/>
<i className="gf-form-input-icon fa fa-search" />
</label>
<div className="p-l-1">
<button className="btn toggle-btn gf-form-btn active">All</button>
<button className="btn toggle-btn gf-form-btn">Favorites</button>
</div>
</>
);
}
render() {
return (
<>
<div className="cta-form__bar">
<div className="cta-form__bar-header">Select data source</div>
{this.renderFilters()}
<div className="gf-form--grow" />
</div>
<div className="ds-picker-list">{this.getDataSources().map(this.renderDataSource)}</div>
</>
);
}
}
......@@ -3,15 +3,15 @@ import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar
import { FadeIn } from 'app/core/components/Animations/FadeIn';
interface Props {
selectedText?: string;
selectedImage?: string;
children: JSX.Element;
main: EditorToolBarView;
toolbarItems: EditorToolBarView[];
}
export interface EditorToolBarView {
title: string;
imgSrc: string;
imgSrc?: string;
icon?: string;
render: () => JSX.Element;
}
......@@ -32,22 +32,32 @@ export class EditorTabBody extends PureComponent<Props, State> {
this.setState({
openView: item === this.state.openView ? null : item,
});
}
};
onCloseOpenView = () => {
this.setState({ openView: null });
}
};
renderToolBarViewToggle(item: EditorToolBarView) {
renderMainSelection(view: EditorToolBarView) {
return (
<div className="edit-section__selected" onClick={() => this.onToggleToolBarView(item)} key={item.title}>
<img className="edit-section__selected-image" src={item.imgSrc} />
<div className="edit-section__selected-name">{item.title}</div>
<div className="edit-section__selected" onClick={() => this.onToggleToolBarView(view)} key={view.title}>
<img className="edit-section__selected-image" src={view.imgSrc} />
<div className="edit-section__selected-name">{view.title}</div>
<i className="fa fa-caret-down" />
</div>
);
}
renderButton(view: EditorToolBarView) {
return (
<div className="nav-buttons" key={view.title}>
<button className="btn navbar-button">
<i className={view.icon} /> {view.title}
</button>
</div>
);
}
renderOpenView(view: EditorToolBarView) {
return (
<div className="editor-toolbar-view">
......@@ -60,25 +70,29 @@ export class EditorTabBody extends PureComponent<Props, State> {
}
render() {
const { children, toolbarItems} = this.props;
const { children, toolbarItems, main } = this.props;
const { openView } = this.state;
return (
<>
<div className="edit-section">
<div className="edit-section__header">{toolbarItems.map(item => this.renderToolBarViewToggle(item))}</div>
</div>
<div className="panel-editor__scroll">
<CustomScrollbar>
<div className="panel-editor__content">
<FadeIn in={openView !== null} duration={300}>
{openView && this.renderOpenView(openView)}
</FadeIn>
{children}
<div className="edit-section">
<div className="edit-section__header">
{this.renderMainSelection(main)}
<div className="gf-form--grow" />
{toolbarItems.map(item => this.renderButton(item))}
</div>
</CustomScrollbar>
</div>
</div>
<div className="panel-editor__scroll">
<CustomScrollbar>
<div className="panel-editor__content">
<FadeIn in={openView !== null} duration={200}>
{openView && this.renderOpenView(openView)}
</FadeIn>
{children}
</div>
</CustomScrollbar>
</div>
</>
);
);
}
}
// Libraries
import React, { PureComponent } from 'react';
// Services & utils
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { EditorTabBody } from './EditorTabBody';
import { DataSourcePicker } from './DataSourcePicker';
// Types
import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model';
......@@ -52,15 +50,23 @@ export class QueriesTab extends PureComponent<Props> {
const currentDataSource = {
title: 'ProductionDB',
imgSrc: 'public/app/plugins/datasource/prometheus/img/prometheus_logo.svg',
render: () => {
return (
<h2>Hello</h2>
);
},
render: () => <DataSourcePicker />,
};
const queryInspector = {
title: 'Query Inspector',
icon: 'fa fa-lightbulb-o',
render: () => <h2>hello</h2>,
};
const dsHelp = {
title: 'Help',
icon: 'fa fa-question',
render: () => <h2>hello</h2>,
};
return (
<EditorTabBody toolbarItems={[currentDataSource]}>
<EditorTabBody main={currentDataSource} toolbarItems={[dsHelp, queryInspector]}>
<div ref={element => (this.element = element)} style={{ width: '100%' }} />
</EditorTabBody>
);
......
......@@ -15,7 +15,6 @@ interface Props {
}
export class VisualizationTab extends PureComponent<Props> {
constructor(props) {
super(props);
}
......@@ -37,7 +36,7 @@ export class VisualizationTab extends PureComponent<Props> {
};
render() {
const {plugin, onTypeChanged} = this.props;
const { plugin, onTypeChanged } = this.props;
const panelSelection = {
title: plugin.name,
......@@ -48,7 +47,7 @@ export class VisualizationTab extends PureComponent<Props> {
};
return (
<EditorTabBody toolbarItems={[panelSelection]}>
<EditorTabBody main={panelSelection} toolbarItems={[]}>
{this.renderPanelOptions()}
</EditorTabBody>
);
......
......@@ -15,6 +15,8 @@ interface State {
}
export class VizTypePicker extends PureComponent<Props, State> {
searchInput: HTMLElement;
constructor(props) {
super(props);
......@@ -47,11 +49,22 @@ export class VizTypePicker extends PureComponent<Props, State> {
);
};
componentDidMount() {
setTimeout(() => {
this.searchInput.focus();
}, 300);
}
renderFilters() {
return (
<>
<label className="gf-form--has-input-icon">
<input type="text" className="gf-form-input width-13" placeholder="" />
<input
type="text"
className="gf-form-input width-13"
placeholder=""
ref={elem => (this.searchInput = elem)}
/>
<i className="gf-form-input-icon fa fa-search" />
</label>
<div className="p-l-1">
......@@ -63,7 +76,6 @@ export class VizTypePicker extends PureComponent<Props, State> {
}
render() {
const { current } = this.props;
const { pluginList } = this.state;
return (
......
// Libraries
import _ from 'lodash';
import coreModule from 'app/core/core_module';
// Utils
import config from 'app/core/config';
import { importPluginModule } from './plugin_loader';
// Types
import { DataSourceApi } from 'app/types/series';
import { DataSource } from 'app/types';
import { DataSource, DataSourceSelectItem } from 'app/types';
export class DatasourceSrv {
datasources: { [name: string]: DataSource };
......@@ -102,8 +99,8 @@ export class DatasourceSrv {
return _.sortBy(es, ['name']);
}
getMetricSources(options) {
const metricSources = [];
getMetricSources(options?) {
const metricSources: DataSourceSelectItem[] = [];
_.each(config.datasources, (value, key) => {
if (value.meta && value.meta.metrics) {
......
......@@ -22,6 +22,13 @@ export interface DataSource {
testDatasource?: () => Promise<any>;
}
export interface DataSourceSelectItem {
name: string;
value: string | null;
meta: PluginMeta;
sort: string;
}
export interface DataSourcesState {
dataSources: DataSource[];
searchQuery: string;
......
......@@ -7,7 +7,7 @@ import { DashboardState } from './dashboard';
import { DashboardAcl, OrgRole, PermissionLevel } from './acl';
import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
import { Invitee, OrgUser, User, UsersState, UserState } from './user';
import { DataSource, DataSourcesState } from './datasources';
import { DataSource, DataSourceSelectItem, DataSourcesState } from './datasources';
import {
TimeRange,
LoadingState,
......@@ -55,6 +55,7 @@ export {
OrgRole,
PermissionLevel,
DataSource,
DataSourceSelectItem,
PluginMeta,
ApiKey,
ApiKeysState,
......
......@@ -53,6 +53,7 @@
background-image: linear-gradient(to right, #ffd500 0%, #ff4400 99%, #ff4400 100%);
}
}
&.active--panel {
background: $panel-bg !important;
}
......
......@@ -53,10 +53,6 @@
}
}
.viz-picker__search {
flex-grow: 0;
}
.viz-picker {
margin-bottom: $spacer;
}
......@@ -64,7 +60,6 @@
.viz-picker__items {
display: flex;
flex-wrap: wrap;
// for scrollbar
margin-bottom: 13px;
}
......@@ -192,7 +187,7 @@
border-radius: $input-border-radius;
display: flex;
align-items: center;
.fa {
.fa {
margin-left: 20px;
display: inline-block;
position: relative;
......@@ -247,6 +242,7 @@
background-color: $empty-list-cta-bg;
border-top: 3px solid $orange;
margin: 0 100px;
margin-bottom: 20px;
}
.editor-toolbar-view__close {
......@@ -254,8 +250,8 @@
padding: 4px 8px 4px 9px;
border: none;
position: absolute;
right: 0;
top: -2px;
right: 9px;
top: 7px;
font-size: $font-size-md;
&:hover {
......@@ -263,3 +259,43 @@
}
}
.ds-picker-list {
display: flex;
flex-wrap: wrap;
margin-bottom: 13px;
flex-direction: column;
}
.ds-picker-list__item {
background: $card-background;
box-shadow: $card-shadow;
border-radius: 3px;
display: flex;
cursor: pointer;
margin-bottom: 3px;
padding: 5px 15px;
align-items: center;
&:hover {
background: $card-background-hover;
}
&--selected {
.ds-picker-list__name {
color: $text-color;
}
}
}
.ds-picker-list__name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: $font-size-md;
padding-left: 15px;
}
.ds-picker-list__img {
width: 30px;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment