Simplify schema explorer
parent
ccd060f179
commit
716f7e8b4d
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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';
|
Loading…
Reference in New Issue