-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes remaining bugs with multi slack handlers #3482
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,21 +27,24 @@ const HandlerTabs: SFC<Props> = ({ | |
}) => | ||
handlersOnThisAlert.length ? ( | ||
<ul className="endpoint-tabs"> | ||
{handlersOnThisAlert.map(ep => ( | ||
<li | ||
key={uuid.v4()} | ||
className={classnames('endpoint-tab', { | ||
active: ep.alias === (selectedHandler && selectedHandler.alias), | ||
})} | ||
onClick={handleChooseHandler(ep)} | ||
> | ||
{ep.text} | ||
<button | ||
className="endpoint-tab--delete" | ||
onClick={handleRemoveHandler(ep)} | ||
/> | ||
</li> | ||
))} | ||
{handlersOnThisAlert.map(endpoint => { | ||
return ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. word. i'm preferring this, much like getting rid of ternaries. |
||
<li | ||
key={uuid.v4()} | ||
className={classnames('endpoint-tab', { | ||
active: | ||
endpoint.alias === (selectedHandler && selectedHandler.alias), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i appreciate this clarification of the var name. |
||
})} | ||
onClick={handleChooseHandler(endpoint)} | ||
> | ||
{endpoint.text} | ||
<button | ||
className="endpoint-tab--delete" | ||
onClick={handleRemoveHandler(endpoint)} | ||
/> | ||
</li> | ||
) | ||
})} | ||
</ul> | ||
) : null | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,14 @@ import RedactedInput from 'src/kapacitor/components/config/RedactedInput' | |
import {ErrorHandling} from 'src/shared/decorators/errors' | ||
import {SlackProperties} from 'src/types/kapacitor' | ||
|
||
interface Options { | ||
url: boolean | ||
channel: string | ||
workspace: string | ||
} | ||
|
||
interface Config { | ||
options: { | ||
url: boolean | ||
channel: string | ||
workspace: string | ||
} | ||
options: Options | ||
} | ||
|
||
interface Props { | ||
|
@@ -33,32 +35,26 @@ interface Props { | |
interface State { | ||
testEnabled: boolean | ||
enabled: boolean | ||
workspace: string | ||
} | ||
|
||
@ErrorHandling | ||
class SlackConfig extends PureComponent<Props, State> { | ||
private url: HTMLInputElement | ||
private channel: HTMLInputElement | ||
private workspace: HTMLInputElement | ||
|
||
constructor(props) { | ||
super(props) | ||
this.state = { | ||
testEnabled: this.props.enabled, | ||
enabled: _.get(this.props, 'config.options.enabled', false), | ||
workspace: _.get(this.props, 'config.options.workspace') || '', | ||
} | ||
} | ||
|
||
public render() { | ||
const { | ||
config: { | ||
options: {url, channel, workspace}, | ||
}, | ||
isNewConfig, | ||
} = this.props | ||
const {testEnabled, enabled} = this.state | ||
|
||
const isNickNameEnabled = isNewConfig && !testEnabled | ||
const {url, channel} = this.options | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice/interesting -- i kind of like this pattern of refactoring this into a getter, though it does introduce some boilerplate |
||
const {testEnabled, enabled, workspace} = this.state | ||
|
||
return ( | ||
<form onSubmit={this.handleSubmit}> | ||
|
@@ -71,10 +67,9 @@ class SlackConfig extends PureComponent<Props, State> { | |
id={`${this.workspaceID}-nickname`} | ||
type="text" | ||
placeholder={this.nicknamePlaceholder} | ||
ref={r => (this.workspace = r)} | ||
defaultValue={workspace || ''} | ||
onChange={this.disableTest} | ||
disabled={!isNickNameEnabled} | ||
value={workspace} | ||
onChange={this.handleWorkspaceChange} | ||
disabled={!this.isNewConfig && !testEnabled} | ||
/> | ||
</div> | ||
<div className="form-group col-xs-12"> | ||
|
@@ -127,31 +122,57 @@ class SlackConfig extends PureComponent<Props, State> { | |
<button | ||
className="btn btn-primary" | ||
type="submit" | ||
disabled={testEnabled} | ||
disabled={testEnabled || this.isWorkspaceEmpty} | ||
> | ||
<span className="icon checkmark" /> | ||
Save Changes | ||
</button> | ||
<button | ||
className="btn btn-primary" | ||
disabled={!testEnabled || !enabled} | ||
disabled={this.isTestDisabled} | ||
onClick={this.handleTest} | ||
> | ||
<span className="icon pulse-c" /> | ||
Send Test Alert | ||
</button> | ||
{!this.isDefaultConfig && ( | ||
<button className="btn btn-danger" onClick={this.handleDelete}> | ||
<span className="icon trash" /> | ||
Delete | ||
</button> | ||
)} | ||
{this.deleteButton} | ||
<hr /> | ||
</div> | ||
</form> | ||
) | ||
} | ||
|
||
private handleWorkspaceChange = (e: ChangeEvent<HTMLInputElement>) => { | ||
this.setState({workspace: e.target.value}) | ||
} | ||
|
||
private get isNewConfig(): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting to see all of these as getters. i'm conflicted about it, as mentioned above, since it's more boilerplate but also more modular. no action requested, just digesting a new pattern. |
||
const {isNewConfig} = this.props | ||
|
||
return isNewConfig | ||
} | ||
|
||
private get options(): Options { | ||
const { | ||
config: {options}, | ||
} = this.props | ||
|
||
return options | ||
} | ||
|
||
private get deleteButton(): JSX.Element { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice! i like this patter of jsx elements as getters |
||
if (this.isDefaultConfig) { | ||
return null | ||
} | ||
|
||
return ( | ||
<button className="btn btn-danger" onClick={this.handleDelete}> | ||
<span className="icon trash" /> | ||
Delete | ||
</button> | ||
) | ||
} | ||
|
||
private get nicknamePlaceholder(): string { | ||
if (this.isDefaultConfig) { | ||
return 'Only for additional Configurations' | ||
|
@@ -167,6 +188,16 @@ class SlackConfig extends PureComponent<Props, State> { | |
return this.props.workspaceID | ||
} | ||
|
||
private get isWorkspaceEmpty(): boolean { | ||
const {workspace} = this.state | ||
return workspace === '' && !this.isDefaultConfig | ||
} | ||
|
||
private get isTestDisabled(): boolean { | ||
const {testEnabled, enabled} = this.state | ||
return !testEnabled || !enabled || this.isWorkspaceEmpty | ||
} | ||
|
||
private handleTest = (e: MouseEvent<HTMLButtonElement>) => { | ||
const { | ||
onTest, | ||
|
@@ -183,29 +214,31 @@ class SlackConfig extends PureComponent<Props, State> { | |
} | ||
|
||
private handleSubmit = async e => { | ||
const {isNewConfig} = this.props | ||
e.preventDefault() | ||
|
||
const {workspace} = this.state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you share your thoughts on why this would be from state as opposed to other state destructuring that has been modularized into getters? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. State is a little different to me than props, since there is no computed value needed I felt fine about destructuring from state. |
||
const {isNewConfig} = this.props | ||
|
||
const properties: SlackProperties = { | ||
url: this.url.value, | ||
channel: this.channel.value, | ||
enabled: this.state.enabled, | ||
} | ||
|
||
if (isNewConfig) { | ||
properties.workspace = this.workspace.value | ||
properties.workspace = workspace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only want to send the workspace on create, for updates we want to omit the key altogether. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
const success = await this.props.onSave( | ||
properties, | ||
isNewConfig, | ||
this.workspace.value | ||
) | ||
|
||
const success = await this.props.onSave(properties, isNewConfig, workspace) | ||
if (success) { | ||
this.setState({testEnabled: true}) | ||
} | ||
} | ||
|
||
private handleDelete = async e => { | ||
e.preventDefault() | ||
await this.props.onDelete(this.workspace.value, this.workspaceID) | ||
const {workspace} = this.state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see question above about a possible getter |
||
await this.props.onDelete(workspace, this.workspaceID) | ||
} | ||
|
||
private disableTest = () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import React, {PureComponent, MouseEvent} from 'react' | ||
import _ from 'lodash' | ||
import {get} from 'src/utils/wrappers' | ||
|
||
import {ErrorHandling} from 'src/shared/decorators/errors' | ||
|
@@ -48,7 +49,7 @@ class SlackConfigs extends PureComponent<Props, State> { | |
|
||
public render() { | ||
const {configs} = this.state | ||
const {onSave, onTest, onEnabled, isMultipleConfigsSupported} = this.props | ||
const {onSave, onTest, onEnabled} = this.props | ||
|
||
return ( | ||
<div> | ||
|
@@ -73,7 +74,7 @@ class SlackConfigs extends PureComponent<Props, State> { | |
/> | ||
) | ||
})} | ||
{isMultipleConfigsSupported && ( | ||
{this.isAddingConfigsAllowed && ( | ||
<div className="form-group col-xs-12 text-center"> | ||
<button className="btn btn-md btn-default" onClick={this.addConfig}> | ||
<span className="icon plus" /> Add Another Config | ||
|
@@ -88,6 +89,14 @@ class SlackConfigs extends PureComponent<Props, State> { | |
return this.state.configs | ||
} | ||
|
||
private get isAddingConfigsAllowed(): boolean { | ||
const {isMultipleConfigsSupported} = this.props | ||
const {configs} = this.state | ||
const isAllConfigsPersisted = _.every(configs, c => !this.isNewConfig(c)) | ||
|
||
return isMultipleConfigsSupported && isAllConfigsPersisted | ||
} | ||
|
||
private isNewConfig = (config: Config): boolean => { | ||
return get(config, 'isNewConfig', false) | ||
} | ||
|
@@ -99,7 +108,13 @@ class SlackConfigs extends PureComponent<Props, State> { | |
private getWorkspace = (config: Config): string => { | ||
const {isMultipleConfigsSupported} = this.props | ||
if (isMultipleConfigsSupported) { | ||
return get(config, 'options.workspace', 'new') | ||
const workspace = _.get(config, 'options', {workspace: null}).workspace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting |
||
|
||
if (workspace !== null) { | ||
return workspace | ||
} | ||
|
||
return 'new' | ||
} | ||
return '' | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason why it can't save? this is more of a ux thing, but i could see a user not understanding why it couldn't save, so if there's any further specificity here possible, what do you think about adding it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we just get a 502 back from Kapa with no additional information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
word