feat(ui/dataLoaders): Check if fields are required for plugin configuration
parent
69b59fbcb4
commit
eb0a38e727
|
@ -14,6 +14,7 @@ const setup = (override = {}) => {
|
|||
removeTagValue: jest.fn(),
|
||||
autoFocus: true,
|
||||
value: [],
|
||||
helpText: '',
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,15 @@ interface Props {
|
|||
removeTagValue: (item: string, fieldName: string) => void
|
||||
autoFocus: boolean
|
||||
value: string[]
|
||||
helpText: string
|
||||
}
|
||||
|
||||
class ConfigFieldSwitcher extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {fieldName, autoFocus} = this.props
|
||||
const {fieldName, autoFocus, helpText} = this.props
|
||||
|
||||
return (
|
||||
<Form.Element label={fieldName} key={fieldName}>
|
||||
<Form.Element label={fieldName} key={fieldName} helpText={helpText}>
|
||||
<TagInput
|
||||
title={fieldName}
|
||||
autoFocus={autoFocus}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
// Libraries
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import {shallow, mount} from 'enzyme'
|
||||
|
||||
// Components
|
||||
import ConfigFieldSwitcher from 'src/onboarding/components/configureStep/streaming/ConfigFieldSwitcher'
|
||||
import ArrayFormElement from 'src/onboarding/components/configureStep/streaming/ArrayFormElement'
|
||||
import URIFormElement from 'src/shared/components/URIFormElement'
|
||||
import {Input} from 'src/clockface'
|
||||
import {Input, FormElement} from 'src/clockface'
|
||||
|
||||
// Types
|
||||
import {ConfigFieldType} from 'src/types/v2/dataLoaders'
|
||||
|
||||
const setup = (override = {}) => {
|
||||
const setup = (override = {}, shouldMount = false) => {
|
||||
const props = {
|
||||
fieldName: '',
|
||||
fieldType: ConfigFieldType.String,
|
||||
|
@ -20,10 +20,13 @@ const setup = (override = {}) => {
|
|||
removeTagValue: jest.fn(),
|
||||
index: 0,
|
||||
value: '',
|
||||
isRequired: true,
|
||||
...override,
|
||||
}
|
||||
|
||||
const wrapper = shallow(<ConfigFieldSwitcher {...props} />)
|
||||
const wrapper = shouldMount
|
||||
? mount(<ConfigFieldSwitcher {...props} />)
|
||||
: shallow(<ConfigFieldSwitcher {...props} />)
|
||||
|
||||
return {wrapper}
|
||||
}
|
||||
|
@ -40,29 +43,89 @@ describe('Onboarding.Components.ConfigureStep.Streaming.ConfigFieldSwitcher', ()
|
|||
expect(wrapper.exists()).toBe(true)
|
||||
expect(input.exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('if not required', () => {
|
||||
it('optional is displayed as help text', () => {
|
||||
const fieldName = 'yo'
|
||||
const fieldType = ConfigFieldType.String
|
||||
const value = ''
|
||||
const {wrapper} = setup({
|
||||
fieldName,
|
||||
fieldType,
|
||||
isRequired: false,
|
||||
value,
|
||||
})
|
||||
|
||||
const input = wrapper.find(Input)
|
||||
const formElement = wrapper.find(FormElement)
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(input.exists()).toBe(true)
|
||||
expect(formElement.prop('helpText')).toBe('optional')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('if type is array', () => {
|
||||
it('renders an array input', () => {
|
||||
const fieldName = ['yo']
|
||||
const fieldType = ConfigFieldType.StringArray
|
||||
const {wrapper} = setup({fieldName, fieldType})
|
||||
const value = []
|
||||
const {wrapper} = setup({fieldName, fieldType, value}, true)
|
||||
|
||||
const input = wrapper.find(ArrayFormElement)
|
||||
const formElement = wrapper.find(FormElement)
|
||||
|
||||
expect(input.exists()).toBe(true)
|
||||
expect(formElement.prop('helpText')).toBe('')
|
||||
})
|
||||
|
||||
describe('if not required', () => {
|
||||
const fieldName = ['yo']
|
||||
const value = []
|
||||
const fieldType = ConfigFieldType.StringArray
|
||||
const {wrapper} = setup(
|
||||
{fieldName, fieldType, value, isRequired: false},
|
||||
true
|
||||
)
|
||||
|
||||
const input = wrapper.find(ArrayFormElement)
|
||||
const formElement = wrapper.find(FormElement)
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(input.exists()).toBe(true)
|
||||
expect(formElement.prop('helpText')).toBe('optional')
|
||||
})
|
||||
})
|
||||
|
||||
describe('if type is uri', () => {
|
||||
it('renders a uri input ', () => {
|
||||
const fieldName = ['http://google.com']
|
||||
const fieldType = ConfigFieldType.Uri
|
||||
const {wrapper} = setup({fieldName, fieldType})
|
||||
const value = ''
|
||||
const {wrapper} = setup({fieldName, fieldType, value}, true)
|
||||
|
||||
const input = wrapper.find(URIFormElement)
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(input.exists()).toBe(true)
|
||||
})
|
||||
|
||||
describe('if not required', () => {
|
||||
it('optional is displayed as help text', () => {
|
||||
const fieldName = ['http://google.com']
|
||||
const fieldType = ConfigFieldType.Uri
|
||||
const value = ''
|
||||
const {wrapper} = setup(
|
||||
{fieldName, fieldType, value, isRequired: false},
|
||||
true
|
||||
)
|
||||
|
||||
const input = wrapper.find(URIFormElement)
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
expect(input.exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -18,6 +18,7 @@ interface Props {
|
|||
addTagValue: (item: string, fieldName: string) => void
|
||||
removeTagValue: (item: string, fieldName: string) => void
|
||||
value: string | string[]
|
||||
isRequired: boolean
|
||||
}
|
||||
|
||||
class ConfigFieldSwitcher extends PureComponent<Props> {
|
||||
|
@ -33,6 +34,7 @@ class ConfigFieldSwitcher extends PureComponent<Props> {
|
|||
autoFocus={this.autoFocus}
|
||||
onChange={onChange}
|
||||
value={value as string}
|
||||
helpText={this.optionalText}
|
||||
/>
|
||||
)
|
||||
case ConfigFieldType.UriArray:
|
||||
|
@ -44,11 +46,16 @@ class ConfigFieldSwitcher extends PureComponent<Props> {
|
|||
removeTagValue={this.props.removeTagValue}
|
||||
autoFocus={this.autoFocus}
|
||||
value={value as string[]}
|
||||
helpText={this.optionalText}
|
||||
/>
|
||||
)
|
||||
case ConfigFieldType.String:
|
||||
return (
|
||||
<Form.Element label={fieldName} key={fieldName}>
|
||||
<Form.Element
|
||||
label={fieldName}
|
||||
key={fieldName}
|
||||
helpText={this.optionalText}
|
||||
>
|
||||
<Input
|
||||
name={fieldName}
|
||||
autoFocus={this.autoFocus}
|
||||
|
@ -62,6 +69,12 @@ class ConfigFieldSwitcher extends PureComponent<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
private get optionalText(): string {
|
||||
if (!this.props.isRequired) {
|
||||
return 'optional'
|
||||
}
|
||||
}
|
||||
|
||||
private get autoFocus(): boolean {
|
||||
const {index} = this.props
|
||||
return index === 0
|
||||
|
|
|
@ -51,20 +51,23 @@ class PluginConfigForm extends PureComponent<Props> {
|
|||
return <p>No configuration required.</p>
|
||||
}
|
||||
|
||||
return Object.entries(configFields).map(([fieldName, fieldType], i) => {
|
||||
return (
|
||||
<ConfigFieldSwitcher
|
||||
key={fieldName}
|
||||
fieldName={fieldName}
|
||||
fieldType={fieldType}
|
||||
index={i}
|
||||
onChange={this.handleUpdateConfigField}
|
||||
value={this.getFieldValue(telegrafPlugin, fieldName, fieldType)}
|
||||
addTagValue={this.handleAddConfigFieldValue}
|
||||
removeTagValue={this.handleRemoveConfigFieldValue}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return Object.entries(configFields).map(
|
||||
([fieldName, {type: fieldType, isRequired}], i) => {
|
||||
return (
|
||||
<ConfigFieldSwitcher
|
||||
key={fieldName}
|
||||
fieldName={fieldName}
|
||||
fieldType={fieldType}
|
||||
index={i}
|
||||
onChange={this.handleUpdateConfigField}
|
||||
value={this.getFieldValue(telegrafPlugin, fieldName, fieldType)}
|
||||
isRequired={isRequired}
|
||||
addTagValue={this.handleAddConfigFieldValue}
|
||||
removeTagValue={this.handleRemoveConfigFieldValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private handleAddConfigFieldValue = (
|
||||
|
|
|
@ -89,7 +89,12 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputDocker.NameEnum.Docker]: {
|
||||
fields: {endpoint: ConfigFieldType.String},
|
||||
fields: {
|
||||
endpoint: {
|
||||
type: ConfigFieldType.String,
|
||||
isRequired: true,
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputDocker.NameEnum.Docker,
|
||||
type: TelegrafPluginInputDocker.TypeEnum.Input,
|
||||
|
@ -97,7 +102,12 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputFile.NameEnum.File]: {
|
||||
fields: {files: ConfigFieldType.StringArray},
|
||||
fields: {
|
||||
files: {
|
||||
type: ConfigFieldType.StringArray,
|
||||
isRequired: true,
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputFile.NameEnum.File,
|
||||
type: TelegrafPluginInputFile.TypeEnum.Input,
|
||||
|
@ -113,7 +123,12 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputKubernetes.NameEnum.Kubernetes]: {
|
||||
fields: {url: ConfigFieldType.Uri},
|
||||
fields: {
|
||||
url: {
|
||||
type: ConfigFieldType.Uri,
|
||||
isRequired: true,
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputKubernetes.NameEnum.Kubernetes,
|
||||
type: TelegrafPluginInputKubernetes.TypeEnum.Input,
|
||||
|
@ -121,7 +136,7 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputLogParser.NameEnum.Logparser]: {
|
||||
fields: {files: ConfigFieldType.StringArray},
|
||||
fields: {files: {type: ConfigFieldType.StringArray, isRequired: true}},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputLogParser.NameEnum.Logparser,
|
||||
type: TelegrafPluginInputLogParser.TypeEnum.Input,
|
||||
|
@ -169,7 +184,7 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputProcstat.NameEnum.Procstat]: {
|
||||
fields: {exe: ConfigFieldType.String},
|
||||
fields: {exe: {type: ConfigFieldType.String, isRequired: false}},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputProcstat.NameEnum.Procstat,
|
||||
type: TelegrafPluginInputProcstat.TypeEnum.Input,
|
||||
|
@ -177,7 +192,7 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputPrometheus.NameEnum.Prometheus]: {
|
||||
fields: {urls: ConfigFieldType.UriArray},
|
||||
fields: {urls: {type: ConfigFieldType.UriArray, isRequired: true}},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputPrometheus.NameEnum.Prometheus,
|
||||
type: TelegrafPluginInputPrometheus.TypeEnum.Input,
|
||||
|
@ -186,8 +201,8 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
[TelegrafPluginInputRedis.NameEnum.Redis]: {
|
||||
fields: {
|
||||
servers: ConfigFieldType.StringArray,
|
||||
password: ConfigFieldType.String,
|
||||
servers: {type: ConfigFieldType.StringArray, isRequired: true},
|
||||
password: {type: ConfigFieldType.String, isRequired: false},
|
||||
},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputRedis.NameEnum.Redis,
|
||||
|
@ -196,7 +211,7 @@ export const telegrafPluginsInfo: TelegrafPluginInfo = {
|
|||
},
|
||||
},
|
||||
[TelegrafPluginInputSyslog.NameEnum.Syslog]: {
|
||||
fields: {server: ConfigFieldType.String},
|
||||
fields: {server: {type: ConfigFieldType.String, isRequired: true}},
|
||||
defaults: {
|
||||
name: TelegrafPluginInputSyslog.NameEnum.Syslog,
|
||||
type: TelegrafPluginInputSyslog.TypeEnum.Input,
|
||||
|
|
|
@ -189,29 +189,36 @@ export default (state = INITIAL_STATE, action: Action): DataLoadersState => {
|
|||
return {...tp, configured: ConfigurationState.Configured}
|
||||
}
|
||||
|
||||
const plugin = getDeep<Plugin>(tp, 'plugin', createNewPlugin(name))
|
||||
const {config} = plugin
|
||||
const {config} = getDeep<Plugin>(
|
||||
tp,
|
||||
'plugin',
|
||||
createNewPlugin(name)
|
||||
)
|
||||
|
||||
let isValidConfig = true
|
||||
|
||||
Object.entries(configFields).forEach(configField => {
|
||||
const [fieldName, fieldType] = configField
|
||||
const fieldValue = config[fieldName]
|
||||
Object.entries(configFields).forEach(
|
||||
([fieldName, {type: fieldType, isRequired}]) => {
|
||||
if (isRequired) {
|
||||
const fieldValue = config[fieldName]
|
||||
|
||||
const isValidUri =
|
||||
fieldType === ConfigFieldType.Uri &&
|
||||
validateURI(fieldValue as string)
|
||||
const isValidString =
|
||||
fieldType === ConfigFieldType.String &&
|
||||
(fieldValue as string) !== ''
|
||||
const isValidArray =
|
||||
(fieldType === ConfigFieldType.StringArray ||
|
||||
fieldType === ConfigFieldType.UriArray) &&
|
||||
(fieldValue as string[]).length
|
||||
const isValidUri =
|
||||
fieldType === ConfigFieldType.Uri &&
|
||||
validateURI(fieldValue as string)
|
||||
const isValidString =
|
||||
fieldType === ConfigFieldType.String &&
|
||||
(fieldValue as string) !== ''
|
||||
const isValidArray =
|
||||
(fieldType === ConfigFieldType.StringArray ||
|
||||
fieldType === ConfigFieldType.UriArray) &&
|
||||
(fieldValue as string[]).length
|
||||
|
||||
if (!isValidUri && !isValidString && !isValidArray) {
|
||||
isValidConfig = false
|
||||
if (!isValidUri && !isValidString && !isValidArray) {
|
||||
isValidConfig = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
if (!isValidConfig || _.isEmpty(config)) {
|
||||
return {...tp, configured: ConfigurationState.Unconfigured}
|
||||
|
|
|
@ -11,6 +11,7 @@ const setup = (override = {}) => {
|
|||
name: '',
|
||||
value: '',
|
||||
onChange: jest.fn(),
|
||||
helpText: '',
|
||||
...override,
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ interface Props {
|
|||
name: string
|
||||
autoFocus?: boolean
|
||||
value: string
|
||||
helpText: string
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
||||
|
@ -37,10 +38,15 @@ class URIFormElement extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {name, value, autoFocus} = this.props
|
||||
const {name, value, autoFocus, helpText} = this.props
|
||||
|
||||
return (
|
||||
<FormElement label={name} key={name} errorMessage={this.errorMessage}>
|
||||
<FormElement
|
||||
label={name}
|
||||
key={name}
|
||||
errorMessage={this.errorMessage}
|
||||
helpText={helpText}
|
||||
>
|
||||
<Input
|
||||
name={name}
|
||||
autoFocus={autoFocus}
|
||||
|
|
|
@ -174,9 +174,15 @@ export enum ConfigFieldType {
|
|||
}
|
||||
|
||||
export interface ConfigFields {
|
||||
[field: string]: ConfigFieldType
|
||||
[field: string]: {
|
||||
type: ConfigFieldType
|
||||
isRequired: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface TelegrafPluginInfo {
|
||||
[name: string]: {fields: ConfigFields; defaults: Plugin}
|
||||
[name: string]: {
|
||||
fields: ConfigFields
|
||||
defaults: Plugin
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue