Merge pull request from influxdata/feat(tempvars)/variables-list

Add ability to create a new template variable
pull/11894/head
Alirie Gray 2019-02-13 22:28:49 -08:00 committed by GitHub
commit dcfab169c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 185 additions and 23 deletions

View File

@ -124,10 +124,6 @@ func (m *Macro) Valid() error {
return fmt.Errorf("invalid arguments type")
}
if len(m.Selected) == 0 {
return fmt.Errorf("no selected values")
}
return nil
}

3
package-lock.json generated Normal file
View File

@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

6
ui/package-lock.json generated
View File

@ -838,9 +838,9 @@
}
},
"@influxdata/influx": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.5.tgz",
"integrity": "sha512-K5arbttAaGIC3iuW5OcJxmy8+qtLRD9pfIoS7NtbN7PUL+NDIzIK7tMrUcvAIPPBREDc4W/lNuicoy79ukMhkw==",
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@influxdata/influx/-/influx-0.2.9.tgz",
"integrity": "sha512-hS+FRtHH+zUVMRGDrlkUQaFUpbrKZUqE0zMD5TIPoYbK9dgKLcOF1pT36btzV2BsDNhwXD2SCHuXimzLaD2koQ==",
"requires": {
"axios": "^0.18.0"
}

View File

@ -117,7 +117,7 @@
},
"dependencies": {
"@influxdata/clockface": "0.0.2",
"@influxdata/influx": "^0.2.3",
"@influxdata/influx": "^0.2.9",
"@influxdata/react-custom-scrollbars": "4.3.8",
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",

View File

@ -19,9 +19,13 @@ import {
import {Button} from '@influxdata/clockface'
import FluxEditor from 'src/shared/components/FluxEditor'
// Types
import {Macro} from '@influxdata/influx'
interface Props {
onCreateVariable: () => void
onCreateVariable: (variable: Macro) => Promise<void>
onCloseModal: () => void
orgID: string
}
interface State {
@ -88,7 +92,7 @@ export default class CreateOrgOverlay extends PureComponent<Props, State> {
<Button
text="Create"
type={ButtonType.Submit}
onClick={this.handleCreateVariable}
onClick={this.handleSubmit}
color={ComponentColor.Primary}
/>
</OverlayFooter>
@ -98,8 +102,17 @@ export default class CreateOrgOverlay extends PureComponent<Props, State> {
)
}
private handleCreateVariable = () => {
this.props.onCloseModal()
private handleSubmit = (): void => {
const {onCreateVariable, orgID} = this.props
onCreateVariable({
name: this.state.name,
orgID,
arguments: {
type: 'query',
values: {query: this.state.script, language: 'flux'},
},
})
}
private handleChangeInput = (e: ChangeEvent<HTMLInputElement>) => {

View File

@ -0,0 +1,26 @@
// Libraries
import React, {PureComponent} from 'react'
// Components
import {IndexList, Alignment} from 'src/clockface'
// Types
import {Macro} from '@influxdata/influx'
interface Props {
variable: Macro
}
export default class VariableRow extends PureComponent<Props> {
public render() {
const {variable} = this.props
return (
<IndexList.Row>
<IndexList.Cell alignment={Alignment.Left}>
{variable.name}
</IndexList.Cell>
<IndexList.Cell alignment={Alignment.Left}>{'Query'}</IndexList.Cell>
</IndexList.Row>
)
}
}

View File

@ -5,13 +5,28 @@ import _ from 'lodash'
// Components
import TabbedPageHeader from 'src/shared/components/tabbed_page/TabbedPageHeader'
import CreateVariableOverlay from 'src/organizations/components/CreateVariableOverlay'
import {Button} from '@influxdata/clockface'
import {Input, ComponentColor, IconFont, OverlayTechnology} from 'src/clockface'
import {Button, ComponentSize} from '@influxdata/clockface'
import VariablesList from 'src/organizations/components/VariablesList'
import {
Input,
ComponentColor,
IconFont,
OverlayTechnology,
EmptyState,
} from 'src/clockface'
import FilterList from 'src/shared/components/Filter'
// Types
import {OverlayState} from 'src/types'
import {client} from 'src/utils/api'
import {Macro} from '@influxdata/influx'
interface Props {}
interface Props {
onChange: () => void
variables: Macro[]
orgName: string
orgID: string
}
interface State {
searchTerm: string
@ -28,6 +43,7 @@ export default class Variables extends PureComponent<Props, State> {
}
public render() {
const {variables, orgID} = this.props
const {searchTerm, overlayState} = this.state
return (
@ -48,10 +64,20 @@ export default class Variables extends PureComponent<Props, State> {
onClick={this.handleOpenModal}
/>
</TabbedPageHeader>
<FilterList<Macro>
searchTerm={searchTerm}
searchKeys={['name', 'ruleString']}
list={variables}
>
{variables => (
<VariablesList variables={variables} emptyState={this.emptyState} />
)}
</FilterList>
<OverlayTechnology visible={overlayState === OverlayState.Open}>
<CreateVariableOverlay
onCreateVariable={this.handleCreateVariable}
onCloseModal={this.handleCloseModal}
orgID={orgID}
/>
</OverlayTechnology>
</>
@ -73,5 +99,37 @@ export default class Variables extends PureComponent<Props, State> {
this.setState({overlayState: OverlayState.Closed})
}
private handleCreateVariable() {}
private handleCreateVariable = async (variable: Macro) => {
await client.variables.create(variable)
this.props.onChange()
this.handleCloseModal()
}
private get emptyState(): JSX.Element {
const {orgName} = this.props
const {searchTerm} = this.state
if (_.isEmpty(searchTerm)) {
return (
<EmptyState size={ComponentSize.Medium}>
<EmptyState.Text
text={`${orgName} does not own any Variables , why not create one?`}
highlightWords={['Buckets']}
/>
<Button
text="Create Variable"
icon={IconFont.Plus}
color={ComponentColor.Primary}
onClick={this.handleOpenModal}
/>
</EmptyState>
)
}
return (
<EmptyState size={ComponentSize.Medium}>
<EmptyState.Text text="No Variables match your query" />
</EmptyState>
)
}
}

View File

@ -0,0 +1,42 @@
// Libraries
import React, {PureComponent} from 'react'
// Components
import {IndexList} from 'src/clockface'
import VariableRow from 'src/organizations/components/VariableRow'
// Types
import {Macro} from '@influxdata/influx'
interface Props {
variables: Macro[]
emptyState: JSX.Element
}
class VariablesList extends PureComponent<Props> {
constructor(props) {
super(props)
}
public render() {
const {emptyState, variables} = this.props
return (
<>
<IndexList>
<IndexList.Header>
<IndexList.HeaderCell columnName="Name" width="60%" />
<IndexList.HeaderCell columnName="Type" width="40%" />
</IndexList.Header>
<IndexList.Body columnCount={3} emptyState={emptyState}>
{variables.map(variable => (
<VariableRow key={variable.id} variable={variable} />
))}
</IndexList.Body>
</IndexList>
</>
)
}
}
export default VariablesList

View File

@ -26,7 +26,7 @@ import * as NotificationsActions from 'src/types/actions/notifications'
import * as notifyActions from 'src/shared/actions/notifications'
const getBuckets = async (org: Organization) => {
return client.buckets.getAllByOrg(org)
return client.buckets.getAllByOrg(org.name)
}
interface RouterProps {

View File

@ -11,12 +11,16 @@ const getCollectors = async (org: Organization) => {
return client.telegrafConfigs.getAllByOrg(org)
}
const getScrapers = async () => {
const getScrapers = async (): Promise<ScraperTargetResponse[]> => {
return await client.scrapers.getAll()
}
const getBuckets = async (org: Organization) => {
return client.buckets.getAllByOrg(org)
const getBuckets = async (org: Organization): Promise<Bucket[]> => {
return client.buckets.getAllByOrg(org.name)
}
const getVariables = async (org: Organization): Promise<Macro[]> => {
return await client.variables.getAllByOrg(org.name)
}
// Actions
@ -44,6 +48,7 @@ import {
ScraperTargetResponse,
} from '@influxdata/influx'
import * as NotificationsActions from 'src/types/actions/notifications'
import {Macro} from '@influxdata/influx'
// Decorators
import {ErrorHandling} from 'src/shared/decorators/errors'
@ -54,7 +59,7 @@ interface StateProps {
}
const getTasks = async (org: Organization): Promise<Task[]> => {
const tasks = await client.tasks.getAllByOrg(org)
const tasks = await client.tasks.getAllByOrg(org.name)
const mappedTasks = tasks.map(task => {
return {
...task,
@ -188,7 +193,26 @@ class OrganizationView extends PureComponent<Props> {
url="variables_tab"
title="Variables"
>
<Variables />
<GetOrgResources<Macro[]>
organization={org}
fetcher={getVariables}
>
{(variables, loading, fetch) => {
return (
<SpinnerContainer
loading={loading}
spinnerComponent={<TechnoSpinner />}
>
<Variables
onChange={fetch}
variables={variables}
orgName={org.name}
orgID={org.id}
/>
</SpinnerContainer>
)
}}
</GetOrgResources>
</TabbedPageSection>
</OrganizationTabs>
</div>

View File

@ -46,7 +46,7 @@ interface State {
schedule: TaskSchedule
}
const getBuckets = (org: Organization) => client.buckets.getAllByOrg(org)
const getBuckets = (org: Organization) => client.buckets.getAllByOrg(org.name)
export default class TaskForm extends PureComponent<Props, State> {
public static defaultProps: Partial<Props> = {