Simplify schema explorer

pull/10616/head
Andrew Watkins 2018-05-04 11:31:27 -07:00
parent ccd060f179
commit 716f7e8b4d
8 changed files with 78 additions and 288 deletions

View File

@ -46,3 +46,25 @@ export const getDatabases = async () => {
throw error throw error
} }
} }
export const getTags = async () => {
try {
const response = {data: {tags: ['tk1', 'tk2', 'tk3']}}
const {data} = await Promise.resolve(response)
return data.tags
} catch (error) {
console.error('Could not get tagKeys', error)
throw error
}
}
export const getTagValues = async () => {
try {
const response = {data: {values: ['tv1', 'tv2', 'tv3']}}
const {data} = await Promise.resolve(response)
return data.values
} catch (error) {
console.error('Could not get tagKeys', error)
throw error
}
}

View File

@ -1,34 +1,36 @@
import React, {PureComponent} from 'react' import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash' import _ from 'lodash'
import DatabaseListItem from 'src/ifql/components/DatabaseListItem' import DatabaseListItem from 'src/ifql/components/DatabaseListItem'
import MeasurementList from 'src/ifql/components/MeasurementList'
import {Source} from 'src/types'
import {showDatabases} from 'src/shared/apis/metaQuery' import {showDatabases} from 'src/shared/apis/metaQuery'
import showDatabasesParser from 'src/shared/parsing/showDatabases' import showDatabasesParser from 'src/shared/parsing/showDatabases'
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
interface DatabaseListProps {
db: string
source: Source
onChooseDatabase: (database: string) => void
}
interface DatabaseListState { interface DatabaseListState {
databases: string[] databases: string[]
measurement: string measurement: string
db: string
} }
const {shape} = PropTypes
@ErrorHandling @ErrorHandling
class DatabaseList extends PureComponent<DatabaseListProps, DatabaseListState> { class DatabaseList extends PureComponent<{}, DatabaseListState> {
public static contextTypes = {
source: shape({
links: shape({}).isRequired,
}).isRequired,
}
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
databases: [], databases: [],
measurement: '', measurement: '',
db: '',
} }
} }
@ -37,7 +39,7 @@ class DatabaseList extends PureComponent<DatabaseListProps, DatabaseListState> {
} }
public async getDatabases() { public async getDatabases() {
const {source} = this.props const {source} = this.context
try { try {
const {data} = await showDatabases(source.links.proxy) const {data} = await showDatabases(source.links.proxy)
@ -46,34 +48,31 @@ class DatabaseList extends PureComponent<DatabaseListProps, DatabaseListState> {
this.setState({databases: sorted}) this.setState({databases: sorted})
const db = _.get(sorted, '0', '') const db = _.get(sorted, '0', '')
this.props.onChooseDatabase(db) this.handleChooseDatabase(db)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
} }
public render() { public render() {
const {onChooseDatabase} = this.props
return ( return (
<div className="query-builder--column query-builder--column-db"> <div className="ifql-schema-tree">
<div className="query-builder--list"> {this.state.databases.map(db => {
{this.state.databases.map(db => { return (
return ( <DatabaseListItem
<React.Fragment key={db}> db={db}
<DatabaseListItem key={db}
db={db} onChooseDatabase={this.handleChooseDatabase}
isActive={this.props.db === db} />
onChooseDatabase={onChooseDatabase} )
/> })}
{this.props.db === db && <MeasurementList db={db} />}
</React.Fragment>
)
})}
</div>
</div> </div>
) )
} }
private handleChooseDatabase = (db: string): void => {
this.setState({db})
}
} }
export default DatabaseList export default DatabaseList

View File

@ -2,17 +2,22 @@ import React, {PureComponent} from 'react'
import classnames from 'classnames' import classnames from 'classnames'
export interface Props { import TagList from 'src/ifql/components/TagList'
isActive: boolean
interface Props {
db: string db: string
onChooseDatabase: (db: string) => void onChooseDatabase: (db: string) => void
} }
class DatabaseListItem extends PureComponent<Props> { interface State {
isOpen: boolean
}
class DatabaseListItem extends PureComponent<Props, State> {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
measurement: '', isOpen: false,
} }
} }
@ -21,23 +26,23 @@ class DatabaseListItem extends PureComponent<Props> {
return ( return (
<div className={this.className} onClick={this.handleChooseDatabase}> <div className={this.className} onClick={this.handleChooseDatabase}>
<span> <div className="ifql-schema-item">
<div className="query-builder--caret icon caret-right" /> <div className="icon caret-right" />
{db} {db}
</span> </div>
{this.state.isOpen && <TagList db={db} />}
</div> </div>
) )
} }
private get className(): string { private get className(): string {
return classnames('query-builder--list-item', { return classnames('ifql-schema-tree', {
active: this.props.isActive, expanded: this.state.isOpen,
}) })
} }
private handleChooseDatabase = () => { private handleChooseDatabase = () => {
const {onChooseDatabase, db} = this.props this.setState({isOpen: !this.state.isOpen})
onChooseDatabase(db)
} }
} }

View File

@ -1,125 +0,0 @@
import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import {showMeasurements} from 'src/shared/apis/metaQuery'
import showMeasurementsParser from 'src/shared/parsing/showMeasurements'
import MeasurementListFilter from 'src/shared/components/MeasurementListFilter'
import MeasurementListItem from 'src/ifql/components/MeasurementListItem'
import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
db: string
}
interface State {
measurements: string[]
filterText: string
filtered: string[]
selected: string
}
const {shape} = PropTypes
@ErrorHandling
class MeasurementList extends PureComponent<Props, State> {
public static contextTypes = {
source: shape({
links: shape({}).isRequired,
}).isRequired,
}
constructor(props) {
super(props)
this.state = {
filterText: '',
filtered: [],
measurements: [],
selected: '',
}
}
public componentDidMount() {
if (!this.props.db) {
return
}
this.getMeasurements()
}
public render() {
const {filtered} = this.state
return (
<div className="query-builder--column">
<div className="query-builder--heading">
<span>Measurements & Tags</span>
<MeasurementListFilter
onEscape={this.handleEscape}
onFilterText={this.handleFilterText}
filterText={this.state.filterText}
/>
</div>
<div className="query-builder--sub-list">
{filtered.map(measurement => (
<MeasurementListItem
key={measurement}
db={this.props.db}
measurement={measurement}
selected={this.state.selected}
onChooseMeasurement={this.handleChooseMeasurement}
/>
))}
</div>
</div>
)
}
private async getMeasurements() {
const {source} = this.context
const {db} = this.props
try {
const {data} = await showMeasurements(source.links.proxy, db)
const {measurementSets} = showMeasurementsParser(data)
const measurements = measurementSets[0].measurements
const selected = measurements[0]
this.setState({measurements, filtered: measurements, selected})
} catch (err) {
console.error(err)
}
}
private handleChooseMeasurement = (selected: string): void => {
this.setState({selected})
}
private handleFilterText = e => {
e.stopPropagation()
const filterText = e.target.value
this.setState({
filterText,
filtered: this.handleFilterMeasuremet(filterText),
})
}
private handleFilterMeasuremet = filter => {
return this.state.measurements.filter(m =>
m.toLowerCase().includes(filter.toLowerCase())
)
}
private handleEscape = e => {
if (e.key !== 'Escape') {
return
}
e.stopPropagation()
this.setState({
filterText: '',
})
}
}
export default MeasurementList

View File

@ -1,50 +0,0 @@
import React, {PureComponent} from 'react'
import {ErrorHandling} from 'src/shared/decorators/errors'
import TagList from 'src/ifql/components/TagList'
interface Props {
db: string
selected: string
measurement: string
onChooseMeasurement: (measurement: string) => void
}
interface State {
isOpen: boolean
}
@ErrorHandling
class MeasurementListItem extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {isOpen: false}
}
public render() {
const {measurement, db} = this.props
return (
<div key={measurement} onClick={this.handleClick}>
<div className="query-builder--list-item">
<span>
<div className="query-builder--caret icon caret-right" />
{measurement}
</span>
</div>
{this.shouldShow && <TagList db={db} measurement={measurement} />}
</div>
)
}
private handleClick = () => {
const {measurement, onChooseMeasurement} = this.props
onChooseMeasurement(measurement)
}
private get shouldShow(): boolean {
return this.state.isOpen
}
}
export default MeasurementListItem

View File

@ -1,42 +1,14 @@
import React, {PureComponent} from 'react' import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import DatabaseList from 'src/ifql/components/DatabaseList' import DatabaseList from 'src/ifql/components/DatabaseList'
interface State { class SchemaExplorer extends PureComponent {
db: string
}
const {shape} = PropTypes
class SchemaExplorer extends PureComponent<{}, State> {
public static contextTypes = {
source: shape({
links: shape({}).isRequired,
}).isRequired,
}
constructor(props) {
super(props)
this.state = {
db: '',
}
}
public render() { public render() {
return ( return (
<div className="ifql-schema-explorer"> <div className="ifql-schema-explorer">
<DatabaseList <DatabaseList />
db={this.state.db}
source={this.context.source}
onChooseDatabase={this.handleChooseDatabase}
/>
</div> </div>
) )
} }
private handleChooseDatabase = (db: string): void => {
this.setState({db})
}
} }
export default SchemaExplorer export default SchemaExplorer

View File

@ -5,16 +5,13 @@ import _ from 'lodash'
import TagListItem from 'src/ifql/components/TagListItem' import TagListItem from 'src/ifql/components/TagListItem'
import {showTagKeys, showTagValues} from 'src/shared/apis/metaQuery' import {getTags, getTagValues} from 'src/ifql/apis'
import showTagKeysParser from 'src/shared/parsing/showTagKeys'
import showTagValuesParser from 'src/shared/parsing/showTagValues'
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
const {shape} = PropTypes const {shape} = PropTypes
interface Props { interface Props {
db: string db: string
measurement: string
} }
interface State { interface State {
@ -39,24 +36,8 @@ class TagList extends PureComponent<Props, State> {
} }
public componentDidMount() { public componentDidMount() {
const {db, measurement} = this.props const {db} = this.props
if (!db || !measurement) { if (!db) {
return
}
this.getTags()
}
public componentDidUpdate(prevProps) {
const {db, measurement} = this.props
const {db: prevDB, measurement: prevMeas} = prevProps
if (!db || !measurement) {
return
}
if (db === prevDB && measurement === prevMeas) {
return return
} }
@ -64,29 +45,14 @@ class TagList extends PureComponent<Props, State> {
} }
public async getTags() { public async getTags() {
const {db, measurement} = this.props const keys = await getTags()
const {source} = this.context const values = await getTagValues()
const {data} = await showTagKeys({ const tags = keys.map(k => {
database: db, return (this.state.tags[k] = values)
measurement,
retentionPolicy: 'autogen',
source: source.links.proxy,
})
const {tagKeys} = showTagKeysParser(data)
const response = await showTagValues({
database: db,
measurement,
retentionPolicy: 'autogen',
source: source.links.proxy,
tagKeys,
}) })
const {tags} = showTagValuesParser(response.data) this.setState({tags})
const selected = Object.keys(tags)
this.setState({tags, selectedTag: selected[0]})
} }
public render() { public render() {

View File

@ -5,5 +5,6 @@
@import '../components/time-machine/ifql-editor'; @import '../components/time-machine/ifql-editor';
@import '../components/time-machine/ifql-builder'; @import '../components/time-machine/ifql-builder';
// @import '../components/time-machine/ifql-explorer';
@import '../components/time-machine/visualization'; @import '../components/time-machine/visualization';
@import '../components/time-machine/add-func-button'; @import '../components/time-machine/add-func-button';